summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/command.cc100
-rw-r--r--crawl-ref/source/mon-util.cc14
-rw-r--r--crawl-ref/source/monplace.cc18
-rw-r--r--crawl-ref/source/monstuff.cc137
-rw-r--r--crawl-ref/source/view.cc23
-rw-r--r--crawl-ref/source/view.h2
6 files changed, 180 insertions, 114 deletions
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index 52f8ec9226..5959825431 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -1832,59 +1832,59 @@ static void _list_wizard_commands()
cols.set_pagesize(get_number_of_lines());
cols.add_formatted(0,
- "a : acquirement\n"
- "A : set all skills to level\n"
- "Ctrl-A : generate new Abyss area\n"
- "b : controlled blink\n"
- "B : banish yourself to the Abyss\n"
- "c : card effect\n"
- "C : (un)curse item\n"
- "g : add a skill\n"
- "G : banish all monsters\n"
- "Ctrl-G : save ghost (bones file)\n"
- "f : player combat damage stats\n"
- "F : combat stats with fsim_kit\n"
- "Ctrl-F : combat stats (monster vs PC)\n"
- "h/H : heal yourself (super-Heal)\n"
- "i/I : identify/unidentify inventory\n"
- "Ctrl-I : item generation stats\n"
- "l : make entrance to labyrinth\n"
- "L : place a vault by name\n"
- "m/M : create monster by number/name\n"
- "o/% : create an object\n"
- "p : make entrance to pandemonium\n"
- "P : make a portal (i.e., bazaars)\n"
- "r : change character's species\n"
- "s : gain 20000 skill points\n"
- "S : set skill to level\n",
+ "<w>a</w> : acquirement\n"
+ "<w>A</w> : set all skills to level\n"
+ "<w>Ctrl-A</w> : generate new Abyss area\n"
+ "<w>b</w> : controlled blink\n"
+ "<w>B</w> : banish yourself to the Abyss\n"
+ "<w>c</w> : card effect\n"
+ "<w>C</w> : (un)curse item\n"
+ "<w>g</w> : add a skill\n"
+ "<w>G</w> : banish all monsters\n"
+ "<w>Ctrl-G</w> : save ghost (bones file)\n"
+ "<w>f</w> : player combat damage stats\n"
+ "<w>F</w> : combat stats with fsim_kit\n"
+ "<w>Ctrl-F</w> : combat stats (monster vs PC)\n"
+ "<w>h</w>/<w>H</w> : heal yourself (super-Heal)\n"
+ "<w>i</w>/<w>I</w> : identify/unidentify inventory\n"
+ "<w>Ctrl-I</w> : item generation stats\n"
+ "<w>l</w> : make entrance to labyrinth\n"
+ "<w>L</w> : place a vault by name\n"
+ "<w>m</w>/<w>M</w> : create monster by number/name\n"
+ "<w>o</w>/<w>%</w> : create an object\n"
+ "<w>p</w> : make entrance to pandemonium\n"
+ "<w>P</w> : make a portal (i.e., bazaars)\n"
+ "<w>r</w> : change character's species\n"
+ "<w>s</w> : gain 20000 skill points\n"
+ "<w>S</w> : set skill to level\n",
true, true);
cols.add_formatted(1,
- "t : tweak object properties\n"
- "T : make a trap\n"
- "v : show gold value of an item\n"
- "x : gain an experience level\n"
- "Ctrl-X : change experience level\n"
- "X : make Xom do something now\n"
- "z/Z : cast spell by number/name\n"
- "$ : get 1000 gold\n"
- "</> : create up/down staircase\n"
- "u/d : shift up/down one level\n"
- "~ : go to a specific level\n"
- "(/) : make feature by number/name\n"
- "] : get a mutation\n"
- "[ : get a demonspawn mutation\n"
- ": : find branches in the dungeon\n"
- "{ : magic mapping\n"
- "^ : gain piety\n"
- "_ : gain religion\n"
- "' : list items\n"
- "\" : list monsters\n"
- "? : list wizard commands\n"
- "| : make unrand/fixed artefacts\n"
- "+ : make randart from item\n"
- "@ : set Str Int Dex\n"
- "\\ : make a shop\n",
+ "<w>t</w> : tweak object properties\n"
+ "<w>T</w> : make a trap\n"
+ "<w>v</w> : show gold value of an item\n"
+ "<w>x</w> : gain an experience level\n"
+ "<w>Ctrl-X</w> : change experience level\n"
+ "<w>X</w> : make Xom do something now\n"
+ "<w>z</w>/<w>Z</w> : cast spell by number/name\n"
+ "<w>$</w> : get 1000 gold\n"
+ "<w><<</w>/<w>></w> : create up/down staircase\n"
+ "<w>u</w>/<w>d</w> : shift up/down one level\n"
+ "<w>~</w> : go to a specific level\n"
+ "<w>(</w>/<w>)</w> : make feature by number/name\n"
+ "<w>]</w> : get a mutation\n"
+ "<w>[</w> : get a demonspawn mutation\n"
+ "<w>:</w> : find branches in the dungeon\n"
+ "<w>{</w> : magic mapping\n"
+ "<w>^</w> : gain piety\n"
+ "<w>_</w> : gain religion\n"
+ "<w>'</w> : list items\n"
+ "<w>\"</w> : list monsters\n"
+ "<w>?</w> : list wizard commands\n"
+ "<w>|</w> : create all unrand/fixed artefacts\n"
+ "<w>+</w> : make randart from item\n"
+ "<w>@</w> : set Str Int Dex\n"
+ "<w>\\</w> : make a shop\n",
true, true);
_show_keyhelp_menu(cols.formatted_lines(), false, true);
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 1c1d7fb53b..64ebfc3324 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -4739,6 +4739,13 @@ void monsters::add_enchantment_effect(const mon_enchant &ench, bool quiet)
target_x = you.x_pos;
target_y = you.y_pos;
foe = MHITYOU;
+
+ if (is_patrolling())
+ {
+ // Enslaved monsters stop patrolling and forget their patrol point,
+ // they're supposed to follow you now.
+ patrol_point = coord_def(0, 0);
+ }
break;
default:
@@ -4838,6 +4845,13 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
activity_interrupt_data(this, "uncharm"));
}
+ if (is_patrolling())
+ {
+ // Enslaved monsters stop patrolling and forget their patrol point,
+ // in case they were on order to wait.
+ patrol_point = coord_def(0, 0);
+ }
+
// reevaluate behaviour
behaviour_event(this, ME_EVAL);
break;
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 2eb7eb29ae..4c9af2a0ff 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -188,8 +188,8 @@ static void hell_spawn_random_monsters()
if (one_chance_in(genodds))
{
mgen_data mg(WANDERING_MONSTER);
- mg.proximity =
- (one_chance_in(10) ? PROX_NEAR_STAIRS : PROX_AWAY_FROM_PLAYER);
+ mg.proximity = (one_chance_in(10) ? PROX_NEAR_STAIRS
+ : PROX_AWAY_FROM_PLAYER);
mons_place(mg);
viewwindow(true, false);
}
@@ -1737,12 +1737,12 @@ int mons_place( mgen_data mg )
mg.cls = RANDOM_MONSTER;
}
- // all monsters have been assigned? {dlb}
+ // All monsters have been assigned? {dlb}
if (mon_count >= MAX_MONSTERS - 1)
return (-1);
- // this gives a slight challenge to the player as they ascend the
- // dungeon with the Orb
+ // This gives a slight challenge to the player as they ascend the
+ // dungeon with the Orb.
if (you.char_direction == GDT_ASCENDING && mg.cls == RANDOM_MONSTER
&& you.level_type == LEVEL_DUNGEON && !mg.summoned())
{
@@ -1776,8 +1776,8 @@ int mons_place( mgen_data mg )
monsters *creation = &menv[mid];
- // look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT
- // alert summoned being to player's presence
+ // Look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT.
+ // Alert summoned being to player's presence.
if (mg.behaviour > NUM_BEHAVIOURS)
{
if (mg.behaviour == BEH_FRIENDLY || mg.behaviour == BEH_GOD_GIFT)
@@ -1801,6 +1801,10 @@ int mons_place( mgen_data mg )
if (creation->type == MONS_RAKSHASA_FAKE && !one_chance_in(3))
creation->add_ench(ENCH_INVIS);
}
+
+ if (mg.needs_patrol_point())
+ creation->patrol_point = coord_def(creation->x, creation->y);
+
return (mid);
}
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index ab4a48d441..7f586238b1 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -2149,26 +2149,54 @@ void behaviour_event( monsters *mon, int event, int src,
_handle_behaviour( mon );
}
-static bool _choose_random_target_grid_in_los(monsters *mon)
+static bool _choose_random_patrol_target_grid(monsters *mon)
{
+ int patrol_x = mon->patrol_point.x;
+ int patrol_y = mon->patrol_point.y;
+ dungeon_feature_type habitat = habitat2grid(
+ mons_habitat_by_type(mon->type) );
int pos_x, pos_y;
int count_grids = 0;
for (int j = -LOS_RADIUS; j < LOS_RADIUS; j++)
for (int k = -LOS_RADIUS; k < LOS_RADIUS; k++)
{
- if (j == 0 && k == 0)
- continue;
-
- pos_x = mon->x + j;
- pos_y = mon->y + k;
+ pos_x = patrol_x + j;
+ pos_y = patrol_y + k;
if (!in_bounds(pos_x, pos_y))
continue;
- if (!mon->mon_see_grid(pos_x, pos_y))
+
+ if (pos_x == mon->x && pos_y == mon->y)
continue;
+
if (!mon->can_pass_through_feat(grd[pos_x][pos_y]))
continue;
+ if (grid_see_grid(mon->x, mon->y, patrol_x, patrol_y, habitat))
+ {
+ // If the patrol point can be easily (within LOS) reached
+ // from the current position, it suffices if the target is
+ // within reach of the patrol point OR the current position:
+ // we can easily get there.
+ if (!grid_see_grid(patrol_x, patrol_y, pos_x, pos_y, habitat)
+ && !grid_see_grid(mon->x, mon->y, pos_x, pos_y, habitat))
+ {
+ continue;
+ }
+ }
+ else
+ {
+ // If, however, the patrol point is out of reach, we have to
+ // make sure the new target brings us into reach of it.
+ // This means that the target must be reachable BOTH from
+ // the patrol point AND the current position.
+ if (!grid_see_grid(patrol_x, patrol_y, pos_x, pos_y, habitat)
+ || !grid_see_grid(mon->x, mon->y, pos_x, pos_y, habitat))
+ {
+ continue;
+ }
+ }
+
if (one_chance_in(++count_grids))
{
mon->target_x = pos_x;
@@ -2508,9 +2536,11 @@ static void _handle_behaviour(monsters *mon)
{
if (patrolling)
{
- if (mon->patrol_point != coord_def(mon->x, mon->y)
- || !_choose_random_target_grid_in_los(mon))
+ if (!_choose_random_patrol_target_grid(mon))
{
+ // If we couldn't find a target that is within easy
+ // reach of the monster and close to the patrol point,
+ // it's time to head back.
mon->target_x = mon->patrol_point.x;
mon->target_y = mon->patrol_point.y;
}
@@ -2727,7 +2757,7 @@ monsters *choose_random_monster_on_level(int weight,
return chosen;
}
-// note that this function *completely* blocks messaging for monsters
+// Note that this function *completely* blocks messaging for monsters
// distant or invisible to the player ... look elsewhere for a function
// permitting output of "It" messages for the invisible {dlb}
// Intentionally avoids info and str_pass now. -- bwr
@@ -3685,7 +3715,7 @@ static bool _handle_scroll(monsters *monster)
bool was_visible =
mons_near(monster) && player_monster_visible(monster);
- // notice how few cases are actually accounted for here {dlb}:
+ // Notice how few cases are actually accounted for here {dlb}:
const int scroll_type = mitm[monster->inv[MSLOT_SCROLL]].sub_type;
switch (scroll_type)
{
@@ -3880,13 +3910,13 @@ static bool _handle_wand(monsters *monster, bolt &beem)
niceWand = true;
break;
}
- // this break causes the wand to be tried on the player:
+ // This break causes the wand to be tried on the player.
break;
}
return (false);
}
- // fire tracer, if necessary
+ // Fire tracer, if necessary.
if (!niceWand)
{
fire_tracer( monster, beem );
@@ -4623,16 +4653,16 @@ static bool _handle_throw(monsters *monster, bolt & beem)
return (false);
}
- // ok, we'll try it.
+ // Ok, we'll try it.
setup_generic_throw( monster, beem );
- // set fake damage for the tracer.
+ // Set fake damage for the tracer.
beem.damage = dice_def(10, 10);
// fire tracer
fire_tracer( monster, beem );
- // clear fake damage (will be set correctly in mons_throw).
+ // Clear fake damage (will be set correctly in mons_throw).
beem.damage = 0;
// good idea?
@@ -4770,7 +4800,7 @@ static void _handle_monster_move(int i, monsters *monster)
if (monster->hit_points > monster->max_hit_points)
monster->hit_points = monster->max_hit_points;
- // monster just summoned (or just took stairs), skip this action
+ // Monster just summoned (or just took stairs), skip this action.
if (testbits( monster->flags, MF_JUST_SUMMONED ))
{
monster->flags &= ~MF_JUST_SUMMONED;
@@ -4779,7 +4809,7 @@ static void _handle_monster_move(int i, monsters *monster)
_monster_add_energy(monster);
- // Handle clouds on nonmoving monsters:
+ // Handle clouds on nonmoving monsters.
if (monster->speed == 0
&& env.cgrid[monster->x][monster->y] != EMPTY_CLOUD
&& !monster->has_ench(ENCH_SUBMERGED))
@@ -5238,7 +5268,7 @@ void handle_monsters(void)
// If the player got banished, discard pending monster actions.
if (you.banished)
{
- // clear list of beholding monsters
+ // Clear list of beholding monsters.
if (you.duration[DUR_BEHELD])
{
you.beheld_by.clear();
@@ -5284,7 +5314,7 @@ static bool _is_item_jelly_edible(const item_def &item)
//
// handle_pickup
//
-// Returns false if monster doesn't spend any time pickup up
+// Returns false if monster doesn't spend any time picking something up.
//
//---------------------------------------------------------------
static bool _handle_pickup(monsters *monster)
@@ -5455,7 +5485,7 @@ static bool _mons_can_displace(const monsters *mpusher, const monsters *mpushee)
return (false);
}
- // Batty monsters are unpushable
+ // Batty monsters are unpushable.
if (mons_is_batty(mpusher) || mons_is_batty(mpushee))
return (false);
@@ -5630,9 +5660,9 @@ void mons_check_pool(monsters *mons, killer_type killer, int killnum)
}
}
-// returns true for monsters that obviously (to the player) feel
-// "thematically at home" in a branch
-// currently used for native monsters recognizing traps
+// Returns true for monsters that obviously (to the player)
+// feel "thematically at home" in a branch.
+// Currently used for native monsters recognizing traps.
static bool _is_native_in_branch(const monsters *monster,
const branch_type branch)
{
@@ -5777,7 +5807,7 @@ static bool _is_trap_safe(const monsters *monster, const int trap_x,
}
}
- // friendlies will try not to be parted from you
+ // Friendlies will try not to be parted from you.
if (intelligent_ally(monster) && trap.type == TRAP_TELEPORT
&& player_knows_trap && mons_near(monster))
{
@@ -5991,21 +6021,19 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
// Friendlies shouldn't try to move onto the player's
// location, if they are aiming for some other target.
if (mons_wont_attack(monster)
- && monster->foe != MHITNOT
&& monster->foe != MHITYOU
+ && (monster->foe != MHITNOT || monster->is_patrolling())
&& targ_x == you.x_pos
&& targ_y == you.y_pos)
{
return false;
}
- // wandering through a trap is OK if we're pretty healthy,
- // really stupid, or immune to the trap
+ // Wandering through a trap is OK if we're pretty healthy,
+ // really stupid, or immune to the trap.
const int which_trap = trap_at_xy(targ_x,targ_y);
if (which_trap >= 0 && !_is_trap_safe(monster, targ_x, targ_y, just_check))
- {
return false;
- }
if (targ_cloud_num != EMPTY_CLOUD)
{
@@ -6054,8 +6082,8 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
return true;
break;
- // this isn't harmful, but dumb critters might think so.
case CLOUD_GREY_SMOKE:
+ // This isn't harmful, but dumb critters might think so.
if (mons_intel(monster->type) > I_ANIMAL || coinflip())
return true;
@@ -6070,13 +6098,13 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
return true; // harmless clouds
}
- // if we get here, the cloud is potentially harmful.
- // exceedingly dumb creatures will still wander in.
+ // If we get here, the cloud is potentially harmful.
+ // Exceedingly dumb creatures will still wander in.
if (mons_intel(monster->type) != I_PLANT)
return false;
}
- // if we end up here the monster can safely move
+ // If we end up here the monster can safely move.
return true;
}
@@ -6089,7 +6117,7 @@ static bool _monster_move(monsters *monster)
const habitat_type habitat = mons_habitat(monster);
bool deep_water_available = false;
- // Berserking monsters make a lot of racket
+ // Berserking monsters make a lot of racket.
if (monster->has_ench(ENCH_BERSERK))
{
int noise_level = get_shout_noise_level(mons_shouts(monster->type));
@@ -6128,7 +6156,7 @@ static bool _monster_move(monsters *monster)
return false;
}
- // let's not even bother with this if mmov_x and mmov_y are zero.
+ // Let's not even bother with this if mmov_x and mmov_y are zero.
if (mmov_x == 0 && mmov_y == 0)
return false;
@@ -6145,10 +6173,7 @@ static bool _monster_move(monsters *monster)
const int targ_x = monster->x + count_x - 1;
const int targ_y = monster->y + count_y - 1;
- // [ds] Bounds check was after grd[targ_x][targ_y] which would
- // trigger an ASSERT. Moved it up.
-
- // bounds check - don't consider moving out of grid!
+ // Bounds check - don't consider moving out of grid!
if (targ_x < 0 || targ_x >= GXM || targ_y < 0 || targ_y >= GYM)
{
good_move[count_x][count_y] = false;
@@ -6162,11 +6187,13 @@ static bool _monster_move(monsters *monster)
const monsters* mons = dynamic_cast<const monsters*>(monster);
good_move[count_x][count_y] =
_mon_can_move_to_pos(mons, count_x-1, count_y-1);
- } // now we know where we _can_ move.
+ }
+
+ // Now we know where we _can_ move.
const coord_def newpos = monster->pos() + coord_def(mmov_x, mmov_y);
- // normal/smart monsters know about secret doors (they _live_ in the
- // dungeon!)
+ // Normal/smart monsters know about secret doors
+ // (they _live_ in the dungeon!)
if (grd(newpos) == DNGN_CLOSED_DOOR
|| (grd(newpos) == DNGN_SECRET_DOOR
&& (mons_intel(monster_index(monster)) == I_HIGH
@@ -6174,7 +6201,7 @@ static bool _monster_move(monsters *monster)
{
if (mons_is_zombified(monster))
{
- // for zombies, monster type is kept in mon->base_monster
+ // For zombies, monster type is kept in mon->base_monster.
if (mons_itemuse(monster->base_monster) >= MONUSE_OPEN_DOORS)
{
_mons_open_door(monster, newpos);
@@ -6210,7 +6237,7 @@ static bool _monster_move(monsters *monster)
} // done door-eating jellies
- // water creatures have a preference for water they can hide in -- bwr
+ // Water creatures have a preference for water they can hide in -- bwr
// [ds] Weakened the powerful attraction to deep water if the monster
// is in good health.
if (habitat == HT_WATER
@@ -6309,7 +6336,7 @@ static bool _monster_move(monsters *monster)
if (dist[0] == dist[1] && abs(dist[0]) == FAR_AWAY)
continue;
- // which one was better? -- depends on FLEEING or not
+ // Which one was better? -- depends on FLEEING or not.
if (monster->behaviour == BEH_FLEE)
{
if (dist[0] >= dist[1] && dist[0] >= current_distance)
@@ -6346,10 +6373,10 @@ static bool _monster_move(monsters *monster)
forget_it:
// ------------------------------------------------------------------
- // if we haven't found a good move by this point, we're not going to.
+ // If we haven't found a good move by this point, we're not going to.
// ------------------------------------------------------------------
- // take care of beetle burrowing
+ // Take care of beetle burrowing.
if (monster->type == MONS_BORING_BEETLE)
{
dungeon_feature_type feat =
@@ -6368,7 +6395,7 @@ forget_it:
bool ret = false;
if (good_move[mmov_x + 1][mmov_y + 1] && !(mmov_x == 0 && mmov_y == 0))
{
- // check for attacking player
+ // Check for attacking player.
if (monster->x + mmov_x == you.x_pos
&& monster->y + mmov_y == you.y_pos)
{
@@ -6407,7 +6434,7 @@ forget_it:
}
}
- // check for attacking another monster
+ // Check for attacking another monster.
int targmon = mgrd[monster->x + mmov_x][monster->y + mmov_y];
if (targmon != NON_MONSTER)
{
@@ -6442,8 +6469,8 @@ forget_it:
{
mmov_x = mmov_y = 0;
- // fleeing monsters that can't move will panic and possibly
- // turn to face their attacker
+ // Fleeing monsters that can't move will panic and possibly
+ // turn to face their attacker.
if (monster->behaviour == BEH_FLEE)
behaviour_event(monster, ME_CORNERED);
}
@@ -6844,7 +6871,7 @@ void seen_monster(monsters *monster)
if (monster->flags & MF_SEEN)
return;
- // First time we've seen this particular monster
+ // First time we've seen this particular monster.
monster->flags |= MF_SEEN;
if (!mons_is_mimic(monster->type)
@@ -6878,7 +6905,7 @@ bool shift_monster( monsters *mon, int x, int y )
if (x == 0 && y == 0)
{
- // try and find a random floor space some distance away
+ // Try and find a random floor space some distance away.
for (i = 0; i < 50; i++)
{
tx = 5 + random2( GXM - 10 );
@@ -6902,7 +6929,7 @@ bool shift_monster( monsters *mon, int x, int y )
if (!inside_level_bounds(tx, ty))
continue;
- // don't drop on anything but vanilla floor right now
+ // Don't drop on anything but vanilla floor right now.
if (grd[tx][ty] != DNGN_FLOOR)
continue;
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 6daeea3893..019ea1605f 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -2438,7 +2438,7 @@ bool find_ray( int sourcex, int sourcey, int targetx, int targety,
// Count the number of matching features between two points along
// a beam-like path; the path will pass through solid features.
-// By default, it excludes enpoints from the count.
+// By default, it excludes end points from the count.
int num_feats_between(int sourcex, int sourcey, int targetx, int targety,
dungeon_feature_type min_feat,
dungeon_feature_type max_feat,
@@ -3632,7 +3632,7 @@ bool see_grid( const coord_def &p )
return see_grid(env.show, you.pos(), p);
}
-// answers the question: "Would a grid be within character's line of sight,
+// Answers the question: "Would a grid be within character's line of sight,
// even if all translucent/clear walls were made opaque?"
bool see_grid_no_trans( const coord_def &p )
{
@@ -3645,6 +3645,25 @@ bool trans_wall_blocking( const coord_def &p )
return see_grid(p) && !see_grid_no_trans(p);
}
+// Usually calculates whether from one grid someone could see the other.
+// Depending on the viewer's habitat, 'allowed' can be set to DNGN_FLOOR,
+// DNGN_SHALLOW_WATER or DNGN_DEEP_WATER.
+// Yes, this ignores lava-loving monsters.
+bool grid_see_grid(int posx_1, int posy_1, int posx_2, int posy_2,
+ dungeon_feature_type allowed)
+{
+ if (distance(posx_1, posy_1, posx_2, posy_2) > LOS_RADIUS * LOS_RADIUS)
+ return (false);
+
+ dungeon_feature_type max_disallowed = DNGN_MAXOPAQUE;
+ if (allowed != DNGN_UNSEEN)
+ max_disallowed = static_cast<dungeon_feature_type>(allowed - 1);
+
+ // XXX: Ignoring clouds for now.
+ return (num_feats_between(posx_1, posy_1, posx_2, posy_2, DNGN_UNSEEN,
+ max_disallowed) == 0);
+}
+
static const unsigned dchar_table[ NUM_CSET ][ NUM_DCHAR_TYPES ] =
{
// CSET_ASCII
diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h
index 40e45becb6..135314223f 100644
--- a/crawl-ref/source/view.h
+++ b/crawl-ref/source/view.h
@@ -194,6 +194,8 @@ bool see_grid( const env_show_grid &show,
bool see_grid(const coord_def &p);
bool see_grid_no_trans( const coord_def &p );
bool trans_wall_blocking( const coord_def &p );
+bool grid_see_grid(int posx_1, int posy_1, int posx_2, int posy_2,
+ dungeon_feature_type allowed = DNGN_UNSEEN);
inline bool see_grid( int grx, int gry )
{