static methods to hopefully make the code more readable. Change berserking monster foe check to use a random order when searching the neighbour grids, so the upper left monsters aren't always prefered.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7426 c06c8d41-db1a-0410-9941-cceddc491573
HFZQADL3R7ITWM3VPW5G3NCB2AHRMAMKYZOI3STW5LWUCTV4FFFQC BLN5LDH5NRRJPBY77A36Q4THEY75N42MVCJMZRUZ2D5YSXTDL4HQC TJN537N2F5J7JWBCT2Z4VSTNXIMFCMEXTKTY7N2UCXIVUUQ3XJBQC WP5VP57D5BWKDAS7AA224OV2RX4O4BPTI2BLY7TS3T2O2PLUGXCQC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC 22ORIULMB2NHLFZNJFK2AF275Q6XBKOBE4ZRMOADY64VK5FAUUSQC YKVVFNKT2M5WG2KBURRTOJG23BJVI6WUBP5JOGYPHQBS4RNGFGWQC NWUWP5QCMJ7ZZMLCVB74PW7HDEFB6ICEQHNDHCGG7UWDQNNLGVMQC 2RMAZBQKZQX7OCQ3AFHNJUKU34A33R7O4UAWGAXMPONLYJI5TEXAC 5CRNBCK3AH6UGZN4R5MZ47UCVYYA3CKFXYPKEPZWRTBJ5PIGDB6AC F4FAPEZ5P5CPHZIHUSRYULB3LY4LOJCUC7DZAYVL77LFFBUBCUNAC TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC NV34PXZWSDIIPPJ3HHQIHB4M5UV66QIHOCUEHCSAACMBM765GX4QC CK7CT5TUFUL2AQY7FUHB5JI3FC2KSPWUWHXC6VEUJJ7G4OWUQFTAC G5G4JTXF6JP3GN7ESZTDLEDNJMTLCCE6BCDBORNAEBOUO5WYHAPQC 25EX6COTFUVEIGQMCJ47FDSEKASVVO74LPJ4ZS66ZYUYXD5G3N3QC SPWOUV6ZNHLBSAX455ACJDBEJYVFHGO4H76L4NPAE5DF6BEAK34QC SXUKGEXMGRRN6UO2GJW4HSVU5TSUNUHIHBMMF7CAG7QMLKZYWTKQC 5FMXUX2ZFIF6NQZCS54W7ZOCVSH7XR6UIMQ5FW2UZLEN4EWP5PSAC EHP6PYCIPYQ3KF4JFGBTZXEUQHN3FVAH4NUWEOWDDNKGPYVOTOJQC JFDTUUUT6AKIGPBKGYFC7HZKGQUZOMG7EUWU4QYKSDVXXPQBBFHAC LH4OYDEWEON5QNUCM74R7MNBJDP7O4XRETY74ZMYSXUXYQV427PAC 2TZT4GURBCNHSVOXO5ZMN7XEIO3K4GWJCDPVSYUCMVZ6UFDL4DIQC SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC JBZ7NU4BB5PGQWCOSZHD5OQUHQIVOD4XGJLSJQ7BUGQEGPRTVGZQC FWLLPRIZDBJVQ336TPOLYAFT6WYGAFC52OFIOTRN2YQPFZ3PQVRQC IPCURZEWW7HBUKIBNAHSPTYD2HVABST6T5VRVLNIUPYGSFYJLPDAC QMN4QZWL4LOQMJ7A56O5WXH6J5TBLNA63XWIL34DNU7J3FVQI2UQC SCXDRLT2W436HM4WX4UZRC5M3XNSA65V7XR7AGHEOTSKBWEHUREAC JKEZHDWFNHKMDJQ36ACKV3H64V5B2XAN5XOC6XVR362HY5SAWA4AC WQCIUOHBMPTI4JOCEK2YDM364Q5RAVK5H6TBRNNUXOBUZ365YM7AC T6RHDGQQWMHGQTTDXLXIJZUQ5MSGI4R6BNISTE7WV73BABJHK2YQC EMOBSWJHHB4V6WVMZL7JCF2V3KZN454Z6NS346OKFPMBNO24EJDQC 5XQBKAEMOIALDL7ERCO5WVBGC2YLZPDJPTCVWHLYJSAYQOTOMORAC J2U2RWUFKGHXSLYE7CRQTOFUCXLYLLRZGM6TU2BUQ33MZMDFA6VQC GDTMDVSG3IGKIEWC5MGJJHRRMKMJY7H2AHBRUXTJ4ADI4RPXL5WQC P5TRGRH7XMQSPCZKM5IEEO34TY6WMLGHHX7BU6Y453JFRXLUR2VQC M6IHSU5JWCTOTUSPCVVHMAQ4XJDGQJOLZTTN5BGKEOS4B6Z7IOWAC LTX72QGIPNUGWQN5ULPOMFCOPZTK7472DQY4AYX5WM3WHSUVXI5QC NUYXKJP5YXHRDUQW5QW7UC3D5U3VPANIOZAOHFCPWMSRYGMA3GCAC BKQIVRLP3ZWFWOZAFACQPXCIJLVA3BLPZJ56PK67D4VT3NT6RBIAC 2E4RV454MTTCKYLKMSHEEAFPNAFVUXXPBZV3XP6V7QMF4BBWE7TAC KAOE5HB3THUKVGFZRO5EZESHEB3Q34WUO5DFMLWIKOBF47LZTIYAC GXXYPBFEWKRZQ6OBGYNS2EXZN52NGNV3UU3WM6S5R74CMJBAKGTAC 6TEISZD7HYSSL24EOKIBNURU66KGSQX7B7SNAHBP4DQSAOTGH2MQC WZTIVJJVK7CAHU5D2IYPH7TWGTLBBYPJZJYPGWKCDGM3JQ6Z6VKAC LJK4ZQATLSB4MKZG3ARZX5V6RFGTN3NLCN6GTCUGJQKU26SOXMUAC 23S5SPIJC5VOGKB5RQ3VEEXPUERPYT6WIR54FUSCRENQNGDHUF7AC for (int x = 0; x < GXM; ++x){coord_def p(x,y);if (in_bounds(p)){const dungeon_feature_type gridc = grd(p);
if (!in_bounds(*ri))continue;const dungeon_feature_type gridc = grd(*ri);
// Teleportation and shaft traps.const trap_type tt = get_trap_type(p);if (tt == TRAP_TELEPORT || tt == TRAP_SHAFT)e.push_back(level_exit(p, false));}}
// Teleportation and shaft traps.const trap_type tt = get_trap_type(*ri);if (tt == TRAP_TELEPORT || tt == TRAP_SHAFT)e.push_back(level_exit(*ri, false));
static void _set_no_path_found(monsters *mon){#ifdef DEBUG_PATHFINDmpr("No path found!");#endifmon->travel_target = MTRAV_UNREACHABLE;// Pass information on to nearby monsters._mark_neighbours_target_unreachable(mon);}// The monster is trying to get to the player (MHITYOU).// Check whether there's an unobstructed path to the player (in sight!),// either by using an existing travel_path or calculating a new one.// Returns true if no further handling necessary, else false.static bool _try_pathfind(monsters *mon, const dungeon_feature_type can_move,bool potentially_blocking){// Just because we can *see* the player, that doesn't mean// we can actually get there. To find about that, we first// check for transparent walls. If there are transparent// walls in the way we'll need pathfinding, no matter what.// (Though monsters with a los attack don't need to get any// closer to hurt the player.)// If no walls are detected, there could still be a river// or a pool of lava in the way. So we check whether there// is water or lava in LoS (boolean) and if so, try to find// a way around it. It's possible that the player can see// lava but it actually has no influence on the monster's// movement (because it's lying in the opposite direction)// but if so, we'll find that out during path finding.// In another attempt of optimization, don't bother with// path finding if the monster in question has no trouble// travelling through water or flying across lava.// Also, if no path is found (too far away, perhaps) set a// flag, so we don't directly calculate the whole thing again// next turn, and even extend that flag to neighbouring// monsters of similar movement restrictions.// Smart monsters that can fire through walls won't use// pathfinding, and it's also not necessary if the monster// is already adjacent to you.if (potentially_blocking && mons_intel(mon) >= I_NORMAL&& !mons_friendly(mon) && mons_has_los_ability(mon->type)|| grid_distance(mon->pos(), you.pos()) == 1){potentially_blocking = false;}else{// If we don't already know whether there's water or lava// in LoS of the player, find out now.if (you.lava_in_sight == -1 || you.water_in_sight == -1)_check_lava_water_in_sight();// 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) < I_NORMAL|| mons_friendly(mon)|| !mons_has_ranged_spell(mon) && !mons_has_ranged_attack(mon))){const habitat_type habit = mons_primary_habitat(mon);if (you.lava_in_sight > 0 && habit != HT_LAVA|| you.water_in_sight > 0 && habit != HT_WATER&& can_move != DNGN_DEEP_WATER){potentially_blocking = true;}}}if (!potentially_blocking|| grid_see_grid(mon->pos(), you.pos(), can_move)){// The player is easily reachable.// Clear travel path and target, if necessary.if (mon->travel_target != MTRAV_PATROL&& mon->travel_target != MTRAV_NONE){if (mon->is_travelling())mon->travel_path.clear();mon->travel_target = MTRAV_NONE;}return (false);}
// Even if the target has been to "unreachable" (the monster already tried,// and failed, to find a path) there's a chance of trying again.if (mon->travel_target != MTRAV_UNREACHABLE || one_chance_in(12)){#ifdef DEBUG_PATHFINDmprf("%s: Player out of reach! What now?",mon->name(DESC_PLAIN).c_str());#endif// If we're already on our way, do nothing.if (mon->is_travelling() && mon->travel_target == MTRAV_PLAYER){const int len = mon->travel_path.size();const coord_def targ = mon->travel_path[len - 1];// Current target still valid?if (grid_see_grid(targ, you.pos(), can_move)){// Did we reach the target?if (mon->pos() == mon->travel_path[0]){// Get next waypoint.mon->travel_path.erase( mon->travel_path.begin() );if (!mon->travel_path.empty()){mon->target = mon->travel_path[0];return (true);}}else if (grid_see_grid(mon->pos(), mon->travel_path[0],can_move)){mon->target = mon->travel_path[0];return (true);}}}// Use pathfinding to find a (new) path to the player.const int dist = grid_distance(mon->pos(), you.pos());#ifdef DEBUG_PATHFINDmprf("Need to calculate a path... (dist = %d)", dist);#endifconst bool native = mons_is_native_in_branch(mon);int range = 0;switch (mons_intel(mon)){case I_PLANT:range = 2;break;case I_INSECT:range = 4;break;case I_ANIMAL:range = 5;break;case I_NORMAL:range = LOS_RADIUS;break;default:// Highly intelligent monsters can find their way// anywhere. (range == 0 means no restriction.)break;}if (range){if (native)range += 3;else if (mons_class_flag(mon->type, M_BLOOD_SCENT))range++;}if (range > 0 && dist > range){mon->travel_target = MTRAV_UNREACHABLE;#ifdef DEBUG_PATHFINDmprf("Distance too great, don't attempt pathfinding! (%s)",mon->name(DESC_PLAIN).c_str());#endifreturn (false);}#ifdef DEBUG_PATHFINDmprf("Need a path for %s from (%d, %d) to (%d, %d), max. dist = %d",mon->name(DESC_PLAIN).c_str(), mon->pos(), you.pos(), range);#endifmonster_pathfind mp;if (range > 0)mp.set_range(range);if (mp.init_pathfind(mon, you.pos())){mon->travel_path = mp.calc_waypoints();if (!mon->travel_path.empty()){// Okay then, we found a path. Let's use it!mon->target = mon->travel_path[0];mon->travel_target = MTRAV_PLAYER;return (true);}else_set_no_path_found(mon);}else_set_no_path_found(mon);}// We didn't find a path.return (false);}// Returns true if a monster left the level.static bool _pacified_leave_level(monsters *mon, std::vector<level_exit> e,int e_index){// If a pacified monster is leaving the level, and has reached its// goal, handle it here.// Likewise, if a pacified monster is far enough away from the// player, make it leave the level.if (e_index != -1 && mon->pos() == e[e_index].target|| grid_distance(mon->pos(), you.pos()) >= LOS_RADIUS * 4){make_mons_leave_level(mon);return (true);}return (false);}// Returns true if further handling neeeded.static bool _handle_monster_travelling(monsters *mon,const dungeon_feature_type can_move){#ifdef DEBUG_PATHFINDmprf("Monster %s reached target (%d, %d)",mon->name(DESC_PLAIN).c_str(), mon->target_x, mon->target_y);#endif// Hey, we reached our first waypoint!if (mon->pos() == mon->travel_path[0]){#ifdef DEBUG_PATHFINDmpr("Arrived at first waypoint.");#endifmon->travel_path.erase( mon->travel_path.begin() );if (mon->travel_path.empty()){#ifdef DEBUG_PATHFINDmpr("We reached the end of our path: stop travelling.");#endifmon->travel_target = MTRAV_NONE;return (true);}else{mon->target = mon->travel_path[0];#ifdef DEBUG_PATHFINDmprf("Next waypoint: (%d, %d)", mon->target.x, mon->target.y);#endifreturn (false);}}// Can we still see our next waypoint?if (!grid_see_grid(mon->pos(), mon->travel_path[0], can_move)){#ifdef DEBUG_PATHFINDmpr("Can't see waypoint grid.");#endif// Apparently we got sidetracked a bit.// Check the waypoints vector backwards and pick the first waypoint// we can see.// XXX: Note that this might still not be the best thing to do// since another path might be even *closer* to our actual target now.// Not by much, though, since the original path was optimal (A*) and// the distance between the waypoints is rather small.int erase = -1; // Erase how many waypoints?const int size = mon->travel_path.size();for (int i = size - 1; i >= 0; --i){if (grid_see_grid(mon->pos(), mon->travel_path[i], can_move)){mon->target = mon->travel_path[i];erase = i;break;}}if (erase > 0){#ifdef DEBUG_PATHFINDmprf("Need to erase %d of %d waypoints.",erase, size);#endif// Erase all waypoints that came earlier:// we don't need them anymore.while (0 < erase--)mon->travel_path.erase( mon->travel_path.begin() );}else{// We can't reach our old path from our current// position, so calculate a new path instead.monster_pathfind mp;// The last coordinate in the path vector is our destination.const int len = mon->travel_path.size();if (mp.init_pathfind(mon, mon->travel_path[len-1])){mon->travel_path = mp.calc_waypoints();if (!mon->travel_path.empty()){mon->target = mon->travel_path[0];#ifdef DEBUG_PATHFINDmprf("Next waypoint: (%d, %d)",mon->target.x, mon->target.y);#endif}else{mon->travel_target = MTRAV_NONE;return (true);}}else{// Or just forget about the whole thing.mon->travel_path.clear();mon->travel_target = MTRAV_NONE;return (true);}}}// Else, we can see the next waypoint and are making good progress.// Carry on, then!return (false);}// Returns true if further handling neeeded.static bool _handle_monster_patrolling(monsters *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, depending// on monster intelligence, do one of the following:// * set current position as new patrol point// * forget about patrolling// * head back to patrol pointif (mons_intel(mon) == I_PLANT){// Really stupid monsters forget where they're supposed to be.if (mons_friendly(mon)){// Your ally was told to wait, and wait it will!// (Though possibly not where you told it to.)mon->patrol_point = mon->pos();}else{// Stop patrolling.mon->patrol_point.reset();mon->travel_target = MTRAV_NONE;return (true);}}else{// It's time to head back!// Other than for tracking the player, there's currently// no distinction between smart and stupid monsters when// it comes to travelling back to the patrol point. This// is in part due to the flavour of e.g. bees finding// their way back to the Hive (and patrolling should// really be restricted to cases like this), and for the// other part it's not all that important because we// calculate the path once and then follow it home, and// the player won't ever see the orderly fashion the// bees will trudge along.// What he will see is them swarming back to the Hive// entrance after some time, and that is what matters.monster_pathfind mp;if (mp.init_pathfind(mon, mon->patrol_point)){mon->travel_path = mp.calc_waypoints();if (!mon->travel_path.empty()){mon->target = mon->travel_path[0];mon->travel_target = MTRAV_PATROL;}else{// We're so close we don't even need a path.mon->target = mon->patrol_point;}}else{// Stop patrolling.mon->patrol_point.reset();mon->travel_target = MTRAV_NONE;return (true);}}}else{#ifdef DEBUG_PATHFINDmprf("Monster %s (pp: %d, %d) is now patrolling to (%d, %d)",mon->name(DESC_PLAIN).c_str(),mon->patrol_point.x, mon->patrol_point.y,mon->target_x, mon->target_y);#endif}return (false);}
// Just because we can *see* the player, that doesn't mean// we can actually get there. To find about that, we first// check for transparent walls. If there are transparent// walls in the way we'll need pathfinding, no matter what.// (Though monsters with a los attack don't need to get any// closer to hurt the player.)// If no walls are detected, there could still be a river// or a pool of lava in the way. So we check whether there// is water or lava in LoS (boolean) and if so, try to find// a way around it. It's possible that the player can see// lava but it actually has no influence on the monster's// movement (because it's lying in the opposite direction)// but if so, we'll find that out during path finding.// In another attempt of optimization, don't bother with// path finding if the monster in question has no trouble// travelling through water or flying across lava.// Also, if no path is found (too far away, perhaps) set a// flag, so we don't directly calculate the whole thing again// next turn, and even extend that flag to neighbouring// monsters of similar movement restrictions.bool potentially_blocking = trans_wall_block;
if (_try_pathfind(mon, can_move, trans_wall_block))break;
// Smart monsters that can fire through walls won't use// pathfinding, and it's also not necessary if the monster// is already adjacent to you.if (potentially_blocking && mons_intel(mon) >= I_NORMAL&& mons_has_los_ability(mon->type)|| grid_distance(mon->pos(), you.pos()) == 1){potentially_blocking = false;}else{// If we don't already know whether there's water or lava// in LoS of the player, find out now.if (you.lava_in_sight == -1 || you.water_in_sight == -1)_check_lava_water_in_sight();// 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) < I_NORMAL|| !mons_has_ranged_spell(mon)&& !mons_has_ranged_attack(mon))){const habitat_type habit = mons_primary_habitat(mon);if (you.lava_in_sight > 0 && habit != HT_LAVA|| you.water_in_sight > 0 && habit != HT_WATER&& can_move != DNGN_DEEP_WATER){potentially_blocking = true;}}}if (!potentially_blocking|| grid_see_grid(mon->pos(), you.pos(),can_move)){if (mon->travel_target != MTRAV_PATROL&& mon->travel_target != MTRAV_NONE){if (mon->is_travelling())mon->travel_path.clear();mon->travel_target = MTRAV_NONE;}}else if (mon->travel_target != MTRAV_UNREACHABLE|| one_chance_in(12)){#ifdef DEBUG_PATHFINDmprf("%s: Player out of reach! What now?",mon->name(DESC_PLAIN).c_str());#endif// If we're already on our way, do nothing.if (mon->is_travelling()&& mon->travel_target == MTRAV_PLAYER){int len = mon->travel_path.size();coord_def targ = mon->travel_path[len - 1];if (grid_see_grid(targ, you.pos(), can_move)){// Current target still valid?if (mon->pos() == mon->travel_path[0]){// Get next waypoint.mon->travel_path.erase(mon->travel_path.begin() );if (!mon->travel_path.empty()){mon->target = mon->travel_path[0];break;}}else if (grid_see_grid(mon->pos(),mon->travel_path[0],can_move)){mon->target = mon->travel_path[0];break;}}}// Use pathfinding to find a (new) path to the player.const int dist = grid_distance(mon->pos(), you.pos());#ifdef DEBUG_PATHFINDmprf("Need to calculate a path... (dist = %d)", dist);#endifconst bool native = mons_is_native_in_branch(mon);int range = 0;switch (mons_intel(mon)){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){if (native)range += 3;else if (mons_class_flag(mon->type, M_BLOOD_SCENT))range++;}if (range > 0 && dist > range){mon->travel_target = MTRAV_UNREACHABLE;#ifdef DEBUG_PATHFINDmprf("Distance too great, don't attempt pathfinding! (%s)",mon->name(DESC_PLAIN).c_str());#endif}else{#ifdef DEBUG_PATHFINDmprf("Need a path for %s from (%d, %d) to (%d, %d), ""max. dist = %d",mon->name(DESC_PLAIN).c_str(), mon->pos(),you.pos(), range);#endifmonster_pathfind mp;if (range > 0)mp.set_range(range);if (mp.init_pathfind(mon, you.pos())){mon->travel_path = mp.calc_waypoints();if (!mon->travel_path.empty()){// Okay then, we found a path. Let's use it!mon->target = mon->travel_path[0];mon->travel_target = MTRAV_PLAYER;break;}else{#ifdef DEBUG_PATHFINDmpr("No path found!");#endifmon->travel_target = MTRAV_UNREACHABLE;// Pass information on to nearby monsters._mark_neighbours_target_unreachable(mon);}}else{#ifdef DEBUG_PATHFINDmpr("No path found!");#endifmon->travel_target = MTRAV_UNREACHABLE;// Pass information on to nearby monsters._mark_neighbours_target_unreachable(mon);}}}
// If a pacified monster is leaving the level, and has// reached its goal, handle it here.if (e_index != -1 && mon->pos() == e[e_index].target){make_mons_leave_level(mon);return;}// If a pacified monster is far enough away from the// player, make it leave the level.if (grid_distance(mon->pos(), you.pos()) >= LOS_RADIUS * 4){make_mons_leave_level(mon);
if (_pacified_leave_level(mon, e, e_index))
//// XXX: This is really dumb wander behaviour... instead of// changing the goal square every turn, better would be to// have the monster store a direction and have the monster// head in that direction for a while, then shift the// direction to the left or right. We're changing this so// wandering monsters at least appear to have some sort of// attention span. -- bwr
{#ifdef DEBUG_PATHFINDmprf("Monster %s reached target (%d, %d)",mon->name(DESC_PLAIN).c_str(),mon->target_x, mon->target_y);#endifneed_target = false;if (mon->pos() == mon->travel_path[0]){#ifdef DEBUG_PATHFINDmpr("Arrived at first waypoint.");#endif// Hey, we reached our first waypoint!mon->travel_path.erase( mon->travel_path.begin() );if (mon->travel_path.empty()){#ifdef DEBUG_PATHFINDmpr("We reached the end of our path: stop ""travelling.");#endifmon->travel_target = MTRAV_NONE;need_target = true;}else{mon->target = mon->travel_path[0];#ifdef DEBUG_PATHFINDmprf("Next waypoint: (%d, %d)",mon->target.x, mon->target.y);#endif}}else if (!grid_see_grid(mon->pos(), mon->travel_path[0],can_move)){#ifdef DEBUG_PATHFINDmpr("Can't see waypoint grid.");#endif// Apparently we got sidetracked a bit.// Check the waypoints vector backwards and pick the// first waypoint we can see.
need_target = _handle_monster_travelling(mon, can_move);
// XXX: Note that this might still not be the best// thing to do since another path might be even// *closer* to our actual target now.// Not by much, though, since the original path was// optimal (A*) and the distance between the waypoints// is rather small.int erase = -1; // Erase how many waypoints?int size = mon->travel_path.size();for (int i = size - 1; i >= 0; --i){if (grid_see_grid(mon->pos(), mon->travel_path[i],can_move)){mon->target = mon->travel_path[i];erase = i;break;}}if (erase > 0){#ifdef DEBUG_PATHFINDmprf("Need to erase %d of %d waypoints.",erase, mon->travel_path.size());#endif// Erase all waypoints that came earlier:// we don't need them anymore.while (0 < erase--){mon->travel_path.erase(mon->travel_path.begin() );}}else{// We can't reach our old path from our current// position, so calculate a new path instead.monster_pathfind mp;// The last coordinate in the path vector is our// destination.int len = mon->travel_path.size();if (mp.init_pathfind(mon, mon->travel_path[len-1])){mon->travel_path = mp.calc_waypoints();if (!mon->travel_path.empty()){mon->target = mon->travel_path[0];#ifdef DEBUG_PATHFINDmprf("Next waypoint: (%d, %d)",mon->target.x, mon->target.y);#endif}else{mon->travel_target = MTRAV_NONE;need_target = true;}}else{// Or just forget about the whole thing.mon->travel_path.clear();mon->travel_target = MTRAV_NONE;need_target = true;}}}// Else, we can see the next waypoint and are making good// progress. Carry on, then!}
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,// do one of the following:// * set current position as new patrol point// * forget about patrolling// * head back to patrol pointif (mons_intel(mon) == I_PLANT){// Really stupid monsters forget where they're// supposed to be.if (mons_friendly(mon)){// Your ally was told to wait, and wait it will!// (Though possibly not where you told it to.)mon->patrol_point = mon->pos();}else{// Stop patrolling.mon->patrol_point.reset();mon->travel_target = MTRAV_NONE;need_target = true;}}else{// It's time to head back!// Other than for tracking the player, there's// currently no distinction between smart and// stupid monsters when it comes to travelling// back to the patrol point. This is in part due// to the flavour in e.g. bees finding their way// back to the Hive (and patrolling should really// be restricted to cases like this), and for the// other part it's not all that important because// we calculate the path once and then follow it// home, and the player won't ever see the// orderly fashion the bees will trudge along.// What he will see is them swarming back to the// Hive entrance after some time, and that is what// matters.monster_pathfind mp;if (mp.init_pathfind(mon, mon->patrol_point)){mon->travel_path = mp.calc_waypoints();if (!mon->travel_path.empty()){mon->target = mon->travel_path[0];mon->travel_target = MTRAV_PATROL;}else{// We're so close we don't even need// a path.mon->target = mon->patrol_point;}}else{// Stop patrolling.mon->patrol_point.reset();mon->travel_target = MTRAV_NONE;need_target = true;}}}else{#ifdef DEBUG_PATHFINDmprf("Monster %s (pp: %d, %d) is now patrolling to (%d, %d)",mon->name(DESC_PLAIN).c_str(),mon->patrol_point.x, mon->patrol_point.y,mon->target_x, mon->target_y);#endif}}
// XXX: This is really dumb wander behaviour... instead of// changing the goal square every turn, better would be to// have the monster store a direction and have the monster// head in that direction for a while, then shift the// direction to the left or right. We're changing this so// wandering monsters at least appear to have some sort of// attention span. -- bwr
const int mx = mon->pos().x;const int my = mon->pos().y;
std::vector<coord_def> d;d.push_back(coord_def(-1,-1));d.push_back(coord_def( 0,-1));d.push_back(coord_def( 1,-1));d.push_back(coord_def(-1, 0));d.push_back(coord_def( 1, 0));d.push_back(coord_def(-1, 1));d.push_back(coord_def( 0, 1));d.push_back(coord_def( 1, 1));
{for (int x = mx - k; x <= mx + k; ++x)if (_mons_check_set_foe(mon, coord_def(x, my - k), friendly, neutral)|| _mons_check_set_foe(mon, coord_def(x, my + k), friendly, neutral)){
for (unsigned int i = 0; i < d.size(); i++){const coord_def p = mon->pos() + coord_def(k*d[i].x, k*d[i].y);if (_mons_check_set_foe(mon, p, friendly, neutral))
}for (int y = my - k + 1; y < my + k; ++y)if (_mons_check_set_foe(mon, coord_def(mx - k, y), friendly, neutral)|| _mons_check_set_foe(mon, coord_def(mx + k, y), friendly, neutral)){return;}}
}
if (walls > 0){// Since when do transparent walls block sound? (jpeg)simple_monster_message(monster, " appears to sing, but you ""can't hear her.");break;}else if (player_monster_visible(monster))
if (player_monster_visible(monster))