summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/exclude.cc291
-rw-r--r--crawl-ref/source/exclude.h39
-rw-r--r--crawl-ref/source/travel.cc304
-rw-r--r--crawl-ref/source/travel.h33
4 files changed, 334 insertions, 333 deletions
diff --git a/crawl-ref/source/exclude.cc b/crawl-ref/source/exclude.cc
index d41bf3324f..077487b1b1 100644
--- a/crawl-ref/source/exclude.cc
+++ b/crawl-ref/source/exclude.cc
@@ -8,13 +8,13 @@
#include "exclude.h"
#include "mon-util.h"
+#include "overmap.h"
#include "stuff.h"
+#include "terrain.h"
#include "travel.h"
#include "tutorial.h"
#include "view.h"
-// TODO: move other exclusion code here.
-
static bool _mon_needs_auto_exclude(const monsters *mon, bool sleepy = false)
{
if (mons_is_stationary(mon))
@@ -75,4 +75,291 @@ void remove_auto_exclude(const monsters *mon, bool sleepy)
}
}
+opacity_type _feat_opacity(dungeon_feature_type feat)
+{
+ return (feat_is_opaque(feat) ? OPC_OPAQUE : OPC_CLEAR);
+}
+
+// A cell is considered clear unless the player knows it's
+// opaque.
+struct opacity_excl : opacity_func
+{
+ CLONE(opacity_excl)
+
+ opacity_type operator()(const coord_def& p) const
+ {
+ if (!is_terrain_seen(p))
+ return OPC_CLEAR;
+ else if (!is_terrain_changed(p))
+ return _feat_opacity(env.grid(p));
+ else if (env.map(p).object < NUM_REAL_FEATURES)
+ return _feat_opacity((dungeon_feature_type) env.map(p).object);
+ else
+ {
+ // If you have seen monsters, items or clouds there,
+ // it must have been passable.
+ return OPC_CLEAR;
+ }
+ }
+};
+static opacity_excl opc_excl;
+
+// Note: bounds_radius gives a circle with square radius r*r+1;
+// this doesn't work well for radius 0, but then we want to
+// skip LOS calculation in that case anyway since it doesn't
+// currently short-cut for small bounds. So radius 0 is special-cased.
+
+travel_exclude::travel_exclude(const coord_def &p, int r,
+ bool autoexcl, monster_type mons, bool vaultexcl)
+: pos(p), radius(r),
+los(los_def(p, opc_excl, bounds_radius(r))),
+uptodate(false), autoex(autoex), mon(mons), vault(vaultexcl)
+{
+ set_los();
+}
+
+void travel_exclude::set_los()
+{
+ uptodate = true;
+ if (radius > 0)
+ {
+ // Radius might have been changed, and this is cheap.
+ los.set_bounds(bounds_radius(radius));
+ los.update();
+ }
+}
+
+bool travel_exclude::affects(const coord_def& p) const
+{
+ if (!uptodate)
+ mprf(MSGCH_ERROR, "exclusion not up-to-date: e (%d,%d) p (%d,%d)",
+ pos.x, pos.y, p.x, p.y);
+ if (radius == 0)
+ return (p == pos);
+ return (los.see_cell(p));
+}
+
+bool travel_exclude::in_bounds(const coord_def &p) const
+{
+ return (radius == 0 && p == pos
+ || los.in_bounds(p));
+}
+
+void _mark_excludes_non_updated(const coord_def &p)
+{
+ for (exclvec::iterator it = curr_excludes.begin();
+ it != curr_excludes.end(); ++it)
+ {
+ it->uptodate = it->uptodate && it->in_bounds(p);
+ }
+}
+
+void _update_exclusion_los(bool all=false)
+{
+ for (exclvec::iterator it = curr_excludes.begin();
+ it != curr_excludes.end(); ++it)
+ {
+ if (all || !it->uptodate)
+ it->set_los();
+ }
+}
+
+void init_exclusion_los()
+{
+ _update_exclusion_los(true);
+}
+
+/*
+ * Update exclusions' LOS to reflect changes within their range.
+ * "changed" is a list of coordinates that have been changed.
+ * Only exclusions that might have one of the changed points
+ * in view are updated.
+ */
+void update_exclusion_los(std::vector<coord_def> changed)
+{
+ if (changed.empty())
+ return;
+
+ for (unsigned int i = 0; i < changed.size(); ++i)
+ _mark_excludes_non_updated(changed[i]);
+ _update_exclusion_los();
+}
+
+bool is_excluded(const coord_def &p, const exclvec &exc)
+{
+ for (unsigned int i = 0; i < exc.size(); ++i)
+ if (exc[i].affects(p))
+ return (true);
+ return (false);
+}
+
+static travel_exclude *_find_exclude_root(const coord_def &p)
+{
+ for (unsigned int i = 0; i < curr_excludes.size(); ++i)
+ if (curr_excludes[i].pos == p)
+ return (&curr_excludes[i]);
+ return (NULL);
+}
+
+bool is_exclude_root(const coord_def &p)
+{
+ return (_find_exclude_root(p));
+}
+
+#ifdef USE_TILE
+// update Gmap for squares surrounding exclude centre
+static void _tile_exclude_gmap_update(const coord_def &p)
+{
+ for (int x = -8; x <= 8; x++)
+ for (int y = -8; y <= 8; y++)
+ {
+ int px = p.x+x, py = p.y+y;
+ if (in_bounds(coord_def(px,py)))
+ {
+ tiles.update_minimap(px, py);
+ }
+ }
+}
+#endif
+
+static void _exclude_update()
+{
+ if (can_travel_interlevel())
+ {
+ LevelInfo &li = travel_cache.get_level_info(level_id::current());
+ li.update();
+ }
+ set_level_exclusion_annotation(get_exclusion_desc());
+}
+
+static void _exclude_update(const coord_def &p)
+{
+#ifdef USE_TILE
+ _tile_exclude_gmap_update(p);
+#endif
+ _exclude_update();
+}
+
+void clear_excludes()
+{
+ // Sanity checks
+ if (!player_in_mappable_area())
+ return;
+
+#ifdef USE_TILE
+ for (int i = curr_excludes.size()-1; i >= 0; i--)
+ _tile_exclude_gmap_update(curr_excludes[i].pos);
+#endif
+
+ curr_excludes.clear();
+ clear_level_exclusion_annotation();
+
+ _exclude_update();
+}
+
+// Cycles the radius of an exclusion, including "off" state.
+void cycle_exclude_radius(const coord_def &p)
+{
+ // XXX: scanning through curr_excludes twice
+ if (travel_exclude *exc = _find_exclude_root(p))
+ {
+ if (exc->radius == LOS_RADIUS)
+ set_exclude(p, 0);
+ else
+ {
+ ASSERT(exc->radius == 0);
+ del_exclude(p);
+ }
+ }
+ else
+ set_exclude(p, LOS_RADIUS);
+}
+
+// Remove a possible exclude.
+void del_exclude(const coord_def &p)
+{
+ for (unsigned int i = 0; i < curr_excludes.size(); ++i)
+ if (curr_excludes[i].pos == p)
+ {
+ curr_excludes.erase(curr_excludes.begin() + i);
+ break;
+ }
+ _exclude_update(p);
+}
+
+// Set or update an exclude.
+void set_exclude(const coord_def &p, int radius, bool autoexcl, bool vaultexcl)
+{
+ // Sanity checks; excludes can be set in Pan and regular dungeon
+ // levels only.
+ if (!player_in_mappable_area())
+ return;
+
+ if (!in_bounds(p))
+ return;
+
+ if (travel_exclude *exc = _find_exclude_root(p))
+ {
+ exc->radius = radius;
+ exc->set_los();
+ }
+ else
+ {
+ monster_type montype = MONS_NO_MONSTER;
+ const monsters *m = monster_at(p);
+ if (m && you.can_see(m))
+ montype = m->type;
+
+ curr_excludes.push_back(travel_exclude(p, radius, autoexcl,
+ montype, vaultexcl));
+ }
+
+ _exclude_update(p);
+}
+
+// If a grid that was placed automatically no longer contains the original
+// monster (or it is invisible), remove the exclusion.
+void maybe_remove_autoexclusion(const coord_def &p)
+{
+ if (travel_exclude *exc = _find_exclude_root(p))
+ {
+ const monsters *m = monster_at(p);
+ if (exc->autoex && (!m || !you.can_see(m) || m->type != exc->mon))
+ del_exclude(p);
+ }
+}
+
+// Lists all exclusions on the current level.
+std::string get_exclusion_desc()
+{
+ std::vector<std::string> monsters;
+ int count_other = 0;
+ for (unsigned int i = 0; i < curr_excludes.size(); ++i)
+ {
+ if (!invalid_monster_type(curr_excludes[i].mon))
+ monsters.push_back(mons_type_name(curr_excludes[i].mon, DESC_PLAIN));
+ else
+ count_other++;
+ }
+
+ if (count_other > 0)
+ {
+ snprintf(info, INFO_SIZE, "%d %sexclusion%s",
+ count_other, monsters.empty() ? "" : "more ",
+ count_other > 1 ? "s" : "");
+ monsters.push_back(info);
+ }
+ else if (monsters.empty())
+ return "";
+
+ std::string desc = "";
+ if (monsters.size() > 1 || count_other == 0)
+ {
+ snprintf(info, INFO_SIZE, "exclusion%s: ",
+ monsters.size() > 1 ? "s" : "");
+ desc += info;
+ }
+ return (desc + comma_separated_line(monsters.begin(), monsters.end(),
+ ", and ", ", "));
+}
diff --git a/crawl-ref/source/exclude.h b/crawl-ref/source/exclude.h
index 77b1244a9e..1a39d82f53 100644
--- a/crawl-ref/source/exclude.h
+++ b/crawl-ref/source/exclude.h
@@ -1,9 +1,48 @@
#ifndef EXCLUDE_H
#define EXCLUDE_H
+#include "los.h"
+
bool need_auto_exclude(const monsters *mon, bool sleepy = false);
void set_auto_exclude(const monsters *mon);
void remove_auto_exclude(const monsters *mon, bool sleepy = false);
+void init_exclusion_los();
+void update_exclusion_los(std::vector<coord_def> changed);
+
+bool is_exclude_root(const coord_def &p);
+void cycle_exclude_radius(const coord_def &p);
+void del_exclude(const coord_def &p);
+void set_exclude(const coord_def &p, int radius = LOS_RADIUS,
+ bool autoexcl = false, bool vaultexcl = false);
+void maybe_remove_autoexclusion(const coord_def &p);
+std::string get_exclusion_desc();
+void clear_excludes();
+
+struct travel_exclude
+{
+ coord_def pos; // exclusion centre
+ int radius; // exclusion radius
+ los_def los; // los from exclusion centre
+ bool uptodate; // Is los up to date?
+ bool autoex; // Was set automatically.
+ monster_type mon; // Monster around which exclusion is centered.
+ bool vault; // Is this exclusion set by a vault?
+
+ travel_exclude(const coord_def &p, int r = LOS_RADIUS,
+ bool autoex = false, monster_type mons = MONS_NO_MONSTER,
+ bool vault = false);
+
+ int radius_sq() const;
+ void set_los();
+ bool in_bounds(const coord_def& p) const;
+ bool affects(const coord_def& p) const;
+};
+
+typedef std::vector<travel_exclude> exclvec;
+extern exclvec curr_excludes; // in travel.cc
+
+bool is_excluded(const coord_def &p, const exclvec &exc = curr_excludes);
+
#endif
diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc
index 57ecbfb305..14eb85f72d 100644
--- a/crawl-ref/source/travel.cc
+++ b/crawl-ref/source/travel.cc
@@ -20,6 +20,7 @@
#include "describe.h"
#include "dgnevent.h"
#include "directn.h"
+#include "exclude.h"
#include "itemname.h"
#include "itemprop.h"
#include "items.h"
@@ -85,7 +86,7 @@ static std::vector<stair_info> curr_stairs;
// Squares that are not safe to travel to on the current level.
typedef std::vector<travel_exclude> exclvec;
-static exclvec curr_excludes;
+exclvec curr_excludes;
// This is where we last tried to take a stair during interlevel travel.
// Note that last_stair.depth should be set to -1 before initiating interlevel
@@ -270,178 +271,6 @@ bool feat_is_traversable(dungeon_feature_type grid)
return (traversable_terrain[grid] == TRAVERSABLE);
}
-opacity_type _feat_opacity(dungeon_feature_type feat)
-{
- return (feat_is_opaque(feat) ? OPC_OPAQUE : OPC_CLEAR);
-}
-
-// A cell is considered clear unless the player knows it's
-// opaque.
-struct opacity_excl : opacity_func
-{
- CLONE(opacity_excl)
-
- opacity_type operator()(const coord_def& p) const
- {
- if (!is_terrain_seen(p))
- return OPC_CLEAR;
- else if (!is_terrain_changed(p))
- return _feat_opacity(env.grid(p));
- else if (env.map(p).object < NUM_REAL_FEATURES)
- return _feat_opacity((dungeon_feature_type) env.map(p).object);
- else
- {
- // If you have seen monsters, items or clouds there,
- // it must have been passable.
- return OPC_CLEAR;
- }
- }
-};
-static opacity_excl opc_excl;
-
-// Note: bounds_radius gives a circle with square radius r*r+1;
-// this doesn't work well for radius 0, but then we want to
-// skip LOS calculation in that case anyway since it doesn't
-// currently short-cut for small bounds. So radius 0 is special-cased.
-
-travel_exclude::travel_exclude(const coord_def &p, int r,
- bool autoexcl, monster_type mons, bool vaultexcl)
- : pos(p), radius(r),
- los(los_def(p, opc_excl, bounds_radius(r))),
- uptodate(false), autoex(autoex), mon(mons), vault(vaultexcl)
-{
- set_los();
-}
-
-void travel_exclude::set_los()
-{
- uptodate = true;
- if (radius > 0)
- {
- // Radius might have been changed, and this is cheap.
- los.set_bounds(bounds_radius(radius));
- los.update();
- }
-}
-
-bool travel_exclude::affects(const coord_def& p) const
-{
- if (!uptodate)
- mprf(MSGCH_ERROR, "exclusion not up-to-date: e (%d,%d) p (%d,%d)",
- pos.x, pos.y, p.x, p.y);
- if (radius == 0)
- return (p == pos);
- return (los.see_cell(p));
-}
-
-bool travel_exclude::in_bounds(const coord_def &p) const
-{
- return (radius == 0 && p == pos
- || los.in_bounds(p));
-}
-
-void init_exclusion_los()
-{
- for (unsigned int i = 0; i < curr_excludes.size(); i++)
- curr_excludes[i].set_los();
-}
-
-void _mark_excludes_non_updated(const coord_def &p)
-{
- for (exclvec::iterator it = curr_excludes.begin();
- it != curr_excludes.end(); ++it)
- {
- it->uptodate = it->uptodate && it->in_bounds(p);
- }
-}
-
-void _update_exclusion_los(bool all=false)
-{
- for (exclvec::iterator it = curr_excludes.begin();
- it != curr_excludes.end(); ++it)
- {
- if (all || !it->uptodate)
- it->set_los();
- }
-}
-
-/*
- * Update exclusions' LOS to reflect changes within their range.
- * "changed" is a list of coordinates that have been changed.
- * Only exclusions that might have one of the changed points
- * in view are updated.
- */
-void update_exclusion_los(std::vector<coord_def> changed)
-{
- if (changed.empty())
- return;
-
- for (unsigned int i = 0; i < changed.size(); ++i)
- _mark_excludes_non_updated(changed[i]);
- _update_exclusion_los();
-}
-
-static bool _is_excluded(const coord_def &p,
- const exclvec &exc)
-{
- for (unsigned int i = 0; i < exc.size(); ++i)
- if (exc[i].affects(p))
- return (true);
- return (false);
-}
-
-bool is_excluded(const coord_def &p)
-{
- return _is_excluded(p, curr_excludes);
-}
-
-static travel_exclude *_find_exclude_root(const coord_def &p)
-{
- for (unsigned int i = 0; i < curr_excludes.size(); ++i)
- if (curr_excludes[i].pos == p)
- return (&curr_excludes[i]);
- return (NULL);
-}
-
-bool is_exclude_root(const coord_def &p)
-{
- return (_find_exclude_root(p));
-}
-
-#ifdef USE_TILE
-// update Gmap for squares surrounding exclude centre
-static void _tile_exclude_gmap_update(const coord_def &p)
-{
- for (int x = -8; x <= 8; x++)
- for (int y = -8; y <= 8; y++)
- {
- int px = p.x+x, py = p.y+y;
- if (in_bounds(coord_def(px,py)))
- {
- tiles.update_minimap(px, py);
- }
- }
-}
-#endif
-
-static void _exclude_update()
-{
- if (can_travel_interlevel())
- {
- LevelInfo &li = travel_cache.get_level_info(level_id::current());
- li.update();
- }
- set_level_exclusion_annotation(get_exclusion_desc());
-}
-
-static void _exclude_update(const coord_def &p)
-{
-#ifdef USE_TILE
- _tile_exclude_gmap_update(p);
-#endif
- _exclude_update();
-}
-
const char *run_mode_name(int runmode)
{
return (runmode == RMODE_TRAVEL ? "travel" :
@@ -468,129 +297,6 @@ inline bool is_stash(const LevelStashes *ls, int x, int y)
return s && s->enabled;
}
-void clear_excludes()
-{
- // Sanity checks
- if (!player_in_mappable_area())
- return;
-
-#ifdef USE_TILE
- for (int i = curr_excludes.size()-1; i >= 0; i--)
- _tile_exclude_gmap_update(curr_excludes[i].pos);
-#endif
-
- curr_excludes.clear();
- clear_level_exclusion_annotation();
-
- _exclude_update();
-}
-
-// Cycles the radius of an exclusion, including "off" state.
-void cycle_exclude_radius(const coord_def &p)
-{
- // XXX: scanning through curr_excludes twice
- if (travel_exclude *exc = _find_exclude_root(p))
- {
- if (exc->radius == LOS_RADIUS)
- set_exclude(p, 0);
- else
- {
- ASSERT(exc->radius == 0);
- del_exclude(p);
- }
- }
- else
- set_exclude(p, LOS_RADIUS);
-}
-
-// Remove a possible exclude.
-void del_exclude(const coord_def &p)
-{
- for (unsigned int i = 0; i < curr_excludes.size(); ++i)
- if (curr_excludes[i].pos == p)
- {
- curr_excludes.erase(curr_excludes.begin() + i);
- break;
- }
- _exclude_update(p);
-}
-
-// Set or update an exclude.
-void set_exclude(const coord_def &p, int radius, bool autoexcl, bool vaultexcl)
-{
- // Sanity checks; excludes can be set in Pan and regular dungeon
- // levels only.
- if (!player_in_mappable_area())
- return;
-
- if (!in_bounds(p))
- return;
-
- if (travel_exclude *exc = _find_exclude_root(p))
- {
- exc->radius = radius;
- exc->set_los();
- }
- else
- {
- monster_type montype = MONS_NO_MONSTER;
- const monsters *m = monster_at(p);
- if (m && you.can_see(m))
- montype = m->type;
-
- curr_excludes.push_back(travel_exclude(p, radius, autoexcl,
- montype, vaultexcl));
- }
-
- _exclude_update(p);
-}
-
-// If a grid that was placed automatically no longer contains the original
-// monster (or it is invisible), remove the exclusion.
-void maybe_remove_autoexclusion(const coord_def &p)
-{
- if (travel_exclude *exc = _find_exclude_root(p))
- {
- const monsters *m = monster_at(p);
- if (exc->autoex && (!m || !you.can_see(m) || m->type != exc->mon))
- del_exclude(p);
- }
-}
-
-// Lists all exclusions on the current level.
-std::string get_exclusion_desc()
-{
- std::vector<std::string> monsters;
- int count_other = 0;
- for (unsigned int i = 0; i < curr_excludes.size(); ++i)
- {
- if (!invalid_monster_type(curr_excludes[i].mon))
- monsters.push_back(mons_type_name(curr_excludes[i].mon, DESC_PLAIN));
- else
- count_other++;
- }
-
- if (count_other > 0)
- {
- snprintf(info, INFO_SIZE, "%d %sexclusion%s",
- count_other, monsters.empty() ? "" : "more ",
- count_other > 1 ? "s" : "");
- monsters.push_back(info);
- }
- else if (monsters.empty())
- return "";
-
- std::string desc = "";
- if (monsters.size() > 1 || count_other == 0)
- {
- snprintf(info, INFO_SIZE, "exclusion%s: ",
- monsters.size() > 1 ? "s" : "");
- desc += info;
- }
- return (desc + comma_separated_line(monsters.begin(), monsters.end(),
- ", and ", ", "));
-}
-
static bool _is_monster_blocked(const coord_def& c)
{
const monsters *mons = monster_at(c);
@@ -2688,7 +2394,7 @@ static int _find_transtravel_stair( const level_id &cur,
if (cur == target.id)
{
// Are we in an exclude? If so, bail out.
- if (_is_excluded( stair, li.get_excludes() ))
+ if (is_excluded( stair, li.get_excludes() ))
return (-1);
// If there's no target position on the target level, or we're on the
@@ -2872,7 +2578,7 @@ static bool _loadlev_populate_stair_distances(const level_pos &target)
if (travel_load_map(target.id.branch,
absdungeon_depth(target.id.branch, target.id.depth)))
{
- std::vector<travel_exclude> old_excludes = curr_excludes;
+ exclvec old_excludes = curr_excludes;
curr_excludes.clear();
LevelInfo &li = travel_cache.get_level_info(target.id);
@@ -3278,7 +2984,7 @@ std::string stair_info::describe() const
void LevelInfo::set_level_excludes()
{
curr_excludes = excludes;
- _update_exclusion_los(true);
+ init_exclusion_los();
}
bool LevelInfo::empty() const
diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h
index cfc8f95c9a..3dcf059577 100644
--- a/crawl-ref/source/travel.h
+++ b/crawl-ref/source/travel.h
@@ -8,6 +8,7 @@
#include "externs.h"
+#include "exclude.h"
#include "los.h"
#include <stdio.h>
@@ -60,23 +61,14 @@ void initialise_travel();
void init_travel_terrain_check(bool check_race_equip = true);
void stop_running(void);
void travel_init_new_level();
-void cycle_exclude_radius(const coord_def &p);
-void del_exclude(const coord_def &p);
-void set_exclude(const coord_def &p, int radius = LOS_RADIUS,
- bool autoexcl = false, bool vaultexcl = false);
-void maybe_remove_autoexclusion(const coord_def &p);
-std::string get_exclusion_desc();
-void clear_excludes();
unsigned char is_waypoint(const coord_def &p);
-bool is_exclude_root(const coord_def &p);
command_type direction_to_command(char x, char y);
bool is_resting(void);
#ifdef CLUA_BINDINGS
const char *trap_name(const coord_def &p);
#endif
void explore_pickup_event(int did_pickup, int tried_pickup);
-bool is_excluded(const coord_def &p);
bool feat_is_traversable(dungeon_feature_type feat);
bool is_unknown_stair(const coord_def &p,
dungeon_feature_type remembered_feat = NUM_REAL_FEATURES);
@@ -350,29 +342,6 @@ public:
bool can_travel() const { return (type == PHYSICAL); }
};
-void init_exclusion_los();
-void update_exclusion_los(std::vector<coord_def> changed);
-
-struct travel_exclude
-{
- coord_def pos; // exclusion centre
- int radius; // exclusion radius
- los_def los; // los from exclusion centre
- bool uptodate; // Is los up to date?
- bool autoex; // Was set automatically.
- monster_type mon; // Monster around which exclusion is centered.
- bool vault; // Is this exclusion set by a vault?
-
- travel_exclude(const coord_def &p, int r = LOS_RADIUS,
- bool autoex = false, monster_type mons = MONS_NO_MONSTER,
- bool vault = false);
-
- int radius_sq() const;
- void set_los();
- bool in_bounds(const coord_def& p) const;
- bool affects(const coord_def& p) const;
-};
-
// Information on a level that interlevel travel needs.
struct LevelInfo
{