summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/monstuff.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/monstuff.cc')
-rw-r--r--crawl-ref/source/monstuff.cc179
1 files changed, 107 insertions, 72 deletions
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index c1431bea59..8aeb15df70 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -2325,20 +2325,21 @@ static bool _choose_random_patrol_target_grid(monsters *mon)
// If a monster can see but not directly reach the player, and then fails to
// find a path to get him, mark all surrounding (in a radius of 2) monsters
-// of the same species as also being unable to find a path, so we won't need
-// to calculate again.
+// of the same (or greater) movement restrictions as also being unable to
+// find a path, so we won't need to calculate again.
// Should there be a direct path to the player for a monster thus marked, it
-// will still be able to come nearer (and the mark will be cleared).
-static void _mark_species_members_player_unreachable(monsters *mon)
+// will still be able to come nearer (and the mark will then be cleared).
+static void _mark_neighbours_player_unreachable(monsters *mon)
{
- // Highly intelligent monsters are capable of pathfinding and don't
- // need their neighbour's advice.
- if (mons_intel(mon->type) > I_NORMAL)
+ // Highly intelligent monsters are perfectly capable of pathfinding
+ // and don't need their neighbour's advice.
+ const int intel = mons_intel(mon->type);
+ if (intel > I_NORMAL)
return;
- // We won't be able to find pack members of human unique monsters.
- if (mons_is_unique(mon->type) && mons_species(mon->type) == MONS_HUMAN)
- return;
+ bool flies = mons_flies(mon);
+ bool amphibious = mons_amphibious(mon);
+ habitat_type habit = mons_habitat(mon);
int x, y;
monsters *m;
@@ -2364,15 +2365,22 @@ static void _mark_species_members_player_unreachable(monsters *mon)
m = &menv[mgrd[x][y]];
- // Only mark target for monsters of same species.
- // Restrict to same _type_ for humans (by far the most
- // versatile species).
- if (mon->type != m->type
- && (mon->type == MONS_HUMAN
- || mons_species(mon->type) != mons_species(m->type)))
- {
+ // Don't restrict smarter monsters as they might find a path
+ // a dumber monster wouldn't.
+ if (mons_intel(m->type) > intel)
+ continue;
+
+ // Monsters of differing habitats might prefer different routes.
+ if (mons_habitat(m) != habit)
+ continue;
+
+ // A flying monster has an advantage over a non-flying one.
+ if (!flies && mons_flies(m))
+ continue;
+
+ // Same for a swimming one, around water.
+ if (you.water_in_sight && !amphibious && mons_amphibious(m))
continue;
- }
if (m->travel_target == MTRAV_NONE)
m->travel_target = MTRAV_UNREACHABLE;
@@ -2424,14 +2432,8 @@ static void _handle_behaviour(monsters *mon)
return;
}
- dungeon_feature_type can_move;
- if (mons_amphibious(mons_is_zombified(mon) ?
- mon->base_monster : mon->type))
- {
- can_move = DNGN_DEEP_WATER;
- }
- else
- can_move = DNGN_SHALLOW_WATER;
+ const dungeon_feature_type can_move =
+ (mons_amphibious(mon)) ? DNGN_DEEP_WATER : DNGN_SHALLOW_WATER;
// Validate current target exists.
if (mon->foe != MHITNOT && mon->foe != MHITYOU
@@ -2543,7 +2545,7 @@ static void _handle_behaviour(monsters *mon)
{
foe_x = you.x_pos;
foe_y = you.y_pos;
- proxFoe = proxPlayer; // take invis into account
+ proxFoe = proxPlayer; // Take invis into account.
}
else
{
@@ -2683,9 +2685,41 @@ static void _handle_behaviour(monsters *mon)
// Monster can see foe: continue 'tracking'
// by updating target x,y.
- if (mon->foe == MHITYOU)
+ if (mon->foe == MHITYOU && proxPlayer)
{
- if (proxPlayer && !trans_wall_block)
+ bool potentially_blocking = trans_wall_block;
+
+ // Smart monsters that can fire through walls won't use
+ // pathfinding.
+ if (potentially_blocking && mons_intel(mon->type) >= I_NORMAL
+ && mons_has_los_ability(mon->type))
+ {
+ potentially_blocking = false;
+ }
+ else
+ {
+ // Flying monsters don't see water/lava as obstacle.
+ // Also don't use pathfinding if the monster can shoot
+ // across the blocking terrain, and is smart enough to
+ // realize that.
+ if (!potentially_blocking && !mons_flies(mon)
+ && (mons_intel(mon->type) < I_NORMAL
+ || !mons_has_ranged_spell(mon)
+ && !mons_has_ranged_attack(mon)))
+ {
+ const habitat_type habit = mons_habitat(mon);
+ if (you.lava_in_sight && habit != HT_LAVA
+ || you.water_in_sight && habit != HT_WATER
+ && !mons_amphibious(mon))
+ {
+ potentially_blocking = true;
+ }
+ }
+ }
+
+ if (!potentially_blocking
+ || grid_see_grid(mon->x, mon->y, you.x_pos, you.y_pos,
+ can_move))
{
if (mon->travel_target != MTRAV_PATROL
&& mon->travel_target != MTRAV_NONE)
@@ -2695,9 +2729,8 @@ static void _handle_behaviour(monsters *mon)
mon->travel_target = MTRAV_NONE;
}
}
- else if (proxPlayer && trans_wall_block
- && (mon->travel_target != MTRAV_UNREACHABLE
- || one_chance_in(12)))
+ else if (mon->travel_target != MTRAV_UNREACHABLE
+ || one_chance_in(12))
{
#ifdef DEBUG_PATHFIND
mprf("%s: Player out of reach! What now?",
@@ -2711,8 +2744,8 @@ static void _handle_behaviour(monsters *mon)
#endif
int len = mon->travel_path.size();
coord_def targ = mon->travel_path[len - 1];
- if (grid_see_grid(targ.x, targ.y, you.x_pos, you.y_pos)
- && !trans_wall_blocking(targ.x, targ.y))
+ if (grid_see_grid(targ.x, targ.y, you.x_pos, you.y_pos,
+ can_move))
{
#ifdef DEBUG_PATHFIND
mpr("Target still valid?");
@@ -2817,7 +2850,8 @@ static void _handle_behaviour(monsters *mon)
mpr("No path found!");
#endif
mon->travel_target = MTRAV_UNREACHABLE;
- _mark_species_members_player_unreachable(mon);
+ // Pass information on to nearby monsters.
+ _mark_neighbours_player_unreachable(mon);
}
}
else
@@ -2826,6 +2860,7 @@ static void _handle_behaviour(monsters *mon)
mpr("No path found!");
#endif
mon->travel_target = MTRAV_UNREACHABLE;
+ _mark_neighbours_player_unreachable(mon);
}
}
}
@@ -6496,7 +6531,7 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
// Bounds check - don't consider moving out of grid!
if (!inside_level_bounds(targ_x, targ_y))
- return false;
+ return (false);
// Non-friendly and non-good neutral monsters won't enter sanctuaries.
if (!mons_wont_attack(monster)
@@ -6542,26 +6577,26 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
if (targ_x <= 7 || targ_x >= (GXM - 8)
|| targ_y <= 7 || targ_y >= (GYM - 8))
{
- return false;
+ return (false);
}
// Don't burrow at an angle (legacy behaviour).
if (count_x != 0 && count_y != 0)
- return false;
+ return (false);
}
else if (!monster->can_pass_through_feat(target_grid)
|| (no_water && target_grid >= DNGN_DEEP_WATER
&& target_grid <= DNGN_WATER_STUCK))
{
- return false;
+ return (false);
}
else if (!_habitat_okay( monster, target_grid ))
{
- return false;
+ return (false);
}
if (monster->type == MONS_WANDERING_MUSHROOM && see_grid(targ_x, targ_y))
- return false;
+ return (false);
// Water elementals avoid fire and heat.
if (monster->type == MONS_WATER_ELEMENTAL
@@ -6569,7 +6604,7 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
|| targ_cloud_type == CLOUD_FIRE
|| targ_cloud_type == CLOUD_STEAM))
{
- return false;
+ return (false);
}
// Fire elementals avoid water and cold
@@ -6577,7 +6612,7 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
&& (grid_is_watery(target_grid)
|| targ_cloud_type == CLOUD_COLD))
{
- return false;
+ return (false);
}
// Submerged water creatures avoid the shallows where
@@ -6591,7 +6626,7 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
&& grd[monster->x][monster->y] == DNGN_DEEP_WATER
&& monster->hit_points < (monster->max_hit_points * 3) / 4)
{
- return false;
+ return (false);
}
// Smacking the player is always a good move if we're
@@ -6606,9 +6641,9 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
if (just_check)
{
if (targ_x == monster->x && targ_y == monster->y)
- return true;
+ return (true);
- return false; // blocks square
+ return (false); // blocks square
}
const int thismonster = monster_index(monster),
@@ -6619,7 +6654,7 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
&& targmonster != MHITYOU
&& !_mons_can_displace(monster, &menv[targmonster]))
{
- return false;
+ return (false);
}
}
@@ -6631,21 +6666,21 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
&& targ_x == you.x_pos
&& targ_y == you.y_pos)
{
- return false;
+ return (false);
}
// 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;
+ return (false);
if (targ_cloud_num != EMPTY_CLOUD)
{
if (curr_cloud_num != EMPTY_CLOUD
&& targ_cloud_type == curr_cloud_type)
{
- return true;
+ return (true);
}
switch (targ_cloud_type)
@@ -6656,61 +6691,61 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
case CLOUD_FIRE:
if (mons_res_fire(monster) > 1)
- return true;
+ return (true);
if (monster->hit_points >= 15 + random2avg(46, 5))
- return true;
+ return (true);
break;
case CLOUD_STINK:
if (mons_res_poison(monster) > 0)
- return true;
+ return (true);
if (1 + random2(5) < monster->hit_dice)
- return true;
+ return (true);
if (monster->hit_points >= random2avg(19, 2))
- return true;
+ return (true);
break;
case CLOUD_COLD:
if (mons_res_cold(monster) > 1)
- return true;
+ return (true);
if (monster->hit_points >= 15 + random2avg(46, 5))
- return true;
+ return (true);
break;
case CLOUD_POISON:
if (mons_res_poison(monster) > 0)
- return true;
+ return (true);
if (monster->hit_points >= random2avg(37, 4))
- return true;
+ return (true);
break;
case CLOUD_GREY_SMOKE:
// This isn't harmful, but dumb critters might think so.
if (mons_intel(monster->type) > I_ANIMAL || coinflip())
- return true;
+ return (true);
if (mons_res_fire(monster) > 0)
- return true;
+ return (true);
if (monster->hit_points >= random2avg(19, 2))
- return true;
+ return (true);
break;
default:
- return true; // harmless clouds
+ return (true); // harmless clouds
}
// 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;
+ return (false);
}
// If we end up here the monster can safely move.
- return true;
+ return (true);
}
static bool _monster_move(monsters *monster)
@@ -6725,7 +6760,7 @@ static bool _monster_move(monsters *monster)
if (monster->type == MONS_TRAPDOOR_SPIDER)
{
if(monster->has_ench(ENCH_SUBMERGED))
- return false;
+ return (false);
// Trapdoor spiders hide if they can't see their target.
bool can_see;
@@ -6743,7 +6778,7 @@ static bool _monster_move(monsters *monster)
{
monster->add_ench(ENCH_SUBMERGED);
monster->behaviour = BEH_LURK;
- return false;
+ return (false);
}
}
@@ -6784,16 +6819,16 @@ static bool _monster_move(monsters *monster)
return _do_move_monster(monster, mmov_x, mmov_y);
}
}
- return false;
+ return (false);
}
// Let's not even bother with this if mmov_x and mmov_y are zero.
if (mmov_x == 0 && mmov_y == 0)
- return false;
+ return (false);
if (mons_flies(monster) != FL_NONE
|| habitat != HT_LAND
- || mons_amphibious(monster->type))
+ || mons_amphibious(monster))
{
okmove = DNGN_MINMOVE;
}
@@ -6836,13 +6871,13 @@ static bool _monster_move(monsters *monster)
if (mons_itemuse(monster->base_monster) >= MONUSE_OPEN_DOORS)
{
_mons_open_door(monster, newpos);
- return true;
+ return (true);
}
}
else if (mons_itemuse(monster->type) >= MONUSE_OPEN_DOORS)
{
_mons_open_door(monster, newpos);
- return true;
+ return (true);
}
} // endif - secret/closed doors