summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/mapdef.cc
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-11-22 08:41:20 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-11-22 08:41:20 +0000
commit1d0f57cbceb778139ca215cc4fcfd1584951f6dd (patch)
treecafd60c944c51fcce778aa5d6912bc548c518339 /crawl-ref/source/mapdef.cc
parent6f5e187a9e5cd348296dba2fd89d2e206e775a01 (diff)
downloadcrawl-ref-1d0f57cbceb778139ca215cc4fcfd1584951f6dd.tar.gz
crawl-ref-1d0f57cbceb778139ca215cc4fcfd1584951f6dd.zip
Merged stone_soup r15:451 into trunk.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@452 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/mapdef.cc')
-rw-r--r--crawl-ref/source/mapdef.cc412
1 files changed, 412 insertions, 0 deletions
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
new file mode 100644
index 0000000000..84e48329d6
--- /dev/null
+++ b/crawl-ref/source/mapdef.cc
@@ -0,0 +1,412 @@
+#include <cstdarg>
+#include <cstdio>
+#include <cctype>
+
+#include "AppHdr.h"
+#include "libutil.h"
+#include "mapdef.h"
+#include "mon-util.h"
+#include "stuff.h"
+
+///////////////////////////////////////////////
+// level_range
+//
+
+level_range::level_range(int s, int d)
+ : shallowest(), deepest()
+{
+ set(s, d);
+}
+
+void level_range::set(int s, int d)
+{
+ shallowest = s;
+ deepest = d;
+ if (deepest == -1)
+ deepest = shallowest;
+}
+
+void level_range::reset()
+{
+ deepest = shallowest = -1;
+}
+
+bool level_range::contains(int x) const
+{
+ // [ds] The level ranges used by the game are zero-based, adjust for that.
+ ++x;
+ return (x >= shallowest && x <= deepest);
+}
+
+bool level_range::valid() const
+{
+ return (shallowest > 0 && deepest >= shallowest);
+}
+
+int level_range::span() const
+{
+ return (deepest - shallowest);
+}
+
+///////////////////////////////////////////////
+// map_lines
+//
+
+map_lines::map_lines() : lines(), map_width(0)
+{
+}
+
+map_lines::map_lines(int nlines, ...) : lines(), map_width(0)
+{
+ va_list args;
+ va_start(args, nlines);
+
+ for (int i = 0; i < nlines; ++i)
+ add_line( va_arg(args, const char *) );
+
+ va_end(args);
+}
+
+const std::vector<std::string> &map_lines::get_lines() const
+{
+ return (lines);
+}
+
+void map_lines::add_line(const std::string &s)
+{
+ lines.push_back(s);
+ if ((int) s.length() > map_width)
+ map_width = s.length();
+}
+
+int map_lines::width() const
+{
+ return map_width;
+}
+
+int map_lines::height() const
+{
+ return lines.size();
+}
+
+void map_lines::clear()
+{
+ lines.clear();
+ map_width = 0;
+}
+
+void map_lines::resolve(std::string &s, const std::string &fill)
+{
+ std::string::size_type pos;
+ while ((pos = s.find('?')) != std::string::npos)
+ s[pos] = fill[ random2(fill.length()) ];
+}
+
+void map_lines::resolve(const std::string &fillins)
+{
+ if (fillins.empty() || fillins.find('?') != std::string::npos)
+ return;
+
+ for (int i = 0, size = lines.size(); i < size; ++i)
+ resolve(lines[i], fillins);
+}
+
+void map_lines::normalise(char fillch)
+{
+ for (int i = 0, size = lines.size(); i < size; ++i)
+ {
+ std::string &s = lines[i];
+ if ((int) s.length() < map_width)
+ s += std::string( map_width - s.length(), fillch );
+ }
+}
+
+// Should never be attempted if the map has a defined orientation, or if one
+// of the dimensions is greater than the lesser of GXM,GYM.
+void map_lines::rotate(bool clockwise)
+{
+ std::vector<std::string> newlines;
+
+ // normalise() first for convenience.
+ normalise();
+
+ const int xs = clockwise? 0 : map_width - 1,
+ xe = clockwise? map_width : -1,
+ xi = clockwise? 1 : -1;
+
+ const int ys = clockwise? (int) lines.size() - 1 : 0,
+ ye = clockwise? -1 : (int) lines.size(),
+ yi = clockwise? -1 : 1;
+
+ for (int i = xs; i != xe; i += xi)
+ {
+ std::string line;
+
+ for (int j = ys; j != ye; j += yi)
+ line += lines[j][i];
+
+ newlines.push_back(line);
+ }
+
+ map_width = lines.size();
+ lines = newlines;
+}
+
+void map_lines::vmirror()
+{
+ const int size = lines.size();
+ const int midpoint = size / 2;
+
+ for (int i = 0; i < midpoint; ++i)
+ {
+ std::string temp = lines[i];
+ lines[i] = lines[size - 1 - i];
+ lines[size - 1 - i] = temp;
+ }
+}
+
+void map_lines::hmirror()
+{
+ const int midpoint = map_width / 2;
+ for (int i = 0, size = lines.size(); i < size; ++i)
+ {
+ std::string &s = lines[i];
+ for (int j = 0; j < midpoint; ++j)
+ {
+ int c = s[j];
+ s[j] = s[map_width - 1 - j];
+ s[map_width - 1 - j] = c;
+ }
+ }
+}
+
+///////////////////////////////////////////////
+// map_def
+//
+
+void map_def::init()
+{
+ name.clear();
+ tags.clear();
+ place.clear();
+ depth.reset();
+ orient = MAP_NONE;
+
+ // Base chance; this is not a percentage.
+ chance = 10;
+
+ // The map designer must explicitly disallow these if unwanted.
+ flags = MAPF_MIRROR_VERTICAL | MAPF_MIRROR_HORIZONTAL
+ | MAPF_ROTATE;
+
+ random_symbols.clear();
+
+ map.clear();
+ mons.clear();
+}
+
+bool map_def::is_minivault() const
+{
+ return (orient == MAP_NONE);
+}
+
+void map_def::hmirror()
+{
+ if (!(flags & MAPF_MIRROR_HORIZONTAL))
+ return;
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Mirroring %s horizontally.", name.c_str());
+#endif
+ map.hmirror();
+
+ switch (orient)
+ {
+ case MAP_EAST: orient = MAP_WEST; break;
+ case MAP_NORTHEAST: orient = MAP_NORTHWEST; break;
+ case MAP_SOUTHEAST: orient = MAP_SOUTHWEST; break;
+ case MAP_WEST: orient = MAP_EAST; break;
+ case MAP_NORTHWEST: orient = MAP_NORTHEAST; break;
+ case MAP_SOUTHWEST: orient = MAP_SOUTHEAST; break;
+ default: break;
+ }
+}
+
+void map_def::vmirror()
+{
+ if (!(flags & MAPF_MIRROR_VERTICAL))
+ return;
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Mirroring %s vertically.", name.c_str());
+#endif
+ map.vmirror();
+
+ switch (orient)
+ {
+ case MAP_NORTH: orient = MAP_SOUTH; break;
+ case MAP_NORTHEAST: orient = MAP_SOUTHEAST; break;
+ case MAP_NORTHWEST: orient = MAP_SOUTHWEST; break;
+
+ case MAP_SOUTH: orient = MAP_NORTH; break;
+ case MAP_SOUTHEAST: orient = MAP_NORTHEAST; break;
+ case MAP_SOUTHWEST: orient = MAP_NORTHWEST; break;
+ default: break;
+ }
+}
+
+void map_def::rotate(bool clock)
+{
+ if (!(flags & MAPF_ROTATE))
+ return;
+
+#define GMINM ((GXM) < (GYM)? (GXM) : (GYM))
+ // Make sure the largest dimension fits in the smaller map bound.
+ if (map.width() <= GMINM && map.height() <= GMINM)
+ {
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Rotating %s %sclockwise.",
+ name.c_str(),
+ !clock? "anti-" : "");
+#endif
+ map.rotate(clock);
+
+ // Orientation shifts for clockwise rotation:
+ const map_section_type clockrotate_orients[][2] = {
+ { MAP_NORTH, MAP_EAST },
+ { MAP_NORTHEAST, MAP_SOUTHEAST },
+ { MAP_EAST, MAP_SOUTH },
+ { MAP_SOUTHEAST, MAP_SOUTHWEST },
+ { MAP_SOUTH, MAP_WEST },
+ { MAP_SOUTHWEST, MAP_NORTHWEST },
+ { MAP_WEST, MAP_NORTH },
+ { MAP_NORTHWEST, MAP_NORTHEAST },
+ };
+ const int nrots = sizeof(clockrotate_orients)
+ / sizeof(*clockrotate_orients);
+
+ const int refindex = !clock;
+ for (int i = 0; i < nrots; ++i)
+ if (orient == clockrotate_orients[i][refindex])
+ {
+ orient = clockrotate_orients[i][!refindex];
+ break;
+ }
+ }
+}
+
+void map_def::normalise()
+{
+ // Minivaults are padded out with floor tiles, normal maps are
+ // padded out with rock walls.
+ map.normalise(is_minivault()? '.' : 'x');
+}
+
+void map_def::resolve()
+{
+ map.resolve( random_symbols );
+}
+
+void map_def::fixup()
+{
+ normalise();
+ resolve();
+}
+
+bool map_def::has_tag(const std::string &tagwanted) const
+{
+ return !tags.empty() && !tagwanted.empty()
+ && tags.find(" " + tagwanted + " ") != std::string::npos;
+}
+
+///////////////////////////////////////////////////////////////////
+// mons_list
+//
+
+mons_list::mons_list(int nids, ...) : mons_ids()
+{
+ va_list args;
+ va_start(args, nids);
+
+ for (int i = 0; i < nids; ++i)
+ mons_ids.push_back( va_arg(args, int) );
+
+ va_end(args);
+}
+
+mons_list::mons_list() : mons_ids()
+{
+}
+
+const std::vector<int> &mons_list::get_ids() const
+{
+ return (mons_ids);
+}
+
+void mons_list::clear()
+{
+ mons_ids.clear();
+}
+
+bool mons_list::add_mons(const std::string &s)
+{
+ const int mid = mons_by_name(s);
+ if (mid != MONS_PROGRAM_BUG)
+ mons_ids.push_back(mid);
+ return (mid != MONS_PROGRAM_BUG);
+}
+
+int mons_list::mons_by_name(std::string name) const
+{
+ lowercase(name);
+
+ name = replace_all( name, "_", " " );
+
+ // Special casery:
+ if (name == "pandemonium demon")
+ return (MONS_PANDEMONIUM_DEMON);
+
+ if (name == "random" || name == "random monster")
+ return (RANDOM_MONSTER);
+
+ if (name == "any demon" || name == "demon" || name == "random demon")
+ return (-100 - DEMON_RANDOM);
+
+ if (name == "any lesser demon"
+ || name == "lesser demon" || name == "random lesser demon")
+ return (-100 - DEMON_LESSER);
+
+ if (name == "any common demon"
+ || name == "common demon" || name == "random common demon")
+ return (-100 - DEMON_COMMON);
+
+ if (name == "any greater demon"
+ || name == "greater demon" || name == "random greater demon")
+ return (-100 - DEMON_GREATER);
+
+ if (name == "small zombie")
+ return (MONS_ZOMBIE_SMALL);
+ if (name == "large zombie")
+ return (MONS_ZOMBIE_LARGE);
+
+ if (name == "small skeleton")
+ return (MONS_SKELETON_SMALL);
+ if (name == "large skeleton")
+ return (MONS_SKELETON_LARGE);
+
+ if (name == "spectral thing")
+ return (MONS_SPECTRAL_THING);
+
+ if (name == "small simulacrum")
+ return (MONS_SIMULACRUM_SMALL);
+ if (name == "large simulacrum")
+ return (MONS_SIMULACRUM_LARGE);
+
+ if (name == "small abomination")
+ return (MONS_ABOMINATION_SMALL);
+
+ if (name == "large abomination")
+ return (MONS_ABOMINATION_LARGE);
+
+ return (get_monster_by_name(name, true));
+}