the level to use the pathfinding routines for patrolling. The monsters still sometimes disappear when near the exit instead of on it, which needs to be fixed, but it's vastly closer to working properly.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@6186 c06c8d41-db1a-0410-9941-cceddc491573
SPWOUV6ZNHLBSAX455ACJDBEJYVFHGO4H76L4NPAE5DF6BEAK34QC
XJBNF2N35THJC2KYGCMPLC3CDCJP25CEDKHUI3P55V6H5YWXBUKAC
XBC6V43KX2PSRWHAW3FUCALPYEDP2FNQMR7UA4FHLXQ6JI42PP2AC
U54JNIWKKB5QRZVEK4ZMBHAVVB6HLKVJVZENZHDOINKBCOAUDOGAC
Q7MDQRE6DP7C6BYGJDFYHHAUZGYQUNZINQWU7GTLT4HNYAEXYUOQC
SWQ3SMISYGEY5OFIR74O5XHGQXCBZE3ZVQDYC2SUA7V327VTE7KQC
VT6WFXYCMVUYNQVKLVT3QZTICAYNKG4LTG2Q44LZCC6CM35KP2CAC
J4LFL6BUKGETJOK3O54CPTCP6NNVXWUHYBQ4IEQMHI67VBS4LNBAC
SKWBAGSAB625IIN4UP3NCPRX2H3KCPC2LULHS2A7JVRLO3EUBJDAC
Y5YQ2AXS6XTWCHEQFDXRYU2IDQTBW7WXNJFES22GSKYQ2JGZ3U5AC
BINKDWGFGUPTOA7IE5KK4ZIELGU5WC3X47MYXOWU4X43EGAC5DUAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
VNB7OLRPCC7ITTUKYLQ4SDV25QD2XZHXOYXDCIRJ2OTF2U4VZFWAC
25EX6COTFUVEIGQMCJ47FDSEKASVVO74LPJ4ZS66ZYUYXD5G3N3QC
P5TRGRH7XMQSPCZKM5IEEO34TY6WMLGHHX7BU6Y453JFRXLUR2VQC
VEVPRVWGRHRKBBUTO64ELK3NPZANUQI3ZZ7F23YXJQLKIORUW3HQC
D7SLVLRNCYCBDYYRANHDG3JYEF25CFCSUY5FMF5KXVD5D4UZSDDAC
5CRNBCK3AH6UGZN4R5MZ47UCVYYA3CKFXYPKEPZWRTBJ5PIGDB6AC
F4FAPEZ5P5CPHZIHUSRYULB3LY4LOJCUC7DZAYVL77LFFBUBCUNAC
MPBVX6OOMRMXWV4AZG4MZ4B6BYMWHHF5OOLD5FUGQCHM6UKBCIEAC
FXK7Y2F4YJE422WMQ6TYHONWVVDRWLWCU47BXHXCR53DHF6YC76AC
IQVLEFABSOHRW24PGIX6XGDJQJG5NXYWLZTKE2V26ZS3OPMH2IZQC
HDFQR3WVDBL62P3RTJ4LBIOTHHL2ZN4FHKUIBCERHLQYDRLHRTKQC
EMOBSWJHHB4V6WVMZL7JCF2V3KZN454Z6NS346OKFPMBNO24EJDQC
LH4OYDEWEON5QNUCM74R7MNBJDP7O4XRETY74ZMYSXUXYQV427PAC
REOC4SN5SYUZ6IDLV6I6XZ4MPKE36VAJXLCZ2SXYYZB3RECLXSLQC
BMZK7EPYNL2TBAQ7AWEJD466B4LI3RBPDXAIZCKBKJRIWOW7DCOAC
IPCURZEWW7HBUKIBNAHSPTYD2HVABST6T5VRVLNIUPYGSFYJLPDAC
S6NJIL6VIKUYD4VVXOT7V237J5WCKOIEBTNIMIF54CABA46KUETQC
U56SICUKK36SJAG3QKV4WGDSAXOW5BELRPZGHTRAMZVUV56AESVAC
FWLLPRIZDBJVQ336TPOLYAFT6WYGAFC52OFIOTRN2YQPFZ3PQVRQC
JME76OR4ZNGHYVDVQ6ZT7FCB4UMG4V3RVMTQJQNQRRR66KARJHLQC
FT2JKKQAUESFIMB2G5YGBI4FX7V7ARLOHWEKLP3M5MGV5ZCAAZMAC
6ZIZHBWWQC7HGUKAL5T2ADE3UXGFOEA7XNIIZOJO3DFPEW3TP7LAC
F7U354ESXSJ4GWPN6CPJ2FZ2ASEO55WS6NHUPTOBPT3OCNFXTB7AC
KVRDLMIRHKEMFKZ22JK5SZEDLDEXPEVOYWW535DN7EJVHL32IOMQC
UIKSTCCPMCWUK6PVX5HTCPJOZHQWZXRQ2J3LTJPZDYVV2STFOQGAC
3RNRFLMD2X4RUFTDVITLXAP377YB6F6YMQLL3DAXSUZDZBTWSLRQC
WQIEW3O4MANA2KKYRUWEZP44KHVJ4RRHEZTDXSF4EDELX66LO26QC
2YK255CF5YJ3LZTKOI633NJSVM63HFB3MAIYDV7ZJDCC5SWQIO6AC
EJYK3CKIEMP4NMZUCMUYLHIBE7A3LPZOU7DUON5V7CPHY7QEKLEAC
ZUV76RGZDBOY745YXVMGFUOWEH2B47J74BCT5MDKHIDHC4URGMKAC
3CY6KJWHQUZFZGO2C7VVCO32RRHUIMQQQJAE2MUXFF45F7ECRLJQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
TFKOHHRA6CJ44OODVA2WL4ITYOLPE6VLKDS7XVBK5JH6BHVZDDFAC
S2LIBA2CLTZ6ZU66AUZ2CCNLCDOBSGWQGTZ6HFAFP2XSWAALGLSQC
IBCGW7GAP7MBB4EQ5Q6B6GAOUIYG3O7NLU2LCK37E7ZSDMTAAYZQC
HIRKGUMNJPWKSVTR6TVBPD3MWNA63CEHCLCIPWEMGDFHVB3NPLDQC
trap_type tt = trap_type_at_xy(x, y);
if (tt == TRAP_SHAFT && _is_trap_safe(mon, x, y))
e.push_back(level_exit(coord_def(x, y), MTRAV_TRAP, false));
if (trap_type_at_xy(x, y) == TRAP_SHAFT
&& _is_trap_safe(mon, x, y))
{
e.push_back(level_exit(coord_def(x, y), false));
}
case MTRAV_STAIR:
command_type dir = grid_stair_direction(grd[x][y]);
simple_monster_message(mon,
make_stringf(" %s the stairs.",
dir == CMD_GO_UPSTAIRS ? "goes up" :
dir == CMD_GO_DOWNSTAIRS ? "goes down"
: "takes").c_str());
}
else if (is_gate(grd[x][y]))
simple_monster_message(mon, " passes through the gate.");
// Shaft traps.
else if (trap_type_at_xy(x, y) == TRAP_SHAFT)
if (is_travelable_stair(grd[x][y]))
{
command_type dir = grid_stair_direction(grd[x][y]);
simple_monster_message(mon,
make_stringf(" %s the stairs.",
dir == CMD_GO_UPSTAIRS ? "goes up" :
dir == CMD_GO_DOWNSTAIRS ? "goes down"
: "takes").c_str());
}
else if (is_gate(grd[x][y]))
simple_monster_message(mon, " passes through the gate.");
break;
simple_monster_message(mon, " falls through a shaft!");
grd[x][y] = trap_category(trap_type_at_xy(x, y));
trap_type tt = trap_type_at_xy(x, y);
if (tt == TRAP_SHAFT)
{
simple_monster_message(mon, " falls through a shaft!");
grd[x][y] = trap_category(tt);
}
break;
}
case MTRAV_SUBMERSIBLE:
new_beh = BEH_LEAVE;
break;
// If a pacified monster is far enough away from the
// player, make it leave the level.
if (grid_distance(mon->x, mon->y, you.x_pos, you.y_pos)
>= LOS_RADIUS * LOS_RADIUS * 4)
{
make_mons_leave_level(mon);
return;
}
// If a pacified monster isn't travelling toward
// someplace from which it can leave the level, make it
// start doing so.
if (mon->travel_target != MTRAV_PATROL
&& mon->travel_target != MTRAV_UNREACHABLE)
{
e_index = _mons_find_nearest_level_exit(mon, e);
if (e_index != -1)
{
mon->foe = MHITNOT;
patrolling = true;
mon->patrol_point = e[e_index].target;
mon->target_x = e[e_index].target.x;
mon->target_y = e[e_index].target.y;
mon->travel_target = MTRAV_PATROL;
mon->travel_path.clear();
}
}
// If the level exit is unreachable, find a new one.
if (mon->travel_target == MTRAV_UNREACHABLE)
{
e[e_index].unreachable = true;
mon->travel_target = MTRAV_NONE;
}
// If the monster is far enough away from the player, make
// it leave the level.
if (grid_distance(mon->x, mon->y, you.x_pos, you.y_pos)
>= LOS_RADIUS * LOS_RADIUS * 4)
{
make_mons_leave_level(mon);
return;
}
// If the monster isn't travelling toward someplace from
// which it can leave the level, and it can move (or at
// least teleport, as a mimic can), make it start doing so.
if (mon->travel_target == MTRAV_NONE)
{
e_index = _mons_find_nearest_level_exit(mon, e);
if (e_index != -1)
{
mon->foe = MHITNOT;
mon->target_x = e[e_index].target.x;
mon->target_y = e[e_index].target.y;
mon->travel_target = e[e_index].target_type;
if (travelling)
mon->travel_path.clear();
}
}
else if (mon->travel_target != MTRAV_UNREACHABLE
|| one_chance_in(12))
{
#ifdef DEBUG_PATHFIND
mprf("%s: Level exit out of reach! What now?",
mon->name(DESC_PLAIN).c_str());
#endif
// If we're already on our way, do nothing.
if (travelling)
{
// Current target still valid?
if (mon->x == mon->travel_path[0].x
&& mon->y == mon->travel_path[0].y)
{
// Get next waypoint.
mon->travel_path.erase(
mon->travel_path.begin() );
if (!mon->travel_path.empty())
{
mon->target_x = mon->travel_path[0].x;
mon->target_y = mon->travel_path[0].y;
break;
}
}
}
}
else
{
// Use pathfinding to find a (new) path to the level exit.
const int dist = grid_distance(mon->x, mon->y,
e[e_index].target.x,
e[e_index].target.y);
#ifdef DEBUG_PATHFIND
mprf("Need to calculate a path... (dist = %d)", dist);
#endif
const bool native = mons_is_native_in_branch(mon);
int range = 0;
switch (mons_intel(mon->type))
{
case I_PLANT:
range = 2;
break;
case I_INSECT:
range = 3;
break;
case I_ANIMAL:
range = 4;
break;
case I_NORMAL:
range = 8;
break;
default:
// Highly intelligent monsters can find their way
// anywhere. (range == 0 means no restriction.)
break;
}
if (range && native)
range += 3;
if (range > 0 && dist > range)
{
mon->travel_target = MTRAV_UNREACHABLE;
#ifdef DEBUG_PATHFIND
mprf("Distance too great, don't attempt pathfinding! (%s)",
mon->name(DESC_PLAIN).c_str());
#endif
}
else
{
#ifdef DEBUG_PATHFIND
mprf("Need a path for %s from (%d, %d) to (%d, %d), "
"max. dist = %d",
mon->name(DESC_PLAIN).c_str(), mon->x, mon->y,
e[e_index].target.x, e[e_index].target.y, range);
#endif
monster_pathfind mp;
if (range > 0)
mp.set_range(range);
if (mp.start_pathfind(mon, e[e_index].target))
{
mon->travel_path = mp.calc_waypoints();
if (!mon->travel_path.empty())
{
// Okay then, we found a path. Let's use it!
mon->target_x = mon->travel_path[0].x;
mon->target_y = mon->travel_path[0].y;
break;
}
else
{
#ifdef DEBUG_PATHFIND
mpr("No path found!");
#endif
mon->travel_target = MTRAV_UNREACHABLE;
// Pass information on to nearby monsters.
_mark_neighbours_target_unreachable(mon);
}
}
else
{
#ifdef DEBUG_PATHFIND
mpr("No path found!");
#endif
mon->travel_target = MTRAV_UNREACHABLE;
// Pass information on to nearby monsters.
_mark_neighbours_target_unreachable(mon);
}
}
}
// If the level exit is unreachable, find a new one.
if (mon->travel_target == MTRAV_UNREACHABLE)
{
e[e_index].unreachable = true;
mon->travel_target = MTRAV_NONE;
}
// If the monster is leaving the level via a stair or
// submersion, and has reached its goal, handle it here.
if ((mon->travel_target == MTRAV_STAIR
|| mon->travel_target == MTRAV_SUBMERSIBLE)
&& mon->x == e[e_index].target.x
&& mon->y == e[e_index].target.y)
{
make_mons_leave_level(mon);
return;
}
// Greatly lowered chances if the monster is fleeing or leaving the
// level.
if ((mons_is_fleeing(monster) || mons_is_leaving(monster))
// Greatly lowered chances if the monster is fleeing or pacified and
// leaving the level.
if ((mons_is_fleeing(monster) || mons_is_pacified(monster))
// If the monster is leaving the level via a trap, and is
// about to reach its goal, handle it here.
if (mons_is_leaving(monster)
&& monster->travel_target == MTRAV_TRAP
// If a pacified monster is leaving the level via a trap,
// and is about to reach its goal, handle it here.
if (mons_is_pacified(monster)
MTRAV_UNREACHABLE, // Not travelling because target is unreachable.
MTRAV_STAIR, // Travelling to reach a stair.
MTRAV_TRAP, // Travelling to reach a trap.
MTRAV_SUBMERSIBLE // Travelling to reach a submersible place.
MTRAV_UNREACHABLE // Not travelling because target is unreachable.