git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2811 c06c8d41-db1a-0410-9941-cceddc491573
PM65H4V4GNPVIJFUQW57DC3VDB7TRUUNXKVZONQKEFZSK3AXX5GQC
3V52MSSK7QX7FWLLUW63DTWCBAJEK674EFZLKP45FLZ5KZKVARHAC
SJDOBXECX7F3ZPPVR7FPURE53D47PP2TFIF4SB6XPS456PZV3DQAC
NNG27Y5ZQAZX6UD7F7M4F6KEZBEDFXPEEC3LFUSX4ESKT7K6UJQAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
T2AYVN57EFJQLFUFLAZDXKDAFDGTDLQIEQWQZNYFWJZBYSTYH4QQC
OSGS3PH2L5CBTDVZCZS6OCFQNA4A7RMEXBYJQB7DDZBYYJW7QSSAC
FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC
WUWTYSQ2Z7HI637WNO2J55LW6WLPBDF2ILH622T47ICW3AN7OWMQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
AUXVWXWIFSTWFA6VZXN2FMG7FQEKRZVV6MD32VQQ7J2RKCXHAVGAC
B62ICMDTN5V7R7RBL4JALFVKEMVOOVLRSJASRNYS6CGFWBEEF5JQC
Y3RBMQ7B6PFQRC6TH7PCIHHGA652AN3FTWTTYAOQHBSWOYDJ7XGQC
ZCNA74GZB3323BWZO3UTFG2BNYNQRZOKZDKCCMXIUAO5UKOU3NCQC
static bool is_trap_safe(const monsters *monster, const trap_struct &trap)
// Check whether a given trap (described by trap position) can be
// regarded as safe. Takes in account monster intelligence and allegiance.
// (just_check is used for intelligent friendlies trying to avoid traps.)
static bool is_trap_safe(const monsters *monster, const int trap_x,
const int trap_y, bool just_check = false)
const int x = monster->x;
const int y = monster->y;
// test for corridor-like environment (simple hack)
if (!(grd[x-1][y] < DNGN_MINMOVE && grd[x+1][y] < DNGN_MINMOVE
|| grd[x][y-1] < DNGN_MINMOVE && grd[x][y+1] < DNGN_MINMOVE))
if (just_check)
return false; // square is blocked
else
return (monster->hit_points == monster->max_hit_points);
// test for corridor-like environment
const int x = trap_x - monster->x;
const int y = trap_y - monster->y;
// The question is whether the monster (m) can easily reach its
// presumable destination (x) without stepping on the trap. Traps
// in corridors do not allow this. See e.g
// #x# ##
// #^# or m^x
// m ##
//
// The same problem occurs if paths are blocked by monsters,
// hostile terrain or other traps rather than walls.
// What we do is check whether the squares with the relative
// positions (-1,0)/(+1,0) or (0,-1)/(0,+1) form a "corridor"
// (relative to the _current_ monster position rather than the
// trap one) form a corridor-like environment. If they don't
// the trap square is marked as "unsafe", otherwise the decision
// will be made according to later tests (monster hp, trap type, ...)
// If a monster still gets stuck in a corridor it will usually be
// because it has less than half its maximum hp
if ((mon_can_move_to_pos(monster, x-1, y, true)
|| mon_can_move_to_pos(monster, x+1,y, true))
&& (mon_can_move_to_pos(monster, x,y-1, true)
|| mon_can_move_to_pos(monster, x,y+1, true)))
{
return (false);
}
}
// Check whether a monster can move to given square (described by its relative
// coordinates to the current monster position). just_check is true only for
// calls from is_trap_safe when checking the surrounding squares of a trap.
bool mon_can_move_to_pos(const monsters *monster, const int count_x,
const int count_y, bool just_check)
{
const int targ_x = monster->x + count_x;
const int targ_y = monster->y + count_y;
// bounds check - don't consider moving out of grid!
if (targ_x < 0 || targ_x >= GXM || targ_y < 0 || targ_y >= GYM)
return false;
dungeon_feature_type target_grid = grd[targ_x][targ_y];
const int habitat = monster_habitat( monster->type );
// effectively slows down monster movement across water.
// Fire elementals can't cross at all.
bool no_water = false;
if (monster->type == MONS_FIRE_ELEMENTAL || one_chance_in(5))
//okmove = DNGN_WATER_STUCK;
no_water = true;
const int targ_cloud_num = env.cgrid[ targ_x ][ targ_y ];
const int targ_cloud_type =
targ_cloud_num == EMPTY_CLOUD? CLOUD_NONE
: env.cloud[targ_cloud_num].type;
const int curr_cloud_num = env.cgrid[ monster->x ][ monster->y ];
const int curr_cloud_type =
curr_cloud_num == EMPTY_CLOUD? CLOUD_NONE
: env.cloud[curr_cloud_num].type;
if (monster->type == MONS_BORING_BEETLE
&& (target_grid == DNGN_ROCK_WALL
|| target_grid == DNGN_CLEAR_ROCK_WALL))
{
// don't burrow out of bounds
if (targ_x <= 7 || targ_x >= (GXM - 8)
|| targ_y <= 7 || targ_y >= (GYM - 8))
{
return false;
}
// don't burrow at an angle (legacy behaviour)
if (count_x != 0 && count_y != 0)
{
return false;
}
}
else if (!monster->can_pass_through(target_grid)
|| (no_water && target_grid >= DNGN_DEEP_WATER
&& target_grid <= DNGN_WATER_STUCK))
{
return false;
}
else if (!habitat_okay( monster, target_grid ))
{
return false;
}
if (monster->type == MONS_WANDERING_MUSHROOM
&& see_grid(targ_x, targ_y))
{
return false;
}
// Water elementals avoid fire and heat
if (monster->type == MONS_WATER_ELEMENTAL
&& (target_grid == DNGN_LAVA
|| targ_cloud_type == CLOUD_FIRE
|| targ_cloud_type == CLOUD_STEAM))
{
return false;
}
// Fire elementals avoid water and cold
if (monster->type == MONS_FIRE_ELEMENTAL
&& (target_grid == DNGN_DEEP_WATER
|| target_grid == DNGN_SHALLOW_WATER
|| target_grid == DNGN_BLUE_FOUNTAIN
|| targ_cloud_type == CLOUD_COLD))
{
return false;
}
// Submerged water creatures avoid the shallows where
// they would be forced to surface. -- bwr
// [dshaligram] Monsters now prefer to head for deep water only if
// they're low on hitpoints. No point in hiding if they want a
// fight.
if (habitat == DNGN_DEEP_WATER
&& (targ_x != you.x_pos || targ_y != you.y_pos)
&& target_grid != DNGN_DEEP_WATER
&& grd[monster->x][monster->y] == DNGN_DEEP_WATER
&& monster->hit_points < (monster->max_hit_points * 3) / 4)
{
return false;
}
// smacking the player is always a good move if we're
// hostile (even if we're heading somewhere else)
// also friendlies want to keep close to the player
// so it's okay as well
// smacking another monster is good, if the monsters
// are aligned differently
if (mgrd[targ_x][targ_y] != NON_MONSTER)
{
if (just_check)
{
if (targ_x == monster->x && targ_y == monster->y)
return true;
return false; // blocks square
}
const int thismonster = monster_index(monster),
targmonster = mgrd[targ_x][targ_y];
if (mons_aligned(thismonster, targmonster)
&& targmonster != MHITNOT
&& targmonster != MHITYOU
&& !mons_can_displace(monster, &menv[targmonster]))
{
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;
}
if (targ_cloud_num != EMPTY_CLOUD)
{
if (curr_cloud_num != EMPTY_CLOUD
&& targ_cloud_type == curr_cloud_type)
{
return true;
}
switch (targ_cloud_type)
{
case CLOUD_FIRE:
if (mons_res_fire(monster) > 0)
return true;
if (monster->hit_points >= 15 + random2avg(46, 5))
return true;
break;
case CLOUD_STINK:
if (mons_res_poison(monster) > 0)
return true;
if (1 + random2(5) < monster->hit_dice)
return true;
if (monster->hit_points >= random2avg(19, 2))
return true;
break;
case CLOUD_COLD:
if (mons_res_cold(monster) > 0)
return true;
if (monster->hit_points >= 15 + random2avg(46, 5))
return true;
break;
case CLOUD_POISON:
if (mons_res_poison(monster) > 0)
return true;
if (monster->hit_points >= random2avg(37, 4))
return true;
break;
// this isn't harmful, but dumb critters might think so.
case CLOUD_GREY_SMOKE:
if (mons_intel(monster->type) > I_ANIMAL || coinflip())
return true;
if (mons_res_fire(monster) > 0)
return true;
if (monster->hit_points >= random2avg(19, 2))
return true;
break;
default:
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;
}
// if we end up here the monster can safely move
return true;
// effectively slows down monster movement across water.
// Fire elementals can't cross at all.
bool no_water = false;
if (monster->type == MONS_FIRE_ELEMENTAL || one_chance_in(5))
//okmove = DNGN_WATER_STUCK;
no_water = true;
good_move[count_x][count_y] = true;
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!
if (targ_x < 0 || targ_x >= GXM || targ_y < 0 || targ_y >= GYM)
{
good_move[count_x][count_y] = false;
continue;
}
dungeon_feature_type target_grid = grd[targ_x][targ_y];
const int targ_cloud_num = env.cgrid[ targ_x ][ targ_y ];
const int targ_cloud_type =
targ_cloud_num == EMPTY_CLOUD? CLOUD_NONE
: env.cloud[targ_cloud_num].type;
const int curr_cloud_num = env.cgrid[ monster->x ][ monster->y ];
const int curr_cloud_type =
curr_cloud_num == EMPTY_CLOUD? CLOUD_NONE
: env.cloud[curr_cloud_num].type;
if (target_grid == DNGN_DEEP_WATER)
deep_water_available = true;
if (monster->type == MONS_BORING_BEETLE
&& (target_grid == DNGN_ROCK_WALL
|| target_grid == DNGN_CLEAR_ROCK_WALL))
{
// don't burrow out of bounds
if (targ_x <= 7 || targ_x >= (GXM - 8)
|| targ_y <= 7 || targ_y >= (GYM - 8))
{
good_move[count_x][count_y] = false;
continue;
}
// don't burrow at an angle (legacy behaviour)
if (count_x != 1 && count_y != 1)
{
good_move[count_x][count_y] = false;
continue;
}
}
else if (!monster->can_pass_through(target_grid)
|| (no_water && target_grid >= DNGN_DEEP_WATER
&& target_grid <= DNGN_WATER_STUCK))
{
good_move[count_x][count_y] = false;
continue;
}
else if (!habitat_okay( monster, target_grid ))
{
good_move[count_x][count_y] = false;
continue;
}
if (monster->type == MONS_WANDERING_MUSHROOM
&& see_grid(targ_x, targ_y))
{
good_move[count_x][count_y] = false;
continue;
}
// Water elementals avoid fire and heat
if (monster->type == MONS_WATER_ELEMENTAL
&& (target_grid == DNGN_LAVA
|| targ_cloud_type == CLOUD_FIRE
|| targ_cloud_type == CLOUD_STEAM))
{
good_move[count_x][count_y] = false;
continue;
}
// Fire elementals avoid water and cold
if (monster->type == MONS_FIRE_ELEMENTAL
&& (target_grid == DNGN_DEEP_WATER
|| target_grid == DNGN_SHALLOW_WATER
|| target_grid == DNGN_BLUE_FOUNTAIN
|| targ_cloud_type == CLOUD_COLD))
{
good_move[count_x][count_y] = false;
continue;
}
// Submerged water creatures avoid the shallows where
// they would be forced to surface. -- bwr
// [dshaligram] Monsters now prefer to head for deep water only if
// they're low on hitpoints. No point in hiding if they want a
// fight.
if (habitat == DNGN_DEEP_WATER
&& (targ_x != you.x_pos || targ_y != you.y_pos)
&& target_grid != DNGN_DEEP_WATER
&& grd[monster->x][monster->y] == DNGN_DEEP_WATER
&& monster->hit_points < (monster->max_hit_points * 3) / 4)
{
good_move[count_x][count_y] = false;
continue;
}
// smacking the player is always a good move if
// we're hostile (even if we're heading somewhere
// else)
// smacking another monster is good, if the monsters
// are aligned differently
if (mgrd[targ_x][targ_y] != NON_MONSTER)
{
const int thismonster = monster_index(monster),
targmonster = mgrd[targ_x][targ_y];
if (mons_aligned(thismonster, targmonster)
&& targmonster != MHITNOT
&& targmonster != MHITYOU
&& !mons_can_displace(monster, &menv[targmonster]))
{
good_move[count_x][count_y] = false;
continue;
}
}
// 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, env.trap[which_trap]))
{
good_move[count_x][count_y] = false;
continue;
}
if (targ_cloud_num != EMPTY_CLOUD)
{
if (curr_cloud_num != EMPTY_CLOUD
&& targ_cloud_type == curr_cloud_type)
{
continue;
}
switch (targ_cloud_type)
{
case CLOUD_FIRE:
if (mons_res_fire(monster) > 0)
continue;
if (monster->hit_points >= 15 + random2avg(46, 5))
continue;
break;
case CLOUD_STINK:
if (mons_res_poison(monster) > 0)
continue;
if (1 + random2(5) < monster->hit_dice)
continue;
if (monster->hit_points >= random2avg(19, 2))
continue;
break;
case CLOUD_COLD:
if (mons_res_cold(monster) > 0)
continue;
if (monster->hit_points >= 15 + random2avg(46, 5))
continue;
break;
case CLOUD_POISON:
if (mons_res_poison(monster) > 0)
continue;
if (monster->hit_points >= random2avg(37, 4))
continue;
break;
// this isn't harmful, but dumb critters might think so.
case CLOUD_GREY_SMOKE:
if (mons_intel(monster->type) > I_ANIMAL || coinflip())
continue;
const int targ_x = monster->x + count_x - 1;
const int targ_y = monster->y + count_y - 1;
if (monster->hit_points >= random2avg(19, 2))
continue;
break;
// 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;
continue;
}
dungeon_feature_type target_grid = grd[targ_x][targ_y];
// if we get here, the cloud is potentially harmful.
// exceedingly dumb creatures will still wander in.
if (mons_intel(monster->type) != I_PLANT)
good_move[count_x][count_y] = false;
}
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);