Use cell_is_solid where appropriate.
[crawl:crawl.git] / crawl-ref / source / mon-behv.cc
1 /**
2  * @file
3  * @brief Monster behaviour functions.
4 **/
5
6 #include "AppHdr.h"
7 #include "mon-behv.h"
8
9 #include "externs.h"
10
11 #include "abl-show.h"
12 #include "act-iter.h"
13 #include "areas.h"
14 #include "coord.h"
15 #include "coordit.h"
16 #include "database.h"
17 #include "dungeon.h"
18 #include "env.h"
19 #include "fprop.h"
20 #include "exclude.h"
21 #include "itemprop.h"
22 #include "losglobal.h"
23 #include "macro.h"
24 #include "mon-act.h"
25 #include "mon-death.h"
26 #include "mon-movetarget.h"
27 #include "mon-pathfind.h"
28 #include "mon-speak.h"
29 #include "mon-stuff.h"
30 #include "ouch.h"
31 #include "random.h"
32 #include "religion.h"
33 #include "spl-summoning.h"
34 #include "state.h"
35 #include "terrain.h"
36 #include "traps.h"
37 #include "hints.h"
38 #include "view.h"
39 #include "shout.h"
40
41 static void _set_nearest_monster_foe(monster* mons);
42
43 static void _guess_invis_foe_pos(monster* mon)
44 {
45     const actor* foe          = mon->get_foe();
46     const int    guess_radius = mons_sense_invis(mon) ? 3 : 2;
47
48     vector<coord_def> possibilities;
49
50     // NOTE: This depends on ignoring clouds, so that cells hidden by
51     // opaque clouds are included as a possibility for the foe's location.
52     los_def los(mon->pos(), opc_fullyopaque, circle_def(guess_radius, C_ROUND));
53     los.update();
54     for (radius_iterator ri(&los); ri; ++ri)
55     {
56         if (foe->is_habitable(*ri))
57             possibilities.push_back(*ri);
58     }
59
60     if (!possibilities.empty())
61         mon->target = possibilities[random2(possibilities.size())];
62     else
63         mon->target = dgn_random_point_from(mon->pos(), guess_radius);
64 }
65
66 static void _mon_check_foe_invalid(monster* mon)
67 {
68     // Assume a spectral weapon has a valid target
69     // Ideally this is not outside special cased like this
70     if (mon->type == MONS_SPECTRAL_WEAPON)
71         return;
72
73     if (mon->foe != MHITNOT && mon->foe != MHITYOU)
74     {
75         if (actor *foe = mon->get_foe())
76         {
77             const monster* foe_mons = foe->as_monster();
78             if (foe_mons->alive() && summon_can_attack(mon, foe)
79                 && (mon->friendly() != foe_mons->friendly()
80                     || mon->neutral() != foe_mons->neutral()))
81             {
82                 return;
83             }
84         }
85
86         mon->foe = MHITNOT;
87     }
88 }
89
90 static bool _mon_tries_regain_los(monster* mon)
91 {
92     // Only intelligent monsters with ranged attack will try to regain LOS.
93     if (mons_intel(mon) < I_NORMAL || !mons_has_ranged_attack(mon))
94         return false;
95
96     // Any special case should go here.
97     if (mons_class_flag(mon->type, M_FIGHTER)
98         && !(mon->type == MONS_CENTAUR_WARRIOR)
99         && !(mon->type == MONS_YAKTAUR_CAPTAIN))
100     {
101         return false;
102     }
103
104     // Randomize it a bit to make it less predictable.
105     return (mons_intel(mon) == I_NORMAL && !one_chance_in(10)
106             || mons_intel(mon) == I_HIGH && !one_chance_in(20));
107 }
108
109 // Monster tries to get into a firing position. Among the cells which have
110 // a line of fire to the target, we choose the closest one to regain LOS as
111 // fast as possible. If several cells are eligible, we choose the one closest
112 // to ideal_range (too far = easier to escape, too close = easier to ambush).
113 static void _set_firing_pos(monster* mon, coord_def target)
114 {
115     const int ideal_range = LOS_RADIUS / 2;
116     const int current_distance = mon->pos().distance_from(target);
117
118     // We don't consider getting farther away unless already very close.
119     const int max_range = max(ideal_range, current_distance);
120
121     int best_distance = INT_MAX;
122     int best_distance_to_ideal_range = INT_MAX;
123     coord_def best_pos(0, 0);
124
125     const los_base *los = mon->get_los();
126     for (distance_iterator di(mon->pos(), true, true, LOS_RADIUS);
127          di; ++di)
128     {
129         const coord_def p(*di);
130         const int range = p.distance_from(target);
131
132         if (!los->see_cell(*di))
133             continue;
134
135         if (!in_bounds(p) || range > max_range
136             || !cell_see_cell(p, target, LOS_NO_TRANS)
137             || !mon_can_move_to_pos(mon, p - mon->pos()))
138         {
139             continue;
140         }
141
142         const int distance = p.distance_from(mon->pos());
143
144         if (distance < best_distance
145             || distance == best_distance
146                && abs(range - ideal_range) < best_distance_to_ideal_range)
147         {
148             best_pos = p;
149             best_distance = distance;
150             best_distance_to_ideal_range = abs(range - ideal_range);
151         }
152     }
153
154     mon->firing_pos = best_pos;
155 }
156
157 struct dist2_sorter
158 {
159     coord_def pos;
160     bool operator()(const coord_def a, const coord_def b)
161     {
162         return distance2(a, pos) < distance2(b, pos);
163     }
164 };
165
166 static bool _can_traverse_unseen(const monster* mon, const coord_def& target)
167 {
168     if (mon->pos() == target)
169         return true;
170
171     ray_def ray;
172     if (!find_ray(mon->pos(), target, ray, opc_immob))
173         return false;
174
175     while (ray.pos() != target && ray.advance())
176         if (!mon_can_move_to_pos(mon, ray.pos() - mon->pos()))
177             return false;
178
179     return true;
180 }
181
182 // Attempt to find the furthest position from a given target which still has
183 // line of sight to it, and which the monster can move to (without pathfinding)
184 static coord_def _furthest_aim_spot(monster* mon, coord_def target)
185 {
186     int best_distance = 0;
187     coord_def best_pos(0, 0);
188
189     const los_base *los = mon->get_los();
190     for (distance_iterator di(mon->pos(), false, false, LOS_RADIUS);
191          di; ++di)
192     {
193         const coord_def p(*di);
194         const int range = p.distance_from(target);
195
196         if (!los->see_cell(*di))
197             continue;
198
199         if (!in_bounds(p) || range > LOS_RADIUS - 1
200             || !cell_see_cell(p, target, LOS_NO_TRANS)
201             || !mon_can_move_to_pos(mon, p - mon->pos(), true))
202         {
203             continue;
204         }
205
206         const int distance = p.distance_from(target);
207         if (distance > best_distance)
208         {
209             if (_can_traverse_unseen(mon, p))
210             {
211                 best_pos = p;
212                 best_distance = distance;
213             }
214         }
215     }
216
217     return best_pos;
218 }
219
220 // Tries to find and set an optimal spot for the curse skull to lurk, just
221 // outside player's line of sight. We consider this to be the spot the furthest
222 // from the player which still has line of sight to where the player will move
223 // if they are approaching us. (This keeps it from lurking immediately around
224 // corners, where the player can enter melee range of it the first turn it comes
225 // into sight)
226 //
227 // The answer given is not always strictly optimal, since no actual pathfinding
228 // is done, and sometimes the best lurking position crosses spots visible to
229 // the player unless a more circuitous route is taken, but generally it is
230 // pretty good, and eliminates the most obvious cases of players luring them
231 // into easy kill.
232 static void _set_curse_skull_lurk_pos(monster* mon)
233 {
234     // If we're already moving somewhere that we can actually reach, don't
235     // search for a new spot.
236     if (!mon->firing_pos.origin() && _can_traverse_unseen(mon, mon->firing_pos))
237         return;
238
239     // Examine spots adjacent to our target, starting with those closest to us
240     vector<coord_def> spots;
241     for (adjacent_iterator ai(you.pos()); ai; ++ai)
242     {
243         if (!cell_is_solid(*ai) || feat_is_door(grd(*ai)))
244             spots.push_back(*ai);
245     }
246
247     dist2_sorter sorter = {mon->pos()};
248     sort(spots.begin(), spots.end(), sorter);
249
250     coord_def lurk_pos(0, 0);
251     for (unsigned int i = 0; i < spots.size(); ++i)
252     {
253         lurk_pos = _furthest_aim_spot(mon, spots[i]);
254
255         // Consider the first position found to be good enough
256         if (!lurk_pos.origin())
257         {
258             mon->firing_pos = lurk_pos;
259             return;
260         }
261     }
262 }
263
264 static bool _stabber_keep_distance(const monster* mon, const actor* foe)
265 {
266     return (mons_class_flag(mon->type, M_STABBER)
267             && !mon->berserk_or_insane()
268             && (mons_has_incapacitating_ranged_attack(mon, foe)
269                 || mons_has_incapacitating_spell(mon, foe))
270             && !foe->incapacitated()
271             && !adjacent(mon->pos(), foe->pos())
272             && !mons_aligned(mon, foe));
273 }
274
275 //---------------------------------------------------------------
276 //
277 // handle_behaviour
278 //
279 // 1. Evaluates current AI state
280 // 2. Sets monster target x,y based on current foe
281 //
282 // XXX: Monsters of I_NORMAL or above should select a new target
283 // if their current target is another monster which is sitting in
284 // a wall and is immune to most attacks while in a wall, unless
285 // the monster has a spell or special/nearby ability which isn't
286 // affected by the wall.
287 //---------------------------------------------------------------
288 void handle_behaviour(monster* mon)
289 {
290     // Test spawners should always be BEH_SEEK against a foe, since
291     // their only purpose is to spew out monsters for testing
292     // purposes.
293     if (mon->type == MONS_TEST_SPAWNER)
294     {
295         for (monster_iterator mi; mi; ++mi)
296         {
297             if (mon->attitude != mi->attitude)
298             {
299                 mon->foe       = mi->mindex();
300                 mon->target    = mi->pos();
301                 mon->behaviour = BEH_SEEK;
302                 return;
303             }
304         }
305     }
306
307     bool changed = true;
308     bool isFriendly = mon->friendly();
309     bool isNeutral  = mon->neutral();
310     bool wontAttack = mon->wont_attack() && !mon->has_ench(ENCH_INSANE);
311
312     // Whether the player position is in LOS of the monster.
313     bool proxPlayer = !crawl_state.game_is_arena() && mon->see_cell(you.pos());
314
315     // If set, pretend the player isn't there, but only for hostile monsters.
316     if (proxPlayer && crawl_state.disables[DIS_MON_SIGHT] && !mon->wont_attack())
317         proxPlayer = false;
318
319     bool proxFoe;
320     bool isHealthy  = (mon->hit_points > mon->max_hit_points / 2);
321     bool isSmart    = (mons_intel(mon) > I_ANIMAL);
322     bool isScared   = mon->has_ench(ENCH_FEAR);
323     bool isPacified = mon->pacified();
324     bool patrolling = mon->is_patrolling();
325     static vector<level_exit> e;
326     static int                e_index = -1;
327
328     // Zotdef rotting
329     if (crawl_state.game_is_zotdef())
330     {
331         if (!isFriendly && !isNeutral && env.orb_pos == mon->pos()
332             && mon->speed)
333         {
334             const int loss = div_rand_round(10, mon->speed);
335             if (loss)
336             {
337                 mpr("Your flesh rots away as the Orb of Zot is desecrated.",
338                     MSGCH_DANGER);
339
340                 // If the rot would reduce us to <= 0 max HP, attribute the
341                 // kill to the monster.
342                 if (loss >= you.hp_max_temp)
343                     ouch(loss, mon->mindex(), KILLED_BY_ROTTING);
344
345                 rot_hp(loss);
346             }
347         }
348     }
349
350     //mprf("AI debug: mon %d behv=%d foe=%d pos=%d %d target=%d %d",
351     //     mon->mindex(), mon->behaviour, mon->foe, mon->pos().x,
352     //     mon->pos().y, mon->target.x, mon->target.y);
353
354     // Check for confusion -- early out.
355     if (mon->has_ench(ENCH_CONFUSION))
356     {
357         set_random_target(mon);
358         return;
359     }
360
361     if (mons_is_fleeing_sanctuary(mon)
362         && mons_is_fleeing(mon)
363         && is_sanctuary(you.pos()))
364     {
365         return;
366     }
367
368     // Make sure monsters are not targetting the player in arena mode.
369     ASSERT(!(crawl_state.game_is_arena() && mon->foe == MHITYOU));
370
371     if (mons_wall_shielded(mon) && cell_is_solid(mon->pos()))
372     {
373         // Monster is safe, so its behaviour can be simplified to fleeing.
374         if (mon->behaviour == BEH_CORNERED || mon->behaviour == BEH_PANIC
375             || isScared)
376         {
377             mon->behaviour = BEH_FLEE;
378         }
379     }
380
381     // Validate current target exists.
382     _mon_check_foe_invalid(mon);
383
384     // The target and foe set here for a spectral weapon should never change
385     if (mon->type == MONS_SPECTRAL_WEAPON)
386     {
387         // Do nothing if we're still being placed
388         if (!mon->summoner)
389             return;
390
391         actor *owner = actor_by_mid(mon->summoner);
392
393         if (!owner || !owner->alive())
394         {
395             end_spectral_weapon(mon, false);
396             return;
397         }
398
399         mon->target = owner->pos();
400         mon->foe = MHITNOT;
401         // Try to move towards any monsters the owner is attacking
402         if (mon->props.exists(SW_TARGET_MID))
403         {
404             actor *atarget = actor_by_mid(mon->props[SW_TARGET_MID].get_int());
405
406             // Only go after the target if it's still near the owner,
407             // and so are we.
408             // The weapon is restricted to a leash range of 2,
409             // and things reachable within that leash range [qoala]
410             const int leash = 2;
411             if (atarget && atarget->alive()
412                 && (grid_distance(owner->pos(), atarget->pos())
413                     <= ((mon->reach_range() == REACH_TWO) ? leash + 2 : leash + 1))
414                 && (grid_distance(owner->pos(), mon->pos()) <= leash))
415             {
416                 mon->target = atarget->pos();
417                 mon->foe = atarget->mindex();
418             }
419             else
420                 reset_spectral_weapon(mon);
421         }
422     }
423
424     // Change proxPlayer depending on invisibility and standing
425     // in shallow water.
426     if (proxPlayer && !you.visible_to(mon))
427     {
428         proxPlayer = false;
429
430         const int intel = mons_intel(mon);
431         // Sometimes, if a player is right next to a monster, they will 'see'.
432         if (grid_distance(you.pos(), mon->pos()) == 1
433             && one_chance_in(3))
434         {
435             proxPlayer = true;
436         }
437
438         // [dshaligram] Very smart monsters have a chance of clueing in to
439         // invisible players in various ways.
440         if (intel == I_NORMAL && one_chance_in(13)
441                  || intel == I_HIGH && one_chance_in(6))
442         {
443             proxPlayer = true;
444         }
445
446         // Ash penance makes monsters very likely to target you through
447         // invisibility, depending on their intelligence.
448         if (player_under_penance(GOD_ASHENZARI) && x_chance_in_y(intel, 7))
449             proxPlayer = true;
450     }
451
452     // Zotdef: immobile allies forget targets that are out of sight
453     if (crawl_state.game_is_zotdef())
454     {
455         if (isFriendly && mon->is_stationary()
456             && (mon->foe != MHITNOT && mon->foe != MHITYOU)
457             && !mon->can_see(&menv[mon->foe]))
458         {
459             mon->foe = MHITYOU;
460             //mprf("%s resetting target (cantSee)",
461             //     mon->name(DESC_THE,true).c_str());
462         }
463     }
464
465     // Set friendly target, if they don't already have one.
466     // Berserking allies ignore your commands!
467     if (isFriendly
468         && (mon->foe == MHITNOT || mon->foe == MHITYOU)
469         && !mon->berserk_or_insane()
470         && mon->behaviour != BEH_WITHDRAW
471         && mon->type != MONS_GIANT_SPORE
472         && mon->type != MONS_BATTLESPHERE
473         && mon->type != MONS_SPECTRAL_WEAPON)
474     {
475         if  (!crawl_state.game_is_zotdef())
476         {
477             if (you.pet_target != MHITNOT)
478                 mon->foe = you.pet_target;
479         }
480         else    // Zotdef only
481         {
482             // Attack pet target if nearby
483             if (you.pet_target != MHITNOT && proxPlayer)
484             {
485                 //mprf("%s setting target (player target)",
486                 //     mon->name(DESC_THE,true).c_str());
487                 mon->foe = you.pet_target;
488             }
489             else
490             {
491                // Zotdef - this is all new, for out-of-sight friendlies to do
492                // something useful.  If no current target, get the closest one.
493                 _set_nearest_monster_foe(mon);
494             }
495         }
496     }
497
498     // Instead, berserkers attack nearest monsters.
499     if (mon->behaviour != BEH_SLEEP
500         && (mon->has_ench(ENCH_INSANE)
501             || ((mon->berserk() || mon->type == MONS_GIANT_SPORE)
502                 && (mon->foe == MHITNOT
503                     || isFriendly && mon->foe == MHITYOU))))
504     {
505         // Intelligent monsters prefer to attack the player,
506         // even when berserking.
507         if (!isFriendly
508             && !mon->has_ench(ENCH_INSANE)
509             && proxPlayer
510             && mons_intel(mon) >= I_NORMAL)
511         {
512             mon->foe = MHITYOU;
513         }
514         else
515             _set_nearest_monster_foe(mon);
516     }
517
518     // Pacified monsters leaving the level prefer not to attack.
519     // Others choose the nearest foe.
520     // XXX: This is currently expensive, so we don't want to do it
521     //      every turn for every monster.
522     if (!isPacified && mon->foe == MHITNOT
523         && mon->behaviour != BEH_SLEEP
524         && (proxPlayer || one_chance_in(3)))
525     {
526         _set_nearest_monster_foe(mon);
527         if (mon->foe == MHITNOT && crawl_state.game_is_zotdef())
528             mon->foe = MHITYOU;
529     }
530
531     // Friendly summons will come back to the player if they go out of sight.
532     // Spectral weapon should keep its target even though it can't attack it
533     if (!summon_can_attack(mon) && mon->type!=MONS_SPECTRAL_WEAPON)
534         mon->target = you.pos();
535
536     // Monsters do not attack themselves. {dlb}
537     if (mon->foe == mon->mindex())
538         mon->foe = MHITNOT;
539
540     // Friendly and good neutral monsters do not attack other friendly
541     // and good neutral monsters.
542     if (mon->foe != MHITNOT && mon->foe != MHITYOU
543         && wontAttack && menv[mon->foe].wont_attack())
544     {
545         mon->foe = MHITNOT;
546     }
547
548     // Neutral monsters prefer not to attack players, or other neutrals.
549     if (isNeutral
550         && !mon->has_ench(ENCH_INSANE)
551         && mon->foe != MHITNOT
552         && (mon->foe == MHITYOU || menv[mon->foe].neutral()))
553     {
554         mon->foe = MHITNOT;
555     }
556
557     // Unfriendly monsters fighting other monsters will usually
558     // target the player, if they're healthy.
559     // Zotdef: 2/3 chance of retargetting changed to 1/4
560     if (!isFriendly && !isNeutral
561         && mon->foe != MHITYOU && mon->foe != MHITNOT
562         && proxPlayer && !mon->berserk_or_insane()
563         && isHealthy
564         && (crawl_state.game_is_zotdef() ? one_chance_in(4)
565                                          : !one_chance_in(3)))
566     {
567         mon->foe = MHITYOU;
568     }
569
570     // Validate current target again.
571     _mon_check_foe_invalid(mon);
572
573     if (mon->has_ench(ENCH_HAUNTING))
574     {
575         actor* targ = mon->get_ench(ENCH_HAUNTING).agent();
576         if (targ && targ->alive())
577         {
578             mon->foe = targ->mindex();
579             mon->target = targ->pos();
580         }
581     }
582
583     while (changed)
584     {
585         actor* afoe = mon->get_foe();
586         proxFoe = afoe && mon->can_see(afoe);
587
588         if (mon->foe == MHITYOU)
589         {
590             // monster::get_foe returns NULL for friendly monsters with
591             // foe == MHITYOU, so make afoe point to the player here.
592             // -cao
593             afoe = &you;
594             proxFoe = proxPlayer;   // Take invis into account.
595         }
596
597         coord_def foepos = coord_def(0,0);
598         if (afoe)
599             foepos = afoe->pos();
600
601         if (crawl_state.game_is_zotdef() && mon->foe == MHITYOU
602             && !mon->wont_attack())
603         {
604             foepos = PLAYER_POS;
605             proxFoe = true;
606         }
607
608         if (mon->pos() == mon->firing_pos)
609             mon->firing_pos.reset();
610
611         // Track changes to state; attitude never changes here.
612         beh_type new_beh       = mon->behaviour;
613         unsigned short new_foe = mon->foe;
614
615         // Take care of monster state changes.
616         switch (mon->behaviour)
617         {
618         case BEH_SLEEP:
619             // default sleep state
620             mon->target = mon->pos();
621             new_foe = MHITNOT;
622             break;
623
624         case BEH_LURK:
625             // Make sure trapdoor spiders are not hiding in plain sight
626             if (mon->type == MONS_TRAPDOOR_SPIDER && !mon->submerged())
627                 mon->add_ench(ENCH_SUBMERGED);
628
629             // Fall through to get a target, but don't change to wandering.
630
631         case BEH_SEEK:
632             // No foe?  Then wander or seek the player.
633             if (mon->foe == MHITNOT)
634             {
635                 if (crawl_state.game_is_arena()
636                     || !proxPlayer && !isFriendly
637                     || isNeutral && !mon->has_ench(ENCH_INSANE)
638                     || patrolling
639                     || mon->type == MONS_GIANT_SPORE)
640                 {
641                     if (mon->behaviour != BEH_LURK)
642                         new_beh = BEH_WANDER;
643                 }
644                 else
645                 {
646                     new_foe = MHITYOU;
647                     mon->target = PLAYER_POS;
648                 }
649                 break;
650             }
651
652             // Foe gone out of LOS?
653             if (!proxFoe
654                 && !(mon->friendly()
655                      && mon->foe == MHITYOU
656                      && mon->is_travelling()
657                      && mon->travel_target == MTRAV_PLAYER))
658             {
659                 // If their foe is marked, the monster always knows exactly
660                 // where they are.
661                 if (mons_foe_is_marked(mon) || mon->has_ench(ENCH_HAUNTING))
662                 {
663                     mon->target = afoe->pos();
664                     try_pathfind(mon);
665                     break;
666                 }
667
668                 // Maybe the foe is just invisible.
669                 if (mon->target.origin() && afoe && mon->near_foe())
670                 {
671                     _guess_invis_foe_pos(mon);
672                     if (mon->target.origin())
673                     {
674                         // Having a seeking mon with a foe who's target is
675                         // (0, 0) can lead to asserts, so lets try to
676                         // avoid that.
677                         _set_nearest_monster_foe(mon);
678                         if (mon->foe == MHITNOT)
679                         {
680                             new_beh = BEH_WANDER;
681                             break;
682                         }
683                         mon->target = mon->get_foe()->pos();
684                     }
685                 }
686
687                 if (mon->travel_target == MTRAV_SIREN)
688                     mon->travel_target = MTRAV_NONE;
689
690                 if (isFriendly && mon->foe != MHITYOU)
691                 {
692                     if (patrolling || crawl_state.game_is_arena())
693                     {
694                         new_foe = MHITNOT;
695                         new_beh = BEH_WANDER;
696                     }
697                     else
698                     {
699                         new_foe = MHITYOU;
700                         mon->target = foepos;
701                     }
702                     break;
703                 }
704
705                 ASSERT(mon->foe != MHITNOT);
706                 if (mon->foe_memory > 0)
707                 {
708                     // If we've arrived at our target x,y
709                     // do a stealth check.  If the foe
710                     // fails, monster will then start
711                     // tracking foe's CURRENT position,
712                     // but only for a few moves (smell and
713                     // intuition only go so far).
714
715                     if (mon->pos() == mon->target
716                         && (!isFriendly || !crawl_state.game_is_zotdef()))
717                     {   // hostiles only in Zotdef
718                         if (mon->foe == MHITYOU)
719                         {
720                             if (crawl_state.game_is_zotdef())
721                                 mon->target = PLAYER_POS;  // infallible tracking in zotdef
722                             else
723                             {
724                                 if (x_chance_in_y(50, you.stealth())
725                                     || you.penance[GOD_ASHENZARI] && coinflip())
726                                 {
727                                     mon->target = you.pos();
728                                 }
729                                 else
730                                     mon->foe_memory = 0;
731                             }
732                         }
733                         else
734                         {
735                             if (coinflip())     // XXX: cheesy!
736                                 mon->target = menv[mon->foe].pos();
737                             else
738                                 mon->foe_memory = 0;
739                         }
740                     }
741                 }
742
743
744                 if (mon->foe_memory <= 0
745                     && !(mon->friendly() && mon->foe == MHITYOU))
746                 {
747                     new_beh = BEH_WANDER;
748                 }
749                 else if ((mon->type == MONS_CURSE_SKULL
750                           && mon->foe == MHITYOU
751                           && grid_distance(mon->pos(), you.pos()) <= LOS_RADIUS))
752                 {
753                     _set_curse_skull_lurk_pos(mon);
754                 }
755                 // If the player walk out of the LOS of a monster with a ranged
756                 // attack, we assume it sees in which direction the player went
757                 // and it tries to find a line of fire instead of following the
758                 // player.
759                 else if (grid_distance(mon->target, you.pos()) == 1
760                          && _mon_tries_regain_los(mon))
761                 {
762                     _set_firing_pos(mon, you.pos());
763                 }
764
765                 if (!isFriendly)
766                     break;
767             }
768
769             ASSERT(proxFoe || isFriendly);
770             ASSERT(mon->foe != MHITNOT);
771
772             // Monster can see foe: set memory in case it loses sight.
773             // Hack: smarter monsters will tend to pursue the player longer.
774             switch (mons_intel(mon))
775             {
776             case I_HIGH:
777                 mon->foe_memory = random_range(700, 1300);
778                 break;
779             case I_NORMAL:
780                 mon->foe_memory = random_range(300, 700);
781                 break;
782             case I_ANIMAL:
783             case I_INSECT:
784             case I_REPTILE:
785                 mon->foe_memory = random_range(250, 550);
786                 break;
787             case I_PLANT:
788                 mon->foe_memory = random_range(100, 300);
789                 break;
790             }
791
792             // Monster can see foe: continue 'tracking'
793             // by updating target x,y.
794             if (mon->foe == MHITYOU)
795             {
796                 // The foe is the player.
797                 if (mons_class_flag(mon->type, M_MAINTAIN_RANGE)
798                     && !mon->berserk_or_insane())
799                 {
800                     if (mon->attitude != ATT_FRIENDLY)
801                         // Get to firing range even if we are close.
802                         _set_firing_pos(mon, you.pos());
803                 }
804                 else if (_stabber_keep_distance(mon, &you))
805                 {
806                     if (mon->pos().distance_from(you.pos()) < 4
807                         && !one_chance_in(7))
808                     {
809                         mon->firing_pos = mon->pos();
810                     }
811                     else
812                         _set_firing_pos(mon, you.pos());
813                 }
814                 else if (!mon->firing_pos.zero()
815                     && mon->see_cell_no_trans(mon->target))
816                 {
817                     // If monster is currently getting into firing position and
818                     // sees the player and can attack him, clear firing_pos.
819                     mon->firing_pos.reset();
820                 }
821
822                 if (mon->type == MONS_SIREN
823                     && you.beheld_by(mon)
824                     && find_siren_water_target(mon))
825                 {
826                     break;
827                 }
828
829                 if (mon->firing_pos.zero() && try_pathfind(mon))
830                     break;
831
832                 // Whew. If we arrived here, path finding didn't yield anything
833                 // (or wasn't even attempted) and we need to set our target
834                 // the traditional way.
835
836                 // Sometimes, your friends will wander a bit.
837                 if (isFriendly && one_chance_in(8)
838                     && mon->foe == MHITYOU && proxFoe)
839                 {
840                     set_random_target(mon);
841                     mon->foe = MHITNOT;
842                     new_beh  = BEH_WANDER;
843                 }
844                 else
845                     mon->target = PLAYER_POS;
846             }
847             else
848             {
849                 // We have a foe but it's not the player.
850                 monster* target = &menv[mon->foe];
851                 mon->target = target->pos();
852
853                 if (mons_class_flag(mon->type, M_MAINTAIN_RANGE)
854                     && !mon->berserk_or_insane())
855                 {
856                     _set_firing_pos(mon, mon->target);
857                 }
858                 else if (target && _stabber_keep_distance(mon, target))
859                 {
860                     if (mon->pos().distance_from(target->pos()) < 4
861                         && !one_chance_in(7))
862                     {
863                         mon->firing_pos = mon->pos();
864                     }
865                     else
866                         _set_firing_pos(mon, target->pos());
867                 }
868
869             }
870
871             break;
872
873         case BEH_WANDER:
874             if (isPacified)
875             {
876                 // If a pacified monster isn't travelling toward
877                 // someplace from which it can leave the level, make it
878                 // start doing so.  If there's no such place, either
879                 // search the level for such a place again, or travel
880                 // randomly.
881                 if (mon->travel_target != MTRAV_PATROL)
882                 {
883                     new_foe = MHITNOT;
884                     mon->travel_path.clear();
885
886                     e_index = mons_find_nearest_level_exit(mon, e);
887
888                     if (e_index == -1 || one_chance_in(20))
889                         e_index = mons_find_nearest_level_exit(mon, e, true);
890
891                     if (e_index != -1)
892                     {
893                         mon->travel_target = MTRAV_PATROL;
894                         patrolling = true;
895                         mon->patrol_point = e[e_index].target;
896                         mon->target = e[e_index].target;
897                     }
898                     else
899                     {
900                         mon->travel_target = MTRAV_NONE;
901                         patrolling = false;
902                         mon->patrol_point.reset();
903                         set_random_target(mon);
904                     }
905                 }
906
907                 if (pacified_leave_level(mon, e, e_index))
908                     return;
909             }
910
911             if (mon->strict_neutral() && mons_is_slime(mon)
912                 && you_worship(GOD_JIYVA))
913             {
914                 set_random_slime_target(mon);
915             }
916
917             // Is our foe in LOS?
918             // Batty monsters don't automatically reseek so that
919             // they'll flitter away, we'll reset them just before
920             // they get movement in handle_monsters() instead. -- bwr
921             if (proxFoe && !mons_is_batty(mon) || mons_foe_is_marked(mon))
922             {
923                 new_beh = BEH_SEEK;
924                 break;
925             }
926
927             // Creatures not currently pursuing another foe are
928             // alerted by a sentinel's mark
929             if (mon->foe == MHITNOT && you.duration[DUR_SENTINEL_MARK]
930                 && (!isFriendly && !isNeutral && !isPacified
931                     || mon->has_ench(ENCH_INSANE)))
932             {
933                 new_foe = MHITYOU;
934                 new_beh = BEH_SEEK;
935                 break;
936             }
937
938             check_wander_target(mon, isPacified);
939
940             // During their wanderings, monsters will eventually relax
941             // their guard (stupid ones will do so faster, smart
942             // monsters have longer memories).  Pacified monsters will
943             // also eventually switch the place from which they want to
944             // leave the level, in case their current choice is blocked.
945             if (!proxFoe && mon->foe != MHITNOT
946                    && one_chance_in(isSmart ? 60 : 20)
947                    && !mons_foe_is_marked(mon)
948                 || isPacified && one_chance_in(isSmart ? 40 : 120))
949             {
950                 new_foe = MHITNOT;
951                 if (mon->is_travelling() && mon->travel_target != MTRAV_PATROL
952                     || isPacified)
953                 {
954 #ifdef DEBUG_PATHFIND
955                     mpr("It's been too long! Stop travelling.");
956 #endif
957                     mon->travel_path.clear();
958                     mon->travel_target = MTRAV_NONE;
959
960                     if (isPacified && e_index != -1)
961                         e[e_index].unreachable = true;
962                 }
963             }
964             break;
965
966         case BEH_RETREAT:
967             // If the target can be reached, there is a chance the monster will
968             // try to attack. The chance is low to prevent the player from
969             // dancing in and out of the water.
970             try_pathfind(mon);
971             if (one_chance_in(10) && !target_is_unreachable(mon)
972                 || mons_can_attack(mon))
973             {
974                 new_beh = BEH_SEEK;
975             }
976             else if (!proxPlayer && one_chance_in(5))
977                 new_beh = BEH_WANDER;
978             else if (proxPlayer)
979                 mon->target = foepos;
980             break;
981
982         case BEH_FLEE:
983             // Check for healed.
984             if (isHealthy && !isScared)
985                 new_beh = BEH_SEEK;
986
987             // Smart monsters flee until they can flee no more...
988             // possible to get a 'CORNERED' event, at which point
989             // we can jump back to WANDER if the foe isn't present.
990
991             if (isFriendly)
992             {
993                 // Special-cased below so that it will flee *towards* you.
994                 if (mon->foe == MHITYOU)
995                     mon->target = you.pos();
996             }
997             else if (mons_wall_shielded(mon) && find_wall_target(mon))
998                 ; // Wall target found.
999             else if (proxFoe)
1000             {
1001                 // Special-cased below so that it will flee *from* the
1002                 // correct position.
1003                 mon->target = foepos;
1004             }
1005             break;
1006
1007         case BEH_CORNERED:
1008             // Plants and nonliving monsters cannot fight back.
1009             if (mon->holiness() == MH_PLANT
1010                 || mon->holiness() == MH_NONLIVING)
1011             {
1012                 break;
1013             }
1014
1015             if (isHealthy)
1016                 new_beh = BEH_SEEK;
1017
1018             // Foe gone out of LOS?
1019             if (!proxFoe)
1020             {
1021                 if ((isFriendly || proxPlayer)
1022                     && (!isNeutral || mon->has_ench(ENCH_INSANE))
1023                     && !patrolling
1024                     && !crawl_state.game_is_arena())
1025                 {
1026                     new_foe = MHITYOU;
1027                 }
1028                 else
1029                     new_beh = BEH_WANDER;
1030             }
1031             else
1032                 mon->target = foepos;
1033             break;
1034
1035         case BEH_WITHDRAW:
1036         {
1037             if (!isFriendly)
1038             {
1039                 new_beh = BEH_WANDER;
1040                 break;
1041             }
1042
1043             bool stop_retreat = false;
1044             // We've approached our next destination, re-evaluate
1045             if (distance2(mon->target, mon->pos()) <= 3)
1046             {
1047                 // Continue on to the rally point
1048                 if (mon->target != mon->patrol_point)
1049                     mon->target = mon->patrol_point;
1050                 // Reached rally point, stop withdrawing
1051                 else
1052                     stop_retreat = true;
1053
1054             }
1055             else if (distance2(mon->pos(), you.pos()) > dist_range(LOS_RADIUS + 2))
1056             {
1057                 // We're too far from the player. Idle around and wait for
1058                 // them to catch up.
1059                 if (!mon->props.exists("idle_point"))
1060                 {
1061                     mon->props["idle_point"] = mon->pos();
1062                     mon->props["idle_deadline"] = you.elapsed_time + 200;
1063                 }
1064
1065                 mon->target = clamp_in_bounds(
1066                                     mon->props["idle_point"].get_coord()
1067                                     + coord_def(random_range(-2, 2),
1068                                                 random_range(-2, 2)));
1069
1070                 if (you.elapsed_time >= mon->props["idle_deadline"].get_int())
1071                     stop_retreat = true;
1072             }
1073             else
1074             {
1075                 // Be more lenient about player distance if a monster is
1076                 // idling (to prevent it from repeatedly resetting idle
1077                 // time if its own wanderings bring it closer to the player)
1078                 if (mon->props.exists("idle_point")
1079                     && distance2(mon->pos(), you.pos()) < dist_range(LOS_RADIUS))
1080                 {
1081                     mon->props.erase("idle_point");
1082                     mon->props.erase("idle_deadline");
1083                     mon->target = mon->patrol_point;
1084                 }
1085
1086                 if (mon->pos() == mon->props["last_pos"].get_coord())
1087                 {
1088                     if (!mon->props.exists("blocked_deadline"))
1089                         mon->props["blocked_deadline"] = you.elapsed_time + 30;
1090
1091                     if (!mon->props.exists("idle_deadline"))
1092                         mon->props["idle_deadline"] = you.elapsed_time + 200;
1093
1094                     if (you.elapsed_time >= mon->props["blocked_deadline"].get_int()
1095                         || you.elapsed_time >= mon->props["idle_deadline"].get_int())
1096                     {
1097                         stop_retreat = true;
1098                     }
1099                 }
1100                 else
1101                 {
1102                     mon->props.erase("blocked_deadline");
1103                     mon->props.erase("idle_deadline");
1104                 }
1105             }
1106
1107             if (stop_retreat)
1108             {
1109                 new_beh = BEH_SEEK;
1110                 new_foe = MHITYOU;
1111                 mon->props.erase("last_pos");
1112                 mon->props.erase("idle_point");
1113                 mon->props.erase("blocked_deadline");
1114                 mon->props.erase("idle_deadline");
1115             }
1116             else
1117                 mon->props["last_pos"] = mon->pos();
1118
1119             break;
1120         }
1121
1122         default:
1123             return;     // uh oh
1124         }
1125
1126         changed = (new_beh != mon->behaviour || new_foe != mon->foe);
1127         mon->behaviour = new_beh;
1128
1129         if (mon->foe != new_foe)
1130             mon->foe_memory = 0;
1131
1132         mon->foe = new_foe;
1133     }
1134
1135     if (mon->travel_target == MTRAV_WALL && cell_is_solid(mon->pos()))
1136     {
1137         if (mon->behaviour == BEH_FLEE)
1138         {
1139             // Monster is safe, so stay put.
1140             mon->target = mon->pos();
1141             mon->foe = MHITNOT;
1142         }
1143     }
1144 }
1145
1146 static bool _mons_check_foe(monster* mon, const coord_def& p,
1147                             bool friendly, bool neutral)
1148 {
1149     // We don't check for the player here because otherwise wandering
1150     // monsters will always attack you.
1151
1152     // -- But why should they always attack monsters? -- 1KB
1153
1154     monster* foe = monster_at(p);
1155     if (foe && foe != mon
1156         && (mon->has_ench(ENCH_INSANE)
1157             || foe->friendly() != friendly
1158             || neutral && !foe->neutral())
1159         && mon->can_see(foe)
1160         && !foe->is_projectile()
1161         && summon_can_attack(mon, p)
1162         && (friendly || !is_sanctuary(p))
1163         && (crawl_state.game_is_zotdef() || !mons_is_firewood(foe)))
1164             // Zotdef allies take out firewood
1165     {
1166         return true;
1167     }
1168
1169     if (mon->has_ench(ENCH_INSANE) && p == you.pos())
1170         return true;
1171
1172     return false;
1173 }
1174
1175 // Choose random nearest monster as a foe.
1176 static void _set_nearest_monster_foe(monster* mon)
1177 {
1178     // These don't look for foes.
1179     if (mon->good_neutral() || mon->strict_neutral()
1180             || mon->behaviour == BEH_WITHDRAW
1181             || mon->type == MONS_BATTLESPHERE
1182             || mon->type == MONS_SPECTRAL_WEAPON
1183             || mon->has_ench(ENCH_HAUNTING))
1184     {
1185         return;
1186     }
1187
1188     const bool friendly = mon->friendly();
1189     const bool neutral  = mon->neutral();
1190
1191     for (int k = 1; k <= LOS_RADIUS; ++k)
1192     {
1193         vector<coord_def> monster_pos;
1194         for (int i = -k; i <= k; ++i)
1195             for (int j = -k; j <= k; (abs(i) == k ? j++ : j += 2*k))
1196             {
1197                 const coord_def p = mon->pos() + coord_def(i, j);
1198                 if (_mons_check_foe(mon, p, friendly, neutral))
1199                     monster_pos.push_back(p);
1200             }
1201         if (monster_pos.empty())
1202             continue;
1203
1204         const coord_def mpos = monster_pos[random2(monster_pos.size())];
1205         if (mpos == you.pos())
1206             mon->foe = MHITYOU;
1207         else
1208             mon->foe = env.mgrid(mpos);
1209         return;
1210     }
1211 }
1212
1213 //-----------------------------------------------------------------
1214 //
1215 // behaviour_event
1216 //
1217 // 1. Change any of: monster state, foe, and attitude
1218 // 2. Call handle_behaviour to re-evaluate AI state and target x, y
1219 //
1220 //-----------------------------------------------------------------
1221 void behaviour_event(monster* mon, mon_event_type event, const actor *src,
1222                      coord_def src_pos, bool allow_shout)
1223 {
1224     if (!mon->alive())
1225         return;
1226
1227     ASSERT(!crawl_state.game_is_arena() || src != &you);
1228     ASSERT_IN_BOUNDS_OR_ORIGIN(src_pos);
1229     if (mons_is_projectile(mon->type))
1230         return; // projectiles have no AI
1231
1232     const beh_type old_behaviour = mon->behaviour;
1233
1234     int fleeThreshold = min(mon->max_hit_points / 4, 20);
1235
1236     bool isSmart          = (mons_intel(mon) > I_ANIMAL);
1237     bool wontAttack       = mon->wont_attack();
1238     bool sourceWontAttack = false;
1239     bool setTarget        = false;
1240     bool breakCharm       = false;
1241     bool was_sleeping     = mon->asleep();
1242     string msg;
1243     int src_idx           = src ? src->mindex() : MHITNOT; // AXE ME
1244
1245     if (src)
1246         sourceWontAttack = src->wont_attack();
1247
1248     if (is_sanctuary(mon->pos()) && mons_is_fleeing_sanctuary(mon))
1249     {
1250         mon->behaviour = BEH_FLEE;
1251         mon->foe       = MHITYOU;
1252         mon->target    = env.sanctuary_pos;
1253         return;
1254     }
1255
1256     switch (event)
1257     {
1258     case ME_DISTURB:
1259         // Assumes disturbed by noise...
1260         if (mon->asleep())
1261         {
1262             mon->behaviour = BEH_WANDER;
1263
1264             if (mons_near(mon))
1265                 remove_auto_exclude(mon, true);
1266         }
1267
1268         // A bit of code to make Projected Noise actually do
1269         // something again.  Basically, dumb monsters and
1270         // monsters who aren't otherwise occupied will at
1271         // least consider the (apparent) source of the noise
1272         // interesting for a moment. -- bwr
1273         if (!isSmart || mon->foe == MHITNOT || mons_is_wandering(mon))
1274         {
1275             if (mon->is_patrolling())
1276                 break;
1277
1278             ASSERT(!src_pos.origin());
1279             mon->target = src_pos;
1280         }
1281         break;
1282
1283     case ME_WHACK:
1284     case ME_ANNOY:
1285         // Orders to withdraw take precedence over interruptions
1286         if (mon->behaviour == BEH_WITHDRAW)
1287             break;
1288
1289         // Will turn monster against <src>, unless they
1290         // are BOTH friendly or good neutral AND stupid,
1291         // or else fleeing anyway.  Hitting someone over
1292         // the head, of course, always triggers this code.
1293         if (event != ME_WHACK
1294             && !mon->has_ench(ENCH_INSANE)
1295             && (wontAttack == sourceWontAttack && mons_intel(mon) <= I_PLANT
1296                 || mons_is_fleeing(mon)
1297                 || mons_class_flag(mon->type, M_FLEEING)
1298                 || mons_is_panicking(mon)))
1299         {
1300             break;
1301         }
1302
1303         // Monster types that you can't gain experience from cannot
1304         // fight back, so don't bother having them do so.  If you
1305         // worship Fedhas, create a ring of friendly plants, and try
1306         // to break out of the ring by killing a plant, you'll get
1307         // a warning prompt and penance only once.  Without the
1308         // hostility check, the plant will remain friendly until it
1309         // dies, and you'll get a warning prompt and penance once
1310         // *per hit*.  This may not be the best way to address the
1311         // issue, though. -cao
1312         if (mons_class_flag(mon->type, M_NO_EXP_GAIN)
1313             && mon->attitude != ATT_FRIENDLY
1314             && mon->attitude != ATT_GOOD_NEUTRAL)
1315         {
1316             return;
1317         }
1318
1319         mon->foe = src_idx;
1320
1321         if (mon->asleep() && mons_near(mon))
1322             remove_auto_exclude(mon, true);
1323
1324         // If the monster can't reach its target and can't attack it
1325         // either, retreat.
1326         try_pathfind(mon);
1327         if (mons_intel(mon) > I_REPTILE && !mons_can_attack(mon)
1328             && target_is_unreachable(mon))
1329         {
1330             mon->behaviour = BEH_RETREAT;
1331         }
1332         else if (!mons_is_cornered(mon) && (mon->hit_points > fleeThreshold))
1333             mon->behaviour = BEH_SEEK;
1334         else if (mon->asleep())
1335             mon->behaviour = BEH_SEEK;
1336
1337         if (src == &you
1338             && !mon->has_ench(ENCH_INSANE)
1339             && mon->type != MONS_BATTLESPHERE
1340             && mon->type != MONS_SPECTRAL_WEAPON)
1341         {
1342             mon->attitude = ATT_HOSTILE;
1343             breakCharm    = true;
1344         }
1345
1346         // XXX: Somewhat hacky, this being here.
1347         if (mons_is_elven_twin(mon))
1348             elven_twins_unpacify(mon);
1349
1350         // Now set target so that monster can whack back (once) at an
1351         // invisible foe.
1352         if (event == ME_WHACK)
1353             setTarget = true;
1354
1355         break;
1356
1357     case ME_ALERT:
1358         // Allow monsters falling asleep while patrolling (can happen if
1359         // they're left alone for a long time) to be woken by this event.
1360         if (mon->friendly() && mon->is_patrolling()
1361             && !mon->asleep())
1362         {
1363             break;
1364         }
1365
1366         // Orders to withdraw take precedence over interruptions
1367         if (mon->behaviour == BEH_WITHDRAW)
1368             break;
1369
1370         // Avoid moving friendly giant spores out of BEH_WANDER.
1371         if (mon->friendly() && mon->type == MONS_GIANT_SPORE)
1372             break;
1373
1374         // [ds] Neutral monsters don't react to your presence.
1375         // XXX: Neutral monsters are a tangled mess of arbitrary logic.
1376         // It's not even clear any more what behaviours are intended for
1377         // neutral monsters and what are merely accidents of the code.
1378         if (mon->neutral() && !mon->has_ench(ENCH_INSANE))
1379         {
1380             if (mon->asleep())
1381                 mon->behaviour = BEH_WANDER;
1382             break;
1383         }
1384
1385         if (mon->asleep() && mons_near(mon))
1386             remove_auto_exclude(mon, true);
1387
1388         // Will alert monster to <src> and turn them
1389         // against them, unless they have a current foe.
1390         // It won't turn friends hostile either.
1391         if ((!mons_is_fleeing(mon) || mons_class_flag(mon->type, M_FLEEING))
1392             && !mons_is_retreating(mon)
1393             && !mons_is_panicking(mon)
1394             && !mons_is_cornered(mon))
1395         {
1396             mon->behaviour = BEH_SEEK;
1397         }
1398
1399         if (mon->foe == MHITNOT)
1400             mon->foe = src_idx;
1401
1402         if (!src_pos.origin()
1403             && (mon->foe == MHITNOT || src && mon->foe == src->mindex()
1404                 || mons_is_wandering(mon)))
1405         {
1406             if (mon->is_patrolling())
1407                 break;
1408
1409             mon->target = src_pos;
1410
1411             // XXX: Should this be done in _handle_behaviour()?
1412             if (src == &you && src_pos == you.pos()
1413                 && !you.see_cell(mon->pos()))
1414             {
1415                 try_pathfind(mon);
1416             }
1417         }
1418         break;
1419
1420     case ME_SCARE:
1421         // Stationary monsters can't flee, and berserking monsters
1422         // are too enraged.
1423         if (mon->is_stationary() || mon->berserk_or_insane())
1424         {
1425             mon->del_ench(ENCH_FEAR, true, true);
1426             break;
1427         }
1428
1429         // Neither do plants or nonliving beings.
1430         if (mon->holiness() == MH_PLANT
1431             || mon->holiness() == MH_NONLIVING)
1432         {
1433             mon->del_ench(ENCH_FEAR, true, true);
1434             break;
1435         }
1436
1437         msg = getSpeakString(mon->name(DESC_PLAIN) + " flee");
1438
1439         // Assume monsters know where to run from, even if player is
1440         // invisible.
1441         mon->behaviour = BEH_FLEE;
1442         mon->foe       = src_idx;
1443         mon->target    = src_pos;
1444         if (src == &you)
1445         {
1446             // Friendly monsters don't become hostile if you read a
1447             // scroll of fear, but enslaved ones will.
1448             // Send friendlies off to a random target so they don't cling
1449             // to you in fear.
1450             if (mon->friendly())
1451             {
1452                 breakCharm = true;
1453                 mon->foe   = MHITNOT;
1454                 set_random_target(mon);
1455             }
1456             else
1457                 setTarget = true;
1458         }
1459         else if (mon->friendly() && !crawl_state.game_is_arena())
1460             mon->foe = MHITYOU;
1461
1462         if (you.see_cell(mon->pos()))
1463             learned_something_new(HINT_FLEEING_MONSTER);
1464
1465         break;
1466
1467     case ME_CORNERED:
1468         // Some monsters can't flee.
1469         if (!mons_is_retreating(mon) && !mon->has_ench(ENCH_FEAR))
1470             break;
1471
1472         // Pacified monsters shouldn't change their behaviour.
1473         if (mon->pacified())
1474             break;
1475
1476         // Just set behaviour... foe doesn't change.
1477         if (!mons_is_cornered(mon) && !mon->has_ench(ENCH_WITHDRAWN))
1478         {
1479             if (mon->friendly() && !crawl_state.game_is_arena())
1480             {
1481                 mon->foe = MHITYOU;
1482                 msg = "PLAIN:@The_monster@ returns to your side!";
1483             }
1484             else if (!mon->is_child_tentacle())
1485             {
1486                 msg = getSpeakString(mon->name(DESC_PLAIN) + " cornered");
1487                 if (msg.empty())
1488                     msg = "PLAIN:@The_monster@ turns to fight!";
1489             }
1490         }
1491
1492         mon->behaviour = BEH_CORNERED;
1493         break;
1494
1495     case ME_HURT:
1496         // Monsters with the M_FLEES flag can flee at low HP.
1497         // Cannot flee if cornered.
1498         // Monster can flee if HP is less than 1/4 maxhp or less than 20 hp
1499         // (whichever is lower). Chance starts quite low, and is near 100% at 1.
1500         // Monsters with less than 8 maxhp are unable to flee.
1501         // These numbers could still use some adjusting.
1502         //
1503         // Assuming fleeThreshold is 20:
1504         //   at 19 hp: 5% chance of fleeing
1505         //   at 10 hp: 50% chance of fleeing
1506         //   (chance increases by 5% for every hp lost.)
1507         if (mons_class_flag(mon->type, M_FLEES)
1508             && !mons_is_cornered(mon)
1509             && !mon->berserk_or_insane()
1510             && x_chance_in_y(fleeThreshold - mon->hit_points, fleeThreshold))
1511         {
1512             mon->behaviour = BEH_FLEE;
1513         }
1514         break;
1515
1516     case ME_EVAL:
1517         break;
1518     }
1519
1520     if (setTarget && src)
1521     {
1522         mon->target = src_pos;
1523         if (src->is_player()
1524             && !mon->has_ench(ENCH_INSANE)
1525             && mon->type != MONS_BATTLESPHERE
1526             && mon->type != MONS_SPECTRAL_WEAPON)
1527         {
1528             // Why only attacks by the player change attitude? -- 1KB
1529             mon->attitude = ATT_HOSTILE;
1530             mons_att_changed(mon);
1531         }
1532     }
1533
1534     // Now, break charms if appropriate.
1535     if (breakCharm)
1536     {
1537         mon->del_ench(ENCH_CHARM);
1538         mons_att_changed(mon);
1539     }
1540
1541     // Do any resultant foe or state changes.
1542     handle_behaviour(mon);
1543
1544     // That might have made the monster leave the level.
1545     if (!mon->alive())
1546         return;
1547
1548     ASSERT_IN_BOUNDS_OR_ORIGIN(mon->target);
1549
1550     // If it woke up and you're its new foe, it might shout.
1551     if (was_sleeping && !mon->asleep() && allow_shout
1552         && mon->foe == MHITYOU && !mon->wont_attack())
1553     {
1554         handle_monster_shouts(mon);
1555     }
1556
1557     const bool wasLurking =
1558         (old_behaviour == BEH_LURK && !mons_is_lurking(mon));
1559     const bool isPacified = mon->pacified();
1560
1561     if ((wasLurking || isPacified)
1562         && (event == ME_DISTURB || event == ME_ALERT || event == ME_EVAL))
1563     {
1564         // Lurking monsters or pacified monsters leaving the level won't
1565         // stop doing so just because they noticed something.
1566         mon->behaviour = old_behaviour;
1567     }
1568     else if (mon->has_ench(ENCH_SUBMERGED) && !mon->del_ench(ENCH_SUBMERGED))
1569     {
1570         // The same goes for submerged monsters, if they can't
1571         // unsubmerge.
1572         mon->behaviour = BEH_LURK;
1573     }
1574
1575     // mons_speaks_msg already handles the LOS check.
1576     if (!msg.empty() && mon->visible_to(&you))
1577         mons_speaks_msg(mon, msg, MSGCH_TALK, silenced(mon->pos()));
1578
1579     if (mons_allows_beogh_now(mon))
1580     {
1581         const bool first = !you.attribute[ATTR_SEEN_BEOGH];
1582         if (first || one_chance_in(10))
1583         {
1584             mons_speaks_msg(mon, getSpeakString("orc_priest_preaching"),
1585                             MSGCH_TALK);
1586             if (first)
1587             {
1588                 ASSERT_RANGE(get_talent(ABIL_CONVERT_TO_BEOGH, false).hotkey,
1589                              'A', 'z' + 1);
1590                 mprf("(press <white>%s %c</white> to convert to Beogh)",
1591                      command_to_string(CMD_USE_ABILITY).c_str(),
1592                      get_talent(ABIL_CONVERT_TO_BEOGH, false).hotkey);
1593                 you.attribute[ATTR_SEEN_BEOGH] = 1;
1594             }
1595         }
1596     }
1597
1598     ASSERT(!crawl_state.game_is_arena()
1599            || mon->foe != MHITYOU && mon->target != you.pos());
1600 }
1601
1602 void make_mons_stop_fleeing(monster* mon)
1603 {
1604     if (mons_is_retreating(mon))
1605         behaviour_event(mon, ME_CORNERED);
1606 }
1607
1608 //Make all monsters lose track of a given target after a few turns
1609 void shake_off_monsters(const actor* target)
1610 {
1611     //If the player is under Ashenzari penance, monsters will not
1612     //lose track of them so easily
1613     if (target->is_player() && you.penance[GOD_ASHENZARI])
1614         return;
1615
1616     for (monster_iterator mi; mi; ++mi)
1617     {
1618         monster* m = mi->as_monster();
1619         if (m->foe == target->mindex() && m->foe_memory > 0)
1620         {
1621             // Set foe_memory to a small non-zero amount so that monsters can
1622             // still close in on your old location, rather than immediately
1623             // realizing their target is gone, even if they took stairs while
1624             // out of sight
1625             dprf("Monster %d forgot about foe %d. (Previous foe_memory: %d)",
1626                     m->mindex(), target->mindex(), m->foe_memory);
1627             m->foe_memory = min(m->foe_memory, 7);
1628         }
1629     }
1630 }