Don't let rolling boulder beetles push (ardl)
[crawl.git] / crawl-ref / source / mon-act.cc
1 /**
2  * @file
3  * @brief Monsters doing stuff (monsters acting).
4 **/
5
6 #include "AppHdr.h"
7
8 #include "mon-act.h"
9
10 #include "act-iter.h"
11 #include "areas.h"
12 #include "arena.h"
13 #include "attitude-change.h"
14 #include "bloodspatter.h"
15 #include "cloud.h"
16 #include "colour.h"
17 #include "coordit.h"
18 #include "corpse.h"
19 #include "dbg-scan.h"
20 #include "delay.h"
21 #include "directn.h" // feature_description_at
22 #include "dungeon.h"
23 #include "english.h" // apostrophise
24 #include "fight.h"
25 #include "fineff.h"
26 #include "ghost.h"
27 #include "god-abil.h" // GOZAG_GOLD_AURA_KEY
28 #include "god-passive.h"
29 #include "god-prayer.h"
30 #include "hints.h"
31 #include "item-name.h"
32 #include "item-prop.h"
33 #include "item-status-flag-type.h"
34 #include "items.h"
35 #include "level-state-type.h"
36 #include "libutil.h"
37 #include "losglobal.h"
38 #include "los.h"
39 #include "mapmark.h"
40 #include "message.h"
41 #include "mon-abil.h"
42 #include "mon-behv.h"
43 #include "mon-book.h"
44 #include "mon-cast.h"
45 #include "mon-death.h"
46 #include "mon-movetarget.h"
47 #include "mon-place.h"
48 #include "mon-poly.h"
49 #include "mon-project.h"
50 #include "mon-speak.h"
51 #include "mon-tentacle.h"
52 #include "nearby-danger.h"
53 #include "religion.h"
54 #include "shout.h"
55 #include "spl-book.h"
56 #include "spl-clouds.h"
57 #include "spl-damage.h"
58 #include "spl-summoning.h"
59 #include "spl-transloc.h"
60 #include "spl-util.h"
61 #include "spl-zap.h"
62 #include "state.h"
63 #include "stringutil.h"
64 #include "target.h"
65 #include "teleport.h"
66 #include "terrain.h"
67 #include "throw.h"
68 #include "timed-effects.h"
69 #include "traps.h"
70 #include "viewchar.h"
71 #include "view.h"
72
73 static bool _handle_pickup(monster* mons);
74 static void _mons_in_cloud(monster& mons);
75 static bool _monster_move(monster* mons);
76
77 // [dshaligram] Doesn't need to be extern.
78 static coord_def mmov;
79
80 /**
81  * Get the monster's "hit dice".
82  *
83  * @return          The monster's HD.
84  */
85 int monster::get_hit_dice() const
86 {
87     const int base_hd = get_experience_level();
88
89     const mon_enchant drain_ench = get_ench(ENCH_DRAINED);
90     const int drained_hd = base_hd - drain_ench.degree;
91
92     // temp malmuts (-25% HD)
93     if (has_ench(ENCH_WRETCHED))
94         return max(drained_hd * 3 / 4, 1);
95     return max(drained_hd, 1);
96 }
97
98 /**
99  * Get the monster's "experience level" - their hit dice, unmodified by
100  * temporary enchantments (draining).
101  *
102  * @return          The monster's XL.
103  */
104 int monster::get_experience_level() const
105 {
106     return hit_dice;
107 }
108
109 static const coord_def mon_compass[8] =
110 {
111     { -1,-1 }, { 0,-1 }, {  1,-1 }, {  1,0 }, // bjnl
112     {  1, 1 }, { 0, 1 }, { -1, 1 }, { -1,0 }  // ukyh
113 };
114
115 static int _compass_idx(const coord_def& mov)
116 {
117     for (int i = 0; i < 8; i++)
118         if (mon_compass[i] == mov)
119             return i;
120     return -1;
121 }
122
123 static inline bool _mons_natural_regen_roll(monster* mons)
124 {
125     const int regen_rate = mons->natural_regen_rate();
126     return x_chance_in_y(regen_rate, 25);
127 }
128
129 // Do natural regeneration for monster.
130 static void _monster_regenerate(monster* mons)
131 {
132     // Early bailout so that regen-based triggers don't get spammed
133     if (mons->hit_points == mons->max_hit_points)
134         return;
135
136     if (crawl_state.disables[DIS_MON_REGEN])
137         return;
138
139     if (mons->has_ench(ENCH_SICK)
140         || !mons_can_regenerate(*mons) && !(mons->has_ench(ENCH_REGENERATION)))
141     {
142         return;
143     }
144
145     // Non-land creatures out of their element cannot regenerate.
146     if (mons_primary_habitat(*mons) != HT_LAND
147         && !monster_habitable_grid(mons, env.grid(mons->pos())))
148     {
149         return;
150     }
151
152     if (mons_class_fast_regen(mons->type)
153         || mons->has_ench(ENCH_REGENERATION)
154         || _mons_natural_regen_roll(mons))
155     {
156         mons->heal(1);
157     }
158
159     if (mons_is_hepliaklqana_ancestor(mons->type))
160     {
161         if (mons->hit_points == mons->max_hit_points && you.can_see(*mons))
162             interrupt_activity(activity_interrupt::ancestor_hp);
163     }
164 }
165
166 static void _escape_water_hold(monster& mons)
167 {
168     if (mons.has_ench(ENCH_WATER_HOLD))
169     {
170         simple_monster_message(mons, " slips free of the water.");
171         mons.del_ench(ENCH_WATER_HOLD);
172     }
173 }
174
175 static void _handle_manticore_barbs(monster& mons)
176 {
177     if (mons.has_ench(ENCH_BARBS))
178     {
179         mon_enchant barbs = mons.get_ench(ENCH_BARBS);
180
181         // Save these first because hurt() might kill the monster.
182         const coord_def pos = mons.pos();
183         const monster_type type = mons.type;
184         mons.hurt(monster_by_mid(barbs.source),
185                   roll_dice(2, barbs.degree * 2 + 2));
186         bleed_onto_floor(pos, type, 2, false);
187         if (coinflip())
188         {
189             barbs.duration--;
190             mons.update_ench(barbs);
191         }
192     }
193 }
194
195 static bool _swap_monsters(monster& mover, monster& moved)
196 {
197     // Can't swap with a stationary monster.
198     // Although nominally stationary kraken tentacles can be swapped
199     // with the main body.
200     if (moved.is_stationary() && !moved.is_child_tentacle())
201         return false;
202
203     // If the target monster is constricted it is stuck
204     // and not eligible to be swapped with
205     if (moved.is_constricted())
206     {
207         dprf("%s fails to swap with %s, constricted.",
208             mover.name(DESC_THE).c_str(),
209             moved.name(DESC_THE).c_str());
210             return false;
211     }
212
213     // Swapping is a purposeful action.
214     if (mover.confused())
215         return false;
216
217     // Right now just happens in sanctuary.
218     if (!is_sanctuary(mover.pos()) || !is_sanctuary(moved.pos()))
219         return false;
220
221     // A friendly or good-neutral monster moving past a fleeing hostile
222     // or neutral monster, or vice versa.
223     if (mover.wont_attack() == moved.wont_attack()
224         || mons_is_retreating(mover) == mons_is_retreating(moved))
225     {
226         return false;
227     }
228
229     // Don't swap places if the player explicitly ordered their pet to
230     // attack monsters.
231     if ((mover.friendly() || moved.friendly())
232         && you.pet_target != MHITYOU && you.pet_target != MHITNOT)
233     {
234         return false;
235     }
236
237     // Okay, we can probably do the swap.
238     if (!mover.swap_with(&moved))
239         return false;
240
241     if (you.can_see(mover) && you.can_see(moved))
242     {
243         mprf("%s and %s swap places.", mover.name(DESC_THE).c_str(),
244              moved.name(DESC_THE).c_str());
245     }
246
247     _escape_water_hold(mover);
248
249     _handle_manticore_barbs(mover);
250     _handle_manticore_barbs(moved);
251
252     if (moved.type == MONS_FOXFIRE)
253     {
254         mprf(MSGCH_GOD, "By Zin's power the foxfire is contained!");
255         monster_die(moved, KILL_DISMISSED, NON_MONSTER, true);
256     }
257
258     return true;
259 }
260
261 static bool _do_mon_spell(monster* mons)
262 {
263     if (handle_mon_spell(mons))
264     {
265         // If a Pan lord/pghost is known to be a spellcaster, it's safer
266         // to assume it has ranged spells too. For others, it'd just
267         // lead to unnecessary false positives.
268         if (mons_is_ghost_demon(mons->type))
269             mons->flags |= MF_SEEN_RANGED;
270
271         mmov.reset();
272         return true;
273     }
274
275     return false;
276 }
277
278 static void _swim_or_move_energy(monster& mon)
279 {
280     const dungeon_feature_type feat = env.grid(mon.pos());
281
282     // FIXME: Replace check with mons_is_swimming()?
283     mon.lose_energy(((feat_is_lava(feat) || feat_is_water(feat))
284                      && mon.ground_level()) ? EUT_SWIM : EUT_MOVE);
285 }
286
287 static bool _unfriendly_or_impaired(const monster& mon)
288 {
289     return !mon.wont_attack() || mon.has_ench(ENCH_INSANE) || mon.confused();
290 }
291
292 // Check up to eight grids in the given direction for whether there's a
293 // monster of the same alignment as the given monster that happens to
294 // have a ranged attack. If this is true for the first monster encountered,
295 // returns true. Otherwise returns false.
296 static bool _ranged_ally_in_dir(monster* mon, coord_def p)
297 {
298     coord_def pos = mon->pos();
299
300     for (int i = 1; i <= LOS_RADIUS; i++)
301     {
302         pos += p;
303         if (!in_bounds(pos))
304             break;
305
306         const actor* ally = actor_at(pos);
307         if (ally == nullptr)
308             continue;
309
310         if (mons_aligned(mon, ally))
311         {
312             // Hostile monsters of normal intelligence only move aside for
313             // monsters of the same type.
314             if (_unfriendly_or_impaired(*mon)
315                 && mons_genus(mon->type) != mons_genus(ally->type))
316             {
317                 return false;
318             }
319
320             // XXX: Sometimes the player wants llies in front of them to stay
321             // out of LOF. However use of allies for cover is extremely common,
322             // so it doesn't work well to always have allies move out of player
323             // LOF. Until a better interface or method can be found to handle
324             // both cases, have allies move out of the way only for other
325             // monsters.
326             if (ally->is_monster())
327                 return mons_has_ranged_attack(*(ally->as_monster()));
328         }
329         break;
330     }
331     return false;
332 }
333
334 // Check whether there's a monster of the same type and alignment adjacent
335 // to the given monster in at least one of three given directions (relative to
336 // the monster position).
337 static bool _allied_monster_at(monster* mon, coord_def a, coord_def b,
338                                coord_def c)
339 {
340     for (coord_def delta : { a, b, c })
341     {
342         coord_def pos = mon->pos() + delta;
343         if (!in_bounds(pos))
344             continue;
345
346         const monster* ally = monster_at(pos);
347         if (ally == nullptr)
348             continue;
349
350         if (ally->is_stationary() || ally->reach_range() > REACH_NONE)
351             continue;
352
353         // Hostile monsters of normal intelligence only move aside for
354         // monsters of the same genus.
355         if (_unfriendly_or_impaired(*mon)
356             && mons_genus(mon->type) != mons_genus(ally->type))
357         {
358             continue;
359         }
360
361         if (mons_aligned(mon, ally))
362             return true;
363     }
364
365     return false;
366 }
367
368 // Altars as well as branch entrances are considered interesting for
369 // some monster types.
370 static bool _mon_on_interesting_grid(monster* mon)
371 {
372     const dungeon_feature_type feat = env.grid(mon->pos());
373
374     switch (feat)
375     {
376     // Holy beings will tend to patrol around altars to the good gods.
377     case DNGN_ALTAR_ELYVILON:
378         if (!one_chance_in(3))
379             return false;
380         // else fall through
381     case DNGN_ALTAR_ZIN:
382     case DNGN_ALTAR_SHINING_ONE:
383         return mon->is_holy();
384
385     // Orcs will tend to patrol around altars to Beogh, and guard the
386     // stairway from and to the Orcish Mines.
387     case DNGN_ALTAR_BEOGH:
388     case DNGN_ENTER_ORC:
389     case DNGN_EXIT_ORC:
390         return mons_is_native_in_branch(*mon, BRANCH_ORC);
391
392     // Same for elves and the Elven Halls.
393     case DNGN_ENTER_ELF:
394     case DNGN_EXIT_ELF:
395         return mons_is_native_in_branch(*mon, BRANCH_ELF);
396
397     // Spiders...
398     case DNGN_ENTER_SPIDER:
399         return mons_is_native_in_branch(*mon, BRANCH_SPIDER);
400
401     default:
402         return false;
403     }
404 }
405
406 // If a hostile monster finds itself on a grid of an "interesting" feature,
407 // while unoccupied, it will remain in that area, and try to return to it
408 // if it left it for fighting, seeking etc.
409 static void _maybe_set_patrol_route(monster* mons)
410 {
411     if (_mon_on_interesting_grid(mons) // Patrolling shouldn't always happen
412         && one_chance_in(4)
413         && mons_is_wandering(*mons)
414         && !mons->is_patrolling()
415         && !mons->friendly())
416     {
417         mons->patrol_point = mons->pos();
418     }
419 }
420
421 static bool _mons_can_cast_dig(const monster* mons, bool random)
422 {
423     if (mons->foe == MHITNOT || !mons->has_spell(SPELL_DIG) || mons->confused()
424         || mons->berserk_or_insane())
425     {
426         return false;
427     }
428
429     const bool antimagiced = mons->has_ench(ENCH_ANTIMAGIC)
430                       && (random
431                           && !x_chance_in_y(4 * BASELINE_DELAY,
432                                             4 * BASELINE_DELAY
433                                             + mons->get_ench(ENCH_ANTIMAGIC).duration)
434                       || (!random
435                           && mons->get_ench(ENCH_ANTIMAGIC).duration
436                              >= 4 * BASELINE_DELAY));
437     const auto flags = mons->spell_slot_flags(SPELL_DIG);
438     return !(antimagiced && flags & MON_SPELL_ANTIMAGIC_MASK)
439             && !(mons->is_silenced() && flags & MON_SPELL_SILENCE_MASK);
440 }
441
442 static bool _mons_can_zap_dig(const monster* mons)
443 {
444     return mons->foe != MHITNOT
445            && !mons->asleep()
446            && !mons->confused() // they don't get here anyway
447            && !mons->berserk_or_insane()
448            && !mons->submerged()
449            && mons_itemuse(*mons) >= MONUSE_STARTING_EQUIPMENT
450            && mons->inv[MSLOT_WAND] != NON_ITEM
451            && env.item[mons->inv[MSLOT_WAND]].is_type(OBJ_WANDS, WAND_DIGGING)
452            && env.item[mons->inv[MSLOT_WAND]].charges > 0;
453 }
454
455 static void _set_mons_move_dir(const monster* mons,
456                                coord_def* dir, coord_def* delta)
457 {
458     ASSERT(dir);
459     ASSERT(delta);
460
461     // Some calculations.
462     if ((mons_class_flag(mons->type, M_BURROWS)
463          || _mons_can_cast_dig(mons, false))
464         && mons->foe == MHITYOU)
465     {
466         // Digging monsters always move in a straight line in your direction.
467         *delta = you.pos() - mons->pos();
468     }
469     else
470     {
471         *delta = (mons->firing_pos.zero() ? mons->target : mons->firing_pos)
472                  - mons->pos();
473     }
474
475     // Move the monster.
476     *dir = delta->sgn();
477
478     if (mons_is_retreating(*mons)
479         && (!mons->friendly() || mons->target != you.pos()))
480     {
481         *dir *= -1;
482     }
483 }
484
485 typedef FixedArray< bool, 3, 3 > move_array;
486
487 static void _fill_good_move(const monster* mons, move_array* good_move)
488 {
489     for (int count_x = 0; count_x < 3; count_x++)
490         for (int count_y = 0; count_y < 3; count_y++)
491         {
492             const int targ_x = mons->pos().x + count_x - 1;
493             const int targ_y = mons->pos().y + count_y - 1;
494
495             // Bounds check: don't consider moving out of grid!
496             if (!in_bounds(targ_x, targ_y))
497             {
498                 (*good_move)[count_x][count_y] = false;
499                 continue;
500             }
501
502             (*good_move)[count_x][count_y] =
503                 mon_can_move_to_pos(mons, coord_def(count_x-1, count_y-1));
504         }
505 }
506
507 // This only tracks movement, not whether hitting an
508 // adjacent monster is a possible move.
509 bool mons_can_move_towards_target(const monster* mon)
510 {
511     coord_def mov, delta;
512     _set_mons_move_dir(mon, &mov, &delta);
513
514     move_array good_move;
515     _fill_good_move(mon, &good_move);
516
517     int dir = _compass_idx(mov);
518     for (int i = -1; i <= 1; ++i)
519     {
520         const int altdir = (dir + i + 8) % 8;
521         const coord_def p = mon_compass[altdir] + coord_def(1, 1);
522         if (good_move(p))
523             return true;
524     }
525
526     return false;
527 }
528
529 static const string BATTY_TURNS_KEY = "BATTY_TURNS";
530
531 static void _be_batty(monster &mons)
532 {
533     mons.behaviour = BEH_WANDER;
534     set_random_target(&mons);
535     mons.props[BATTY_TURNS_KEY] = 0;
536 }
537
538 static void _handle_movement(monster* mons)
539 {
540     _maybe_set_patrol_route(mons);
541
542     if (sanctuary_exists())
543     {
544         // Monsters will try to flee out of a sanctuary.
545         if (is_sanctuary(mons->pos())
546             && mons_is_influenced_by_sanctuary(*mons)
547             && !mons_is_fleeing_sanctuary(*mons))
548         {
549             mons_start_fleeing_from_sanctuary(*mons);
550         }
551         else if (mons_is_fleeing_sanctuary(*mons)
552                  && !is_sanctuary(mons->pos()))
553         {
554             // Once outside there's a chance they'll regain their courage.
555             // Nonliving and berserking monsters always stop immediately,
556             // since they're only being forced out rather than actually
557             // scared.
558             if (mons->is_nonliving()
559                 || mons->berserk()
560                 || mons->has_ench(ENCH_INSANE)
561                 || x_chance_in_y(2, 5))
562             {
563                 mons_stop_fleeing_from_sanctuary(*mons);
564             }
565         }
566     }
567
568     coord_def delta;
569     _set_mons_move_dir(mons, &mmov, &delta);
570
571     if (sanctuary_exists())
572     {
573         // Don't allow monsters to enter a sanctuary or attack you inside a
574         // sanctuary, even if you're right next to them.
575         if (is_sanctuary(mons->pos() + mmov)
576             && (!is_sanctuary(mons->pos())
577                 || mons->pos() + mmov == you.pos()))
578         {
579             mmov.reset();
580         }
581     }
582
583     // Bounds check: don't let fleeing monsters try to run off the grid.
584     const coord_def s = mons->pos() + mmov;
585     if (!in_bounds_x(s.x))
586         mmov.x = 0;
587     if (!in_bounds_y(s.y))
588         mmov.y = 0;
589
590     if (delta.rdist() > 3)
591     {
592         // Reproduced here is some semi-legacy code that makes monsters
593         // move somewhat randomly along oblique paths. It is an
594         // exceedingly good idea, given crawl's unique line of sight
595         // properties.
596         //
597         // Added a check so that oblique movement paths aren't used when
598         // close to the target square. -- bwr
599
600         // Sometimes we'll just move parallel the x axis.
601         if (abs(delta.x) > abs(delta.y) && coinflip())
602             mmov.y = 0;
603
604         // Sometimes we'll just move parallel the y axis.
605         if (abs(delta.y) > abs(delta.x) && coinflip())
606             mmov.x = 0;
607     }
608
609     // Now quit if we can't move.
610     if (mmov.origin())
611         return;
612
613     const coord_def newpos(mons->pos() + mmov);
614
615     // Filling this is relatively costly and not always needed, so be a bit
616     // lazy about it.
617     move_array good_move;
618     bool good_move_filled = false;
619
620     // If the monster is moving in your direction, whether to attack or
621     // protect you, or towards a monster it intends to attack, check
622     // whether we first need to take a step to the side to make sure the
623     // reinforcement can follow through. Only do this with 50% chance,
624     // though, so it's not completely predictable.
625
626     // First, check whether the monster is smart enough to even consider
627     // this.
628     if ((newpos == you.pos()
629            || monster_at(newpos) && mons->foe == env.mgrid(newpos))
630         && mons_intel(*mons) > I_BRAINLESS
631         && coinflip()
632         && !mons_is_confused(*mons) && !mons->caught()
633         && !mons->berserk_or_insane())
634     {
635         _fill_good_move(mons, &good_move);
636         good_move_filled = true;
637         // If the monster is moving parallel to the x or y axis, check
638         // if there are other unblocked grids adjacent to the target and
639         // whether
640         //
641         // a) the neighbouring grids are blocked and an ally is behind us,
642         // or
643         // b) we're intelligent and blocking a ranged attack
644         if (mmov.y == 0)
645         {
646             if ((good_move[mmov.x+1][0] || good_move[mmov.x+1][2])
647                 && (_allied_monster_at(mons, coord_def(-mmov.x, -1),
648                                        coord_def(-mmov.x, 0),
649                                        coord_def(-mmov.x, 1))
650                        && !good_move[1][0] && !good_move[1][2]
651                     || mons_intel(*mons) >= I_HUMAN
652                        && _ranged_ally_in_dir(mons, coord_def(-mmov.x, 0))))
653             {
654                 if (good_move[mmov.x+1][0])
655                     mmov.y = -1;
656                 if (good_move[mmov.x+1][2] && (mmov.y == 0 || coinflip()))
657                     mmov.y = 1;
658             }
659         }
660         else if (mmov.x == 0)
661         {
662             if ((good_move[0][mmov.y+1] || good_move[2][mmov.y+1])
663                 && (_allied_monster_at(mons, coord_def(-1, -mmov.y),
664                                        coord_def(0, -mmov.y),
665                                        coord_def(1, -mmov.y))
666                        && !good_move[0][1] && !good_move[2][1]
667                     || mons_intel(*mons) >= I_HUMAN
668                        && _ranged_ally_in_dir(mons, coord_def(0, -mmov.y))))
669             {
670                 if (good_move[0][mmov.y+1])
671                     mmov.x = -1;
672                 if (good_move[2][mmov.y+1] && (mmov.x == 0 || coinflip()))
673                     mmov.x = 1;
674             }
675         }
676         else // We're moving diagonally.
677         {
678             if (good_move[mmov.x+1][1])
679             {
680                 if (!good_move[1][mmov.y+1]
681                        && _allied_monster_at(mons, coord_def(-mmov.x, -1),
682                                            coord_def(-mmov.x, 0),
683                                            coord_def(-mmov.x, 1))
684                     || mons_intel(*mons) >= I_HUMAN
685                        && _ranged_ally_in_dir(mons, coord_def(-mmov.x, -mmov.y)))
686                 {
687                     mmov.y = 0;
688                 }
689             }
690             else if (good_move[1][mmov.y+1]
691                      && _allied_monster_at(mons, coord_def(-1, -mmov.y),
692                                             coord_def(0, -mmov.y),
693                                             coord_def(1, -mmov.y))
694                          || mons_intel(*mons) >= I_HUMAN
695                             && _ranged_ally_in_dir(mons, coord_def(-mmov.x, -mmov.y)))
696             {
697                 mmov.x = 0;
698             }
699         }
700     }
701
702     // Now quit if we can't move.
703     if (mmov.origin())
704         return;
705
706     // everything below here is irrelevant if the player is not in bounds, for
707     // example if they have stepped from time.
708     if (!in_bounds(you.pos()))
709         return;
710
711     // Try to stay in sight of the player if we're moving towards
712     // him/her, in order to avoid the monster coming into view,
713     // shouting, and then taking a step in a path to the player which
714     // temporarily takes it out of view, which can lead to the player
715     // getting "comes into view" and shout messages with no monster in
716     // view.
717
718     // Doesn't matter for arena mode.
719     if (crawl_state.game_is_arena())
720         return;
721
722     // Did we just come into view?
723     // TODO: This doesn't seem to work right. Fix, or remove?
724
725     if (mons->seen_context != SC_JUST_SEEN)
726         return;
727     if (testbits(mons->flags, MF_WAS_IN_VIEW))
728         return;
729
730     const coord_def old_pos  = mons->pos();
731     const int       old_dist = grid_distance(you.pos(), old_pos);
732
733     // We're already staying in the player's LOS.
734     if (you.see_cell(old_pos + mmov))
735         return;
736
737     // We're not moving towards the player.
738     if (grid_distance(you.pos(), old_pos + mmov) >= old_dist)
739     {
740         // Instead of moving out of view, we stay put.
741         if (you.see_cell(old_pos))
742             mmov.reset();
743         return;
744     }
745
746     // Try to find a move that brings us closer to the player while
747     // keeping us in view.
748     int matches = 0;
749     for (int i = 0; i < 3; i++)
750         for (int j = 0; j < 3; j++)
751         {
752             if (i == 0 && j == 0)
753                 continue;
754
755             coord_def d(i - 1, j - 1);
756             coord_def tmp = old_pos + d;
757             if (!you.see_cell(tmp))
758                 continue;
759
760             if (!good_move_filled)
761             {
762                 _fill_good_move(mons, &good_move);
763                 good_move_filled = true;
764             }
765             if (!good_move[i][j])
766                 continue;
767
768             if (grid_distance(you.pos(), tmp) < old_dist)
769             {
770                 if (one_chance_in(++matches))
771                     mmov = d;
772                 break;
773             }
774         }
775
776     // We haven't been able to find a visible cell to move to. If previous
777     // position was visible, we stay put.
778     if (you.see_cell(old_pos) && !you.see_cell(old_pos + mmov))
779         mmov.reset();
780 }
781
782 static bool _handle_potion(monster& mons)
783 {
784     item_def* potion = mons.mslot_item(MSLOT_POTION);
785     if (mons.asleep()
786         || !potion
787         || !one_chance_in(3)
788         || mons_itemuse(mons) < MONUSE_STARTING_EQUIPMENT
789         || potion->base_type != OBJ_POTIONS)
790     {
791         return false;
792     }
793
794     bool rc = false;
795
796     const potion_type ptype = static_cast<potion_type>(potion->sub_type);
797
798     if (mons.can_drink_potion(ptype) && mons.should_drink_potion(ptype))
799     {
800         const bool was_visible = you.can_see(mons);
801
802         // XXX: this is mostly to prevent a funny message order:
803         // "$foo drinks a potion. $foo wields a great mace. $foo goes berserk!"
804         if (ptype == POT_BERSERK_RAGE)
805             mons.wield_melee_weapon();
806
807         // Drink the potion, and identify it.
808         if (mons.drink_potion_effect(ptype) && was_visible)
809             set_ident_type(OBJ_POTIONS, ptype, true);
810
811         // Remove it from inventory.
812         if (dec_mitm_item_quantity(potion->index(), 1))
813             mons.inv[MSLOT_POTION] = NON_ITEM;
814
815         mons.lose_energy(EUT_ITEM);
816         rc = true;
817     }
818
819     return rc;
820 }
821
822 static bool _handle_evoke_equipment(monster& mons)
823 {
824     // TODO: check non-ring, non-amulet equipment
825     item_def* jewel = mons.mslot_item(MSLOT_JEWELLERY);
826     if (mons.asleep()
827         || mons_is_confused(mons)
828         || !jewel
829         || !one_chance_in(3)
830         || mons_itemuse(mons) < MONUSE_STARTING_EQUIPMENT
831         || jewel->base_type != OBJ_JEWELLERY)
832     {
833         return false;
834     }
835
836     bool rc = false;
837
838     const jewellery_type jtype = static_cast<jewellery_type>(jewel->sub_type);
839
840     if (mons.can_evoke_jewellery(jtype) && mons.should_evoke_jewellery(jtype))
841     {
842         const bool was_visible = you.can_see(mons);
843
844         // Evoke the item, and identify it.
845         if (mons.evoke_jewellery_effect(jtype) && was_visible)
846             set_ident_type(OBJ_JEWELLERY, jtype, true);
847
848         mons.lose_energy(EUT_ITEM);
849         rc = true;
850     }
851
852     return rc;
853 }
854
855 /**
856  * Check if the monster has a swooping attack and is in a position to
857  * use it, and do so if they can.
858  *
859  * Specifically, this seems to try to move to the opposite side of the target
860  * (if there's space) and perform a melee attack, then set a cooldown for
861  * 4-8 turns.
862  *
863  * @param mons The monster who might be swooping.
864  * @return Whether they performed a swoop attack. False if the monster
865  *         can't swoop, the foe isn't hostile, the positioning doesn't
866  *         work, etc.
867  */
868 static bool _handle_swoop(monster& mons)
869 {
870     // TODO: check for AF_SWOOP in other slots and/or make it work there?
871     if (mons_attack_spec(mons, 0, true).flavour != AF_SWOOP)
872         return false;
873
874     actor *defender = mons.get_foe();
875     if (mons.confused() || !defender || !mons.can_see(*defender))
876         return false;
877
878     if (mons.foe_distance() >= 5 || mons.foe_distance() == 1)
879         return false;
880
881     if (!one_chance_in(4))
882         return false;
883
884     if (mons.props.exists("swoop_cooldown")
885         && (you.elapsed_time < mons.props["swoop_cooldown"].get_int()))
886     {
887         return false;
888     }
889
890     coord_def target = defender->pos();
891
892     bolt tracer;
893     tracer.source = mons.pos();
894     tracer.target = target;
895     tracer.is_tracer = true;
896     tracer.pierce = true;
897     tracer.range = LOS_RADIUS;
898     tracer.fire();
899
900     for (unsigned int j = 0; j < tracer.path_taken.size() - 1; ++j)
901     {
902         if (tracer.path_taken[j] != target)
903             continue;
904
905         if (!monster_habitable_grid(&mons, env.grid(tracer.path_taken[j+1]))
906             || actor_at(tracer.path_taken[j+1]))
907         {
908             continue;
909         }
910
911         if (you.can_see(mons))
912         {
913             mprf("%s swoops through the air toward %s!",
914                  mons.name(DESC_THE).c_str(),
915                  defender->name(DESC_THE).c_str());
916         }
917         mons.move_to_pos(tracer.path_taken[j+1]);
918         fight_melee(&mons, defender);
919         mons.props["swoop_cooldown"].get_int() = you.elapsed_time
920                                                   + 40 + random2(51);
921         return true;
922     }
923
924     return false;
925 }
926
927 /**
928  * Check whether this monster can make a reaching attack, and do so if
929  * they can.
930  *
931  * @param mons The monster who might be reaching.
932  * @return Whether they attempted a reaching attack. False if the monster
933  *         doesn't have a reaching weapon, the foe isn't hostile, the foe
934  *         is too near or too far, etc.
935  */
936 static bool _handle_reaching(monster* mons)
937 {
938     bool       ret = false;
939     const reach_type range = mons->reach_range();
940     actor *foe = mons->get_foe();
941
942     if (mons->caught()
943         || mons_is_confused(*mons)
944         || !foe
945         || range <= REACH_NONE
946         || is_sanctuary(mons->pos())
947         || is_sanctuary(foe->pos())
948         || mons->submerged()
949         || (mons_aligned(mons, foe) && !mons->has_ench(ENCH_INSANE))
950         || (mons_is_fleeing(*mons)
951         || mons->pacified()))
952     {
953         return false;
954     }
955
956     const coord_def foepos(foe->pos());
957     const coord_def delta(foepos - mons->pos());
958     const int grid_distance(delta.rdist());
959     const coord_def first_middle(mons->pos() + delta / 2);
960     const coord_def second_middle(foepos - delta / 2);
961
962     if (grid_distance == 2
963         // The monster has to be attacking the correct position.
964         && mons->target == foepos
965         // With a reaching attack with a large enough range:
966         && delta.rdist() <= range
967         // And with no dungeon furniture in the way of the reaching
968         // attack;
969         && (feat_is_reachable_past(env.grid(first_middle))
970             || feat_is_reachable_past(env.grid(second_middle)))
971         // The foe should be on the map (not stepped from time).
972         && in_bounds(foepos))
973     {
974         ret = true;
975
976         ASSERT(foe->is_player() || foe->is_monster());
977
978         fight_melee(mons, foe);
979     }
980
981     return ret;
982 }
983
984 static bool _handle_scroll(monster& mons)
985 {
986     item_def* scroll = mons.mslot_item(MSLOT_SCROLL);
987
988     // Yes, there is a logic to this ordering {dlb}:
989     if (mons.asleep()
990         || mons_is_confused(mons)
991         || mons.submerged()
992         || !scroll
993         || mons.has_ench(ENCH_BLIND)
994         || !one_chance_in(3)
995         || mons_itemuse(mons) < MONUSE_STARTING_EQUIPMENT
996         || silenced(mons.pos())
997         || scroll->base_type != OBJ_SCROLLS)
998     {
999         return false;
1000     }
1001
1002     bool read        = false;
1003     bool was_visible = you.can_see(mons);
1004
1005     // Notice how few cases are actually accounted for here {dlb}:
1006     const int scroll_type = scroll->sub_type;
1007     switch (scroll_type)
1008     {
1009     case SCR_TELEPORTATION:
1010         if (!mons.has_ench(ENCH_TP) && !mons.no_tele(true, false))
1011         {
1012             if (mons.caught() || mons_is_fleeing(mons) || mons.pacified())
1013             {
1014                 simple_monster_message(mons, " reads a scroll.");
1015                 read = true;
1016                 monster_teleport(&mons, false);
1017             }
1018         }
1019         break;
1020
1021     case SCR_BLINKING:
1022         if ((mons.caught() || mons_is_fleeing(mons) || mons.pacified())
1023             && mons.can_see(you) && !mons.no_tele(true, false))
1024         {
1025             simple_monster_message(mons, " reads a scroll.");
1026             read = true;
1027             if (mons.caught())
1028                 monster_blink(&mons);
1029             else
1030                 blink_away(&mons);
1031         }
1032         break;
1033
1034     case SCR_SUMMONING:
1035         if (mons.can_see(you))
1036         {
1037             simple_monster_message(mons, " reads a scroll.");
1038             mprf("Wisps of shadow swirl around %s.", mons.name(DESC_THE).c_str());
1039             read = true;
1040             int count = roll_dice(2, 2);
1041             for (int i = 0; i < count; ++i)
1042             {
1043                 create_monster(
1044                     mgen_data(RANDOM_MOBILE_MONSTER, SAME_ATTITUDE((&mons)),
1045                               mons.pos(), mons.foe)
1046                     .set_summoned(&mons, 3, MON_SUMM_SCROLL));
1047             }
1048         }
1049         break;
1050     }
1051
1052     if (read)
1053     {
1054         if (dec_mitm_item_quantity(mons.inv[MSLOT_SCROLL], 1))
1055             mons.inv[MSLOT_SCROLL] = NON_ITEM;
1056
1057         if (was_visible)
1058             set_ident_type(OBJ_SCROLLS, scroll_type, true);
1059
1060         mons.lose_energy(EUT_ITEM);
1061     }
1062
1063     return read;
1064 }
1065
1066 static void _mons_fire_wand(monster& mons, item_def &wand, bolt &beem,
1067                             bool was_visible)
1068 {
1069     if (!simple_monster_message(mons, " zaps a wand."))
1070     {
1071         if (!silenced(you.pos()))
1072             mprf(MSGCH_SOUND, "You hear a zap.");
1073     }
1074
1075     // charge expenditure {dlb}
1076     wand.charges--;
1077     const spell_type mzap =
1078         spell_in_wand(static_cast<wand_type>(wand.sub_type));
1079
1080     mons_cast(&mons, beem, mzap, MON_SPELL_EVOKE, false);
1081
1082     if (was_visible)
1083     {
1084         if (wand.charges <= 0)
1085             mprf("The now-empty wand crumbles to dust.");
1086         else
1087             mons.flags |= MF_SEEN_RANGED;
1088     }
1089
1090     if (wand.charges <= 0)
1091         dec_mitm_item_quantity(wand.index(), 1);
1092
1093     mons.lose_energy(EUT_ITEM);
1094 }
1095
1096 static bool _handle_wand(monster& mons)
1097 {
1098     item_def *wand = mons.mslot_item(MSLOT_WAND);
1099     // Yes, there is a logic to this ordering {dlb}:
1100     // FIXME: monsters should be able to use wands
1101     //        out of sight of the player [rob]
1102     if (!you.see_cell(mons.pos())
1103         || mons.asleep()
1104         || mons_is_fleeing(mons)
1105         || mons.pacified()
1106         || mons.confused()
1107         || mons_itemuse(mons) < MONUSE_STARTING_EQUIPMENT
1108         || mons.has_ench(ENCH_SUBMERGED)
1109         || x_chance_in_y(3, 4)
1110         || !wand
1111         || wand->base_type != OBJ_WANDS)
1112     {
1113         return false;
1114     }
1115
1116     if (wand->charges <= 0)
1117         return false;
1118
1119     if (item_type_removed(wand->base_type, wand->sub_type))
1120         return false;
1121
1122     // XXX: Teach monsters to use random effects
1123     // Digging is handled elsewhere so that sensible (wall) targets are
1124     // chosen.
1125     if (wand->sub_type == WAND_RANDOM_EFFECTS
1126         || wand->sub_type == WAND_DIGGING)
1127     {
1128         return false;
1129     }
1130
1131     bolt beem;
1132
1133     const spell_type mzap =
1134         spell_in_wand(static_cast<wand_type>(wand->sub_type));
1135
1136     if (!setup_mons_cast(&mons, beem, mzap, true))
1137         return false;
1138
1139     beem.source     = mons.pos();
1140     beem.aux_source =
1141         wand->name(DESC_QUALNAME, false, true, false, false);
1142
1143     bool should_fire = false;
1144     const wand_type kind = (wand_type)wand->sub_type;
1145     switch (kind)
1146     {
1147     case WAND_DISINTEGRATION:
1148         // Dial down damage from wands of disintegration, since
1149         // disintegration beams can do large amounts of damage.
1150         beem.damage.size = beem.damage.size * 2 / 3;
1151
1152         // Intentional fallthrough
1153     default:
1154         fire_tracer(&mons, beem);
1155         should_fire = mons_should_fire(beem);
1156         break;
1157     }
1158
1159     if (should_fire)
1160     {
1161         _mons_fire_wand(mons, *wand, beem, you.see_cell(mons.pos()));
1162         return true;
1163     }
1164
1165     return false;
1166 }
1167
1168 bool handle_throw(monster* mons, bolt & beem, bool teleport, bool check_only)
1169 {
1170     // Yes, there is a logic to this ordering {dlb}:
1171     if (mons->incapacitated()
1172         || mons->submerged()
1173         || mons->caught()
1174         || mons_is_confused(*mons))
1175     {
1176         return false;
1177     }
1178
1179     if (mons_itemuse(*mons) < MONUSE_STARTING_EQUIPMENT
1180         && mons->type != MONS_SPECTRAL_THING)
1181     {
1182         return false;
1183     }
1184
1185     const bool prefer_ranged_attack = mons_class_flag(mons->type,
1186                                                             M_PREFER_RANGED);
1187     const bool master_archer = prefer_ranged_attack && mons->is_archer();
1188     // archers in general get a to-hit bonus and a damage bonus to ranged
1189     // attacks (determined elsewhere).
1190     // master archers will fire when adjacent, and are more likely to fire
1191     // over other actions.
1192
1193     const bool liquefied = mons->liquefied_ground();
1194
1195     // Don't allow offscreen throwing for now.
1196     if (mons->foe == MHITYOU && !you.see_cell(mons->pos()))
1197         return false;
1198
1199     // Most monsters won't shoot in melee range, largely for balance reasons.
1200     // Specialist archers are an exception to this rule, though most archers
1201     // lack the M_PREFER_RANGED flag.
1202     if (adjacent(beem.target, mons->pos()))
1203     {
1204         if (!prefer_ranged_attack)
1205             return false;
1206         // Monsters who only can attack with ranged still should. Keep in mind
1207         // that M_PREFER_RANGED only applies if the monster has ammo.
1208     }
1209     else if (!teleport &&
1210                     (liquefied && !master_archer && one_chance_in(9)
1211                      || !liquefied && one_chance_in(master_archer ? 9 : 5)))
1212     {
1213         // Do we fire, or do something else?
1214         // Monsters that are about to teleport will always try to fire.
1215         // If we're standing on liquified ground, try to stand and fire.
1216         //    regular monsters: 8/9 chance to fire. Master archers: always.
1217         // Otherwise, a lower chance of firing vs doing something else.
1218         //    regular monsters: 4/5 chance to fire. Master archers: 8/9 chance.
1219         // TODO: this seems overly complicated, is 4/5 vs 8/9 even noticeable?
1220         return false;
1221     }
1222
1223     // Don't let fleeing (or pacified creatures) stop to shoot at things
1224     if (mons_is_fleeing(*mons) || mons->pacified())
1225         return false;
1226
1227     item_def *launcher = nullptr;
1228     const item_def *weapon = nullptr;
1229     const int mon_item = mons_usable_missile(mons, &launcher);
1230
1231     if (mon_item == NON_ITEM || !env.item[mon_item].defined())
1232         return false;
1233
1234     if (player_or_mon_in_sanct(*mons))
1235         return false;
1236
1237     item_def *missile = &env.item[mon_item];
1238
1239     const actor *act = actor_at(beem.target);
1240     ASSERT(missile->base_type == OBJ_MISSILES);
1241     if (act && missile->sub_type == MI_THROWING_NET)
1242     {
1243         // Throwing a net at a target that is already caught would be
1244         // completely useless, so bail out.
1245         if (act->caught())
1246             return false;
1247         // Netting targets that are already permanently stuck in place
1248         // is similarly useless.
1249         if (mons_class_is_stationary(act->type))
1250             return false;
1251     }
1252
1253     // If the attack needs a launcher that we can't wield, bail out.
1254     if (launcher)
1255     {
1256         weapon = mons->mslot_item(MSLOT_WEAPON);
1257         if (weapon && weapon != launcher && weapon->cursed())
1258             return false;
1259     }
1260
1261     // Ok, we'll try it.
1262     setup_monster_throw_beam(mons, beem);
1263
1264     // Set fake damage for the tracer.
1265     beem.damage = dice_def(10, 10);
1266
1267     // Set item for tracer, even though it probably won't be used
1268     beem.item = missile;
1269
1270     ru_interference interference = DO_NOTHING;
1271     // See if Ru worshippers block or redirect the attack.
1272     if (does_ru_wanna_redirect(mons))
1273     {
1274         interference = get_ru_attack_interference_level();
1275         if (interference == DO_BLOCK_ATTACK)
1276         {
1277             simple_monster_message(*mons,
1278                                 " is stunned by your will and fails to attack.",
1279                                 MSGCH_GOD);
1280             return false;
1281         }
1282         else if (interference == DO_REDIRECT_ATTACK)
1283         {
1284             mprf(MSGCH_GOD, "You redirect %s's attack!",
1285                     mons->name(DESC_THE).c_str());
1286             int pfound = 0;
1287             for (radius_iterator ri(you.pos(),
1288                 LOS_DEFAULT); ri; ++ri)
1289             {
1290                 monster* new_target = monster_at(*ri);
1291
1292                 if (new_target == nullptr
1293                     || mons_is_projectile(new_target->type)
1294                     || mons_is_firewood(*new_target)
1295                     || new_target->friendly())
1296                 {
1297                     continue;
1298                 }
1299
1300                 ASSERT(new_target);
1301
1302                 if (one_chance_in(++pfound))
1303                 {
1304                     mons->target = new_target->pos();
1305                     mons->foe = new_target->mindex();
1306                     beem.target = mons->target;
1307                 }
1308             }
1309         }
1310     }
1311
1312     // Fire tracer.
1313     if (!teleport)
1314         fire_tracer(mons, beem);
1315
1316     // Clear fake damage (will be set correctly in mons_throw).
1317     beem.damage = dice_def();
1318
1319     // Good idea?
1320     if (teleport || mons_should_fire(beem) || interference != DO_NOTHING)
1321     {
1322         if (check_only)
1323             return true;
1324
1325         // Monsters shouldn't shoot if fleeing, so let them "turn to attack".
1326         make_mons_stop_fleeing(mons);
1327
1328         if (launcher && launcher != weapon)
1329             mons->swap_weapons();
1330
1331         beem.name.clear();
1332         return mons_throw(mons, beem, mon_item, teleport);
1333     }
1334
1335     return false;
1336 }
1337
1338 // Give the monster its action energy (aka speed_increment).
1339 static void _monster_add_energy(monster& mons)
1340 {
1341     if (mons.speed > 0)
1342     {
1343         // Randomise to make counting off monster moves harder:
1344         const int energy_gained =
1345             max(1, div_rand_round(mons.speed * you.time_taken, 10));
1346         mons.speed_increment += energy_gained;
1347     }
1348 }
1349
1350 #ifdef DEBUG
1351 #    define DEBUG_ENERGY_USE(problem) \
1352     if (mons->speed_increment == old_energy && mons->alive()) \
1353              mprf(MSGCH_DIAGNOSTICS, \
1354                   problem " for monster '%s' consumed no energy", \
1355                   mons->name(DESC_PLAIN).c_str());
1356 #else
1357 #    define DEBUG_ENERGY_USE(problem) ((void) 0)
1358 #endif
1359
1360 static void _confused_move_dir(monster *mons)
1361 {
1362     mmov.reset();
1363     int pfound = 0;
1364     for (adjacent_iterator ai(mons->pos(), false); ai; ++ai)
1365         if (mons->can_pass_through(*ai) && one_chance_in(++pfound))
1366             mmov = *ai - mons->pos();
1367 }
1368
1369 static int _tentacle_move_speed(monster_type type)
1370 {
1371     if (type == MONS_KRAKEN)
1372         return 10;
1373     else if (type == MONS_TENTACLED_STARSPAWN)
1374         return 18;
1375     else
1376         return 0;
1377 }
1378
1379 static void _pre_monster_move(monster& mons)
1380 {
1381     mons.hit_points = min(mons.max_hit_points, mons.hit_points);
1382
1383     if (mons.type == MONS_SPATIAL_MAELSTROM
1384         && !player_in_branch(BRANCH_ABYSS)
1385         && !player_in_branch(BRANCH_ZIGGURAT))
1386     {
1387         for (int i = 0; i < you.time_taken; ++i)
1388         {
1389             if (one_chance_in(100))
1390             {
1391                 mons.banish(&mons);
1392                 return;
1393             }
1394         }
1395     }
1396
1397     if (mons.has_ench(ENCH_HEXED))
1398     {
1399         const actor* const agent =
1400             actor_by_mid(mons.get_ench(ENCH_HEXED).source);
1401         if (!agent || !agent->alive())
1402             mons.del_ench(ENCH_HEXED);
1403     }
1404
1405     if (mons.type == MONS_SNAPLASHER_VINE
1406         && mons.props.exists("vine_awakener"))
1407     {
1408         monster* awakener = monster_by_mid(mons.props["vine_awakener"].get_int());
1409         if (awakener && !awakener->can_see(mons))
1410         {
1411             simple_monster_message(mons, " falls limply to the ground.");
1412             monster_die(mons, KILL_RESET, NON_MONSTER);
1413             return;
1414         }
1415     }
1416
1417     // Dissipate player ball lightnings and foxfires
1418     // that have left the player's sight
1419     // (monsters are allowed to 'cheat', as with orb of destruction)
1420     if ((mons.type == MONS_BALL_LIGHTNING || mons.type == MONS_FOXFIRE)
1421         && mons.summoner == MID_PLAYER
1422         && !cell_see_cell(you.pos(), mons.pos(), LOS_SOLID))
1423     {
1424         if (mons.type == MONS_FOXFIRE)
1425             check_place_cloud(CLOUD_FLAME, mons.pos(), 2, &mons);
1426         monster_die(mons, KILL_RESET, NON_MONSTER);
1427         return;
1428     }
1429
1430     if (mons_stores_tracking_data(mons))
1431     {
1432         actor* foe = mons.get_foe();
1433         if (foe)
1434         {
1435             if (!mons.props.exists("foe_pos"))
1436                 mons.props["foe_pos"].get_coord() = foe->pos();
1437             else
1438             {
1439                 if (mons.props["foe_pos"].get_coord().distance_from(mons.pos())
1440                     > foe->pos().distance_from(mons.pos()))
1441                 {
1442                     mons.props["foe_approaching"].get_bool() = true;
1443                 }
1444                 else
1445                     mons.props["foe_approaching"].get_bool() = false;
1446
1447                 mons.props["foe_pos"].get_coord() = foe->pos();
1448             }
1449         }
1450         else
1451             mons.props.erase("foe_pos");
1452     }
1453
1454     reset_battlesphere(&mons);
1455     reset_spectral_weapon(&mons);
1456
1457     fedhas_neutralise(&mons);
1458     slime_convert(&mons);
1459
1460     // Monster just summoned (or just took stairs), skip this action.
1461     if (testbits(mons.flags, MF_JUST_SUMMONED))
1462     {
1463         mons.flags &= ~MF_JUST_SUMMONED;
1464         return;
1465     }
1466
1467     mon_acting mact(&mons);
1468
1469     _monster_add_energy(mons);
1470
1471     // Handle clouds on nonmoving monsters.
1472     if (mons.speed == 0)
1473     {
1474         _mons_in_cloud(mons);
1475
1476         // Update constriction durations
1477         mons.accum_has_constricted();
1478
1479         if (mons.type == MONS_NO_MONSTER)
1480             return;
1481     }
1482
1483     // Apply monster enchantments once for every normal-speed
1484     // player turn.
1485     mons.ench_countdown -= you.time_taken;
1486     while (mons.ench_countdown < 0)
1487     {
1488         mons.ench_countdown += 10;
1489         mons.apply_enchantments();
1490
1491         // If the monster *merely* died just break from the loop
1492         // rather than quit altogether, since we have to deal with
1493         // ballistomycete spores and ball lightning exploding at the end of the
1494         // function, but do return if the monster's data has been
1495         // reset, since then the monster type is invalid.
1496         if (mons.type == MONS_NO_MONSTER)
1497             return;
1498         else if (mons.hit_points < 1)
1499             break;
1500     }
1501
1502     // Memory is decremented here for a reason -- we only want it
1503     // decrementing once per monster "move".
1504     if (mons.foe_memory > 0 && !you.penance[GOD_ASHENZARI])
1505         mons.foe_memory -= you.time_taken;
1506
1507     // Otherwise there are potential problems with summonings.
1508     if (mons.type == MONS_GLOWING_SHAPESHIFTER)
1509         mons.add_ench(ENCH_GLOWING_SHAPESHIFTER);
1510
1511     if (mons.type == MONS_SHAPESHIFTER)
1512         mons.add_ench(ENCH_SHAPESHIFTER);
1513
1514     mons.check_speed();
1515
1516     // spellforged servitors lose an extra random2(16) energy per turn, often
1517     // causing them to skip a turn. Show this message to give the player some
1518     // feedback on what is going on when a servitor skips an attack due to
1519     // random energy loss (otherwise, it just sits there silently).
1520     // TODO: could this effect be implemented in some way other than energy?
1521     if (mons.type == MONS_SPELLFORGED_SERVITOR && mons.foe != MHITNOT
1522         && !mons.has_action_energy())
1523     {
1524         simple_monster_message(mons, " hums quietly as it recharges.");
1525     }
1526 }
1527
1528 void handle_monster_move(monster* mons)
1529 {
1530     ASSERT(mons); // XXX: change to monster &mons
1531     const monsterentry* entry = get_monster_data(mons->type);
1532     if (!entry)
1533         return;
1534
1535     const bool disabled = crawl_state.disables[DIS_MON_ACT]
1536                           && _unfriendly_or_impaired(*mons);
1537
1538     int old_energy      = mons->speed_increment;
1539     int non_move_energy = min(entry->energy_usage.move,
1540                               entry->energy_usage.swim);
1541
1542 #ifdef DEBUG_MONS_SCAN
1543     bool monster_was_floating = env.mgrid(mons->pos()) != mons->mindex();
1544 #endif
1545     coord_def old_pos = mons->pos();
1546
1547     if (!mons->has_action_energy())
1548         return;
1549
1550     if (!disabled)
1551         move_solo_tentacle(mons);
1552
1553     if (!mons->alive())
1554         return;
1555
1556     if (!disabled && mons_is_tentacle_head(mons_base_type(*mons)))
1557         move_child_tentacles(mons);
1558
1559     old_pos = mons->pos();
1560
1561 #ifdef DEBUG_MONS_SCAN
1562     if (!monster_was_floating
1563         && env.mgrid(mons->pos()) != mons->mindex())
1564     {
1565         mprf(MSGCH_ERROR, "Monster %s became detached from env.mgrid "
1566                           "in handle_monster_move() loop",
1567              mons->name(DESC_PLAIN, true).c_str());
1568         mprf(MSGCH_WARN, "[[[[[[[[[[[[[[[[[[");
1569         debug_mons_scan();
1570         mprf(MSGCH_WARN, "]]]]]]]]]]]]]]]]]]");
1571         monster_was_floating = true;
1572     }
1573     else if (monster_was_floating
1574              && env.mgrid(mons->pos()) == mons->mindex())
1575     {
1576         mprf(MSGCH_DIAGNOSTICS, "Monster %s re-attached itself to env.mgrid "
1577                                 "in handle_monster_move() loop",
1578              mons->name(DESC_PLAIN, true).c_str());
1579         monster_was_floating = false;
1580     }
1581 #endif
1582
1583     if (mons_is_projectile(*mons))
1584     {
1585         if (iood_act(*mons))
1586             return;
1587         mons->lose_energy(EUT_MOVE);
1588         return;
1589     }
1590
1591     if (mons->type == MONS_BATTLESPHERE)
1592     {
1593         if (fire_battlesphere(mons))
1594             mons->lose_energy(EUT_SPECIAL);
1595     }
1596
1597     if (mons->type == MONS_FULMINANT_PRISM)
1598     {
1599         ++mons->prism_charge;
1600         if (mons->prism_charge == 2)
1601             mons->suicide();
1602         else
1603         {
1604             if (player_can_hear(mons->pos()))
1605             {
1606                 if (you.can_see(*mons))
1607                 {
1608                     simple_monster_message(*mons, " crackles loudly.",
1609                                            MSGCH_WARN);
1610                 }
1611                 else
1612                     mprf(MSGCH_SOUND, "You hear a loud crackle.");
1613             }
1614             // Done this way to keep the detonation timer predictable
1615             mons->speed_increment -= BASELINE_DELAY;
1616         }
1617         return;
1618     }
1619
1620     if (mons->type == MONS_FOXFIRE)
1621     {
1622         if (mons->steps_remaining == 0)
1623         {
1624             check_place_cloud(CLOUD_FLAME, mons->pos(), 2, mons);
1625             mons->suicide();
1626             return;
1627         }
1628     }
1629
1630     mons->shield_blocks = 0;
1631
1632     _mons_in_cloud(*mons);
1633     actor_apply_toxic_bog(mons);
1634
1635     if (!mons->alive())
1636         return;
1637
1638     if (env.level_state & LSTATE_SLIMY_WALL)
1639         slime_wall_damage(mons, speed_to_duration(mons->speed));
1640
1641     if (!mons->alive())
1642         return;
1643
1644     if (env.level_state & LSTATE_ICY_WALL)
1645         ice_wall_damage(*mons, speed_to_duration(mons->speed));
1646
1647     if (!mons->alive())
1648         return;
1649
1650     if (mons->type == MONS_TIAMAT && one_chance_in(3))
1651         draconian_change_colour(mons);
1652
1653     _monster_regenerate(mons);
1654
1655     // Please change _slouch_damage to match!
1656     if (mons->cannot_act()
1657         || mons->type == MONS_SIXFIRHY // these move only 8 of 24 turns
1658             && ++mons->move_spurt / 8 % 3 != 2  // but are not helpless
1659         || mons->type == MONS_JIANGSHI // similarly, but more irregular (48 of 90)
1660             && (++mons->move_spurt / 6 % 3 == 1 || mons->move_spurt / 3 % 5 == 1))
1661     {
1662         mons->speed_increment -= non_move_energy;
1663         return;
1664     }
1665
1666     if (mons->has_ench(ENCH_DAZED) && one_chance_in(4))
1667     {
1668         simple_monster_message(*mons, " is lost in a daze.");
1669         mons->speed_increment -= non_move_energy;
1670         return;
1671     }
1672
1673     if (mons->has_ench(ENCH_GOLD_LUST))
1674     {
1675         mons->speed_increment -= non_move_energy;
1676         return;
1677     }
1678
1679     if (mons->has_ench(ENCH_BRILLIANCE_AURA))
1680         aura_of_brilliance(mons);
1681
1682     if (you.duration[DUR_GOZAG_GOLD_AURA]
1683         && have_passive(passive_t::gold_aura)
1684         && you.see_cell(mons->pos())
1685         && !mons->asleep()
1686         && !mons_is_conjured(mons->type)
1687         && !mons_is_tentacle_or_tentacle_segment(mons->type)
1688         && !mons_is_firewood(*mons)
1689         && !mons->wont_attack())
1690     {
1691         const int gold = you.props[GOZAG_GOLD_AURA_KEY].get_int();
1692         if (bernoulli(gold, 3.0/100.0))
1693         {
1694             if (gozag_gold_in_los(mons))
1695             {
1696                 simple_monster_message(*mons,
1697                     " becomes distracted by the nearby gold, dreaming of "
1698                     "imaginary riches.");
1699             }
1700             else if (you.gold > 0)
1701             {
1702                 simple_monster_message(*mons,
1703                     " becomes distracted by your gold, dreaming of "
1704                     "imaginary riches.");
1705             }
1706             else
1707             {
1708                 // Just in case!
1709                 simple_monster_message(*mons,
1710                             " is distracted by dreams of imaginary riches.");
1711             }
1712
1713             mons->add_ench(
1714                 mon_enchant(ENCH_GOLD_LUST, 1, nullptr,
1715                             random_range(1, 5) * BASELINE_DELAY));
1716             mons->foe = MHITNOT;
1717             mons->target = mons->pos();
1718             mons->speed_increment -= non_move_energy;
1719             return;
1720         }
1721     }
1722
1723     if (disabled)
1724     {
1725         mons->speed_increment -= non_move_energy;
1726         return;
1727     }
1728
1729     handle_behaviour(mons);
1730
1731     // handle_behaviour() could make the monster leave the level.
1732     if (!mons->alive())
1733         return;
1734
1735     ASSERT(!crawl_state.game_is_arena() || mons->foe != MHITYOU);
1736     ASSERT_IN_BOUNDS_OR_ORIGIN(mons->target);
1737
1738     if (mons->speed >= 100)
1739     {
1740         mons->speed_increment -= non_move_energy;
1741         return;
1742     }
1743
1744     if (_handle_pickup(mons))
1745     {
1746         DEBUG_ENERGY_USE("handle_pickup()");
1747         return;
1748     }
1749
1750     // Lurking monsters only stop lurking if their target is right
1751     // next to them, otherwise they just sit there.
1752     if (mons->has_ench(ENCH_SUBMERGED))
1753     {
1754         if (mons->foe != MHITNOT
1755             && grid_distance(mons->target, mons->pos()) <= 1)
1756         {
1757             if (mons->submerged())
1758             {
1759                 if (!mons->del_ench(ENCH_SUBMERGED))
1760                 {
1761                     // Couldn't unsubmerge.
1762                     mons->speed_increment -= non_move_energy;
1763                     return;
1764                 }
1765             }
1766             mons->behaviour = BEH_SEEK;
1767         }
1768         else
1769         {
1770             mons->speed_increment -= non_move_energy;
1771             return;
1772         }
1773     }
1774
1775     if (mons->caught())
1776     {
1777         // Struggling against the net takes time.
1778         _swim_or_move_energy(*mons);
1779     }
1780     else if (!mons->petrified())
1781     {
1782         // Calculates mmov based on monster target.
1783         _handle_movement(mons);
1784
1785         // Confused monsters sometimes stumble about instead of moving with
1786         // purpose.
1787         if (mons_is_confused(*mons) && !one_chance_in(3))
1788         {
1789             set_random_target(mons);
1790             _confused_move_dir(mons);
1791         }
1792     }
1793     if (!mons->asleep() && !mons->submerged())
1794         maybe_mons_speaks(mons);
1795
1796     if (!mons->alive())
1797         return;
1798
1799     // XXX: A bit hacky, but stores where we WILL move, if we don't take
1800     //      another action instead (used for decision-making)
1801     if (mons_stores_tracking_data(*mons))
1802         mons->props["mmov"].get_coord() = mmov;
1803
1804     if (!mons->asleep() && !mons_is_wandering(*mons)
1805         // Berserking monsters are limited to running up and
1806         // hitting their foes.
1807         && !mons->berserk_or_insane()
1808         // Slime creatures can split while wandering or resting.
1809         || mons->type == MONS_SLIME_CREATURE)
1810     {
1811         // Prevents unfriendlies from nuking you from offscreen.
1812         // How nice!
1813         const bool friendly_or_near =
1814             mons->friendly() && mons->foe == MHITYOU || mons->near_foe();
1815         if (friendly_or_near
1816             || mons->type == MONS_TEST_SPAWNER
1817             // Slime creatures can split when offscreen.
1818             || mons->type == MONS_SLIME_CREATURE
1819             // Let monsters who have Awaken Earth use it off-screen.
1820             || mons->has_spell(SPELL_AWAKEN_EARTH)
1821             )
1822         {
1823             // [ds] Special abilities shouldn't overwhelm
1824             // spellcasting in monsters that have both. This aims
1825             // to give them both roughly the same weight.
1826             if (coinflip() ? mon_special_ability(mons) || _do_mon_spell(mons)
1827                            : _do_mon_spell(mons) || mon_special_ability(mons))
1828             {
1829                 DEBUG_ENERGY_USE("spell or special");
1830                 mmov.reset();
1831                 return;
1832             }
1833         }
1834
1835         const bool prefer_ranged = mons_class_flag(mons->type, M_PREFER_RANGED);
1836
1837         if (friendly_or_near)
1838         {
1839             if (_handle_potion(*mons))
1840             {
1841                 DEBUG_ENERGY_USE("_handle_potion()");
1842                 return;
1843             }
1844
1845             if (_handle_scroll(*mons))
1846             {
1847                 DEBUG_ENERGY_USE("_handle_scroll()");
1848                 return;
1849             }
1850
1851             if (_handle_evoke_equipment(*mons))
1852             {
1853                 DEBUG_ENERGY_USE("_handle_evoke_equipment()");
1854                 return;
1855             }
1856
1857             if (_handle_wand(*mons))
1858             {
1859                 DEBUG_ENERGY_USE("_handle_wand()");
1860                 return;
1861             }
1862
1863             if (_handle_swoop(*mons))
1864             {
1865                 DEBUG_ENERGY_USE("_handle_swoop()");
1866                 return;
1867             }
1868
1869             // we want to let M_PREFER_RANGED monsters try their ranged attack
1870             // first, even if within reaching range.
1871             if (!prefer_ranged && _handle_reaching(mons))
1872             {
1873                 DEBUG_ENERGY_USE("_handle_reaching()");
1874                 return;
1875             }
1876         }
1877
1878         bolt beem = setup_targetting_beam(*mons);
1879         if (handle_throw(mons, beem, false, false))
1880         {
1881             DEBUG_ENERGY_USE("_handle_throw()");
1882             return;
1883         }
1884
1885         if (friendly_or_near && prefer_ranged && _handle_reaching(mons))
1886         {
1887             DEBUG_ENERGY_USE("_handle_reaching()");
1888             return;
1889         }
1890     }
1891
1892     if (!mons->caught())
1893     {
1894         if (mons->pos() + mmov == you.pos())
1895         {
1896             ASSERT(!crawl_state.game_is_arena());
1897
1898             if (_unfriendly_or_impaired(*mons)
1899                 && !mons->has_ench(ENCH_CHARM)
1900                 && !mons->has_ench(ENCH_HEXED))
1901             {
1902                 monster* new_target = 0;
1903                 if (!mons->wont_attack())
1904                 {
1905                     // Otherwise, if it steps into you, cancel other targets.
1906                     mons->foe = MHITYOU;
1907                     mons->target = you.pos();
1908
1909                     // Check to see if your religion redirects the attack
1910                     if (does_ru_wanna_redirect(mons))
1911                     {
1912                         ru_interference interference =
1913                                 get_ru_attack_interference_level();
1914                         if (interference == DO_BLOCK_ATTACK)
1915                         {
1916                             simple_monster_message(*mons,
1917                                 " is stunned by your will and fails to attack.",
1918                                 MSGCH_GOD);
1919                             mons->speed_increment -= non_move_energy;
1920                             return;
1921                         }
1922                         else if (interference == DO_REDIRECT_ATTACK)
1923                         {
1924                             // get a target
1925                             int pfound = 0;
1926                             for (adjacent_iterator ai(mons->pos(), false); ai; ++ai)
1927                             {
1928                                 monster* candidate = monster_at(*ai);
1929                                 if (candidate == nullptr
1930                                     || mons_is_projectile(candidate->type)
1931                                     || mons_is_firewood(*candidate)
1932                                     || candidate->friendly())
1933                                 {
1934                                     continue;
1935                                 }
1936                                 ASSERT(candidate);
1937                                 if (one_chance_in(++pfound))
1938                                     new_target = candidate;
1939                             }
1940                         }
1941                     }
1942                 }
1943
1944                 if (new_target)
1945                 {
1946                     // attack that target
1947                     mons->target = new_target->pos();
1948                     mons->foe = new_target->mindex();
1949                     mprf(MSGCH_GOD, "You redirect %s's attack!",
1950                          mons->name(DESC_THE).c_str());
1951                     fight_melee(mons, new_target);
1952                 }
1953                 else
1954                     fight_melee(mons, &you);
1955
1956                 if (mons_is_batty(*mons))
1957                     _be_batty(*mons);
1958                 DEBUG_ENERGY_USE("fight_melee()");
1959                 mmov.reset();
1960                 return;
1961             }
1962         }
1963
1964         // See if we move into (and fight) an unfriendly monster.
1965         monster* targ = monster_at(mons->pos() + mmov);
1966
1967         //If a tentacle owner is attempting to move into an adjacent
1968         //segment, kill the segment and adjust connectivity data.
1969         if (targ && mons_tentacle_adjacent(mons, targ))
1970         {
1971             const bool basis = targ->props.exists("outwards");
1972             monster* outward =  basis ? monster_by_mid(targ->props["outwards"].get_int()) : nullptr;
1973             if (outward)
1974                 outward->props["inwards"].get_int() = mons->mid;
1975
1976             monster_die(*targ, KILL_MISC, NON_MONSTER, true);
1977             targ = nullptr;
1978         }
1979
1980         if (targ
1981             && targ != mons
1982             && mons->behaviour != BEH_WITHDRAW
1983             && (!(mons_aligned(mons, targ) || targ->type == MONS_FOXFIRE)
1984                 || mons->has_ench(ENCH_INSANE))
1985             && monster_can_hit_monster(mons, targ))
1986         {
1987             // Maybe they can swap places?
1988             if (_swap_monsters(*mons, *targ))
1989             {
1990                 _swim_or_move_energy(*mons);
1991                 return;
1992             }
1993             // Figure out if they fight.
1994             else if ((!mons_is_firewood(*targ)
1995                       || mons->is_child_tentacle())
1996                           && fight_melee(mons, targ))
1997             {
1998                 if (mons_is_batty(*mons))
1999                     _be_batty(*mons);
2000
2001                 mmov.reset();
2002                 DEBUG_ENERGY_USE("fight_melee()");
2003                 return;
2004             }
2005         }
2006         else if (mons->behaviour == BEH_WITHDRAW
2007                  && ((targ && targ != mons && targ->friendly())
2008                       || (you.pos() == mons->pos() + mmov)))
2009         {
2010             // Don't count turns spent blocked by friendly creatures
2011             // (or the player) as an indication that we're stuck
2012             mons->props.erase("blocked_deadline");
2013         }
2014
2015         if (invalid_monster(mons) || mons->is_stationary())
2016         {
2017             if (mons->speed_increment == old_energy)
2018                 mons->speed_increment -= non_move_energy;
2019             return;
2020         }
2021
2022         if (mons->cannot_move() || !_monster_move(mons))
2023             mons->speed_increment -= non_move_energy;
2024     }
2025     you.update_beholder(mons);
2026     you.update_fearmonger(mons);
2027
2028     // Reevaluate behaviour, since the monster's surroundings have
2029     // changed (it may have moved, or died for that matter). Don't
2030     // bother for dead monsters.  :)
2031     if (mons->alive())
2032     {
2033         handle_behaviour(mons);
2034         ASSERT_IN_BOUNDS_OR_ORIGIN(mons->target);
2035     }
2036
2037     if (mons_is_tentacle_head(mons_base_type(*mons)))
2038     {
2039         move_child_tentacles(mons);
2040
2041         mons->move_spurt += (old_energy - mons->speed_increment)
2042                              * _tentacle_move_speed(mons_base_type(*mons));
2043         ASSERT(mons->move_spurt > 0);
2044         while (mons->move_spurt >= 100)
2045         {
2046             move_child_tentacles(mons);
2047             mons->move_spurt -= 100;
2048         }
2049     }
2050 }
2051
2052 /**
2053  * Let trapped monsters struggle against nets, webs, etc.
2054  */
2055 void monster::struggle_against_net()
2056 {
2057     if (is_stationary() || cannot_act() || asleep())
2058         return;
2059
2060     if (props.exists(NEWLY_TRAPPED_KEY))
2061     {
2062         props.erase(NEWLY_TRAPPED_KEY);
2063         return; // don't try to escape on the same turn you were trapped!
2064     }
2065
2066     int net = get_trapping_net(pos(), true);
2067
2068     if (net == NON_ITEM)
2069     {
2070         trap_def *trap = trap_at(pos());
2071         if (trap && trap->type == TRAP_WEB)
2072         {
2073             if (coinflip())
2074             {
2075                 if (you.see_cell(pos()))
2076                 {
2077                     if (!visible_to(&you))
2078                         mpr("Something you can't see is thrashing in a web.");
2079                     else
2080                         simple_monster_message(*this,
2081                                            " struggles to get unstuck from the web.");
2082                 }
2083                 return;
2084             }
2085         }
2086         monster_web_cleanup(*this);
2087         del_ench(ENCH_HELD);
2088         return;
2089     }
2090
2091     if (you.see_cell(pos()))
2092     {
2093         if (!visible_to(&you))
2094             mpr("Something wriggles in the net.");
2095         else
2096             simple_monster_message(*this, " struggles against the net.");
2097     }
2098
2099     int damage = 1 + random2(2);
2100
2101     // Faster monsters can damage the net more often per
2102     // time period.
2103     if (speed != 0)
2104         damage = div_rand_round(damage * speed, 10);
2105
2106     env.item[net].net_durability -= damage;
2107
2108     if (env.item[net].net_durability < NET_MIN_DURABILITY)
2109     {
2110         if (you.see_cell(pos()))
2111         {
2112             if (visible_to(&you))
2113             {
2114                 mprf("The net rips apart, and %s comes free!",
2115                      name(DESC_THE).c_str());
2116             }
2117             else
2118                 mpr("All of a sudden the net rips apart!");
2119         }
2120         destroy_item(net);
2121
2122         del_ench(ENCH_HELD, true);
2123     }
2124 }
2125
2126 static void _ancient_zyme_sicken(monster* mons)
2127 {
2128     if (is_sanctuary(mons->pos()))
2129         return;
2130
2131     if (!is_sanctuary(you.pos())
2132         && !mons->wont_attack()
2133         && you.res_rotting() <= 0
2134         && !you.duration[DUR_DIVINE_STAMINA]
2135         && cell_see_cell(you.pos(), mons->pos(), LOS_SOLID_SEE))
2136     {
2137         if (!you.disease)
2138         {
2139             if (!you.duration[DUR_SICKENING])
2140             {
2141                 mprf(MSGCH_WARN, "You feel yourself growing ill in the "
2142                                  "presence of %s.",
2143                     mons->name(DESC_THE).c_str());
2144             }
2145
2146             you.duration[DUR_SICKENING] += (2 + random2(4)) * BASELINE_DELAY;
2147             if (you.duration[DUR_SICKENING] > 100)
2148             {
2149                 you.sicken(40 + random2(30));
2150                 you.duration[DUR_SICKENING] = 0;
2151             }
2152         }
2153         else
2154         {
2155             if (x_chance_in_y(you.time_taken, 60))
2156                 you.sicken(15 + random2(30));
2157         }
2158     }
2159
2160     for (radius_iterator ri(mons->pos(), LOS_RADIUS, C_SQUARE); ri; ++ri)
2161     {
2162         monster *m = monster_at(*ri);
2163         if (m && !mons_aligned(mons, m)
2164             && cell_see_cell(mons->pos(), *ri, LOS_SOLID_SEE)
2165             && !is_sanctuary(*ri))
2166         {
2167             m->sicken(2 * you.time_taken);
2168         }
2169     }
2170 }
2171
2172 /**
2173  * Apply the torpor snail slowing effect.
2174  *
2175  * @param mons      The snail applying the effect.
2176  */
2177 static void _torpor_snail_slow(monster* mons)
2178 {
2179     // XXX: might be nice to refactor together with _ancient_zyme_sicken().
2180     // XXX: also with torpor_slowed().... so many duplicated checks :(
2181
2182     if (is_sanctuary(mons->pos())
2183         || mons->attitude != ATT_HOSTILE
2184         || mons->has_ench(ENCH_CHARM))
2185     {
2186         return;
2187     }
2188
2189     if (!is_sanctuary(you.pos())
2190         && !you.stasis()
2191         && cell_see_cell(you.pos(), mons->pos(), LOS_SOLID_SEE))
2192     {
2193         if (!you.duration[DUR_SLOW])
2194         {
2195             mprf("Being near %s leaves you feeling lethargic.",
2196                  mons->name(DESC_THE).c_str());
2197         }
2198
2199         if (you.duration[DUR_SLOW] <= 1)
2200             you.set_duration(DUR_SLOW, 1);
2201         you.props[TORPOR_SLOWED_KEY] = true;
2202     }
2203
2204     for (monster_near_iterator ri(mons->pos(), LOS_SOLID_SEE); ri; ++ri)
2205     {
2206         monster *m = *ri;
2207         if (m && !mons_aligned(mons, m) && !m->stasis()
2208             && !mons_is_conjured(m->type) && !m->is_stationary()
2209             && !is_sanctuary(m->pos()))
2210         {
2211             m->add_ench(mon_enchant(ENCH_SLOW, 0, mons, 1));
2212             m->props[TORPOR_SLOWED_KEY] = true;
2213         }
2214     }
2215 }
2216
2217 static void _post_monster_move(monster* mons)
2218 {
2219     if (invalid_monster(mons))
2220         return;
2221
2222     mons->handle_constriction();
2223
2224     if (mons->has_ench(ENCH_HELD))
2225         mons->struggle_against_net();
2226
2227     if (mons->type == MONS_ANCIENT_ZYME)
2228         _ancient_zyme_sicken(mons);
2229
2230     if (mons->type == MONS_TORPOR_SNAIL)
2231         _torpor_snail_slow(mons);
2232
2233     if (mons->type == MONS_WATER_NYMPH)
2234     {
2235         for (adjacent_iterator ai(mons->pos(), false); ai; ++ai)
2236             if (feat_has_solid_floor(env.grid(*ai))
2237                 && (coinflip() || *ai == mons->pos()))
2238             {
2239                 if (env.grid(*ai) != DNGN_SHALLOW_WATER && env.grid(*ai) != DNGN_FLOOR
2240                     && you.see_cell(*ai))
2241                 {
2242                     mprf("%s watery aura covers %s.",
2243                          apostrophise(mons->name(DESC_THE)).c_str(),
2244                          feature_description_at(*ai, false, DESC_THE).c_str());
2245                 }
2246                 temp_change_terrain(*ai, DNGN_SHALLOW_WATER, random_range(50, 80),
2247                                     TERRAIN_CHANGE_FLOOD, mons);
2248             }
2249     }
2250
2251     if (mons->type == MONS_GUARDIAN_GOLEM)
2252         guardian_golem_bond(*mons);
2253
2254     // A rakshasa that has regained full health dismisses its emergency clones
2255     // (if they're somehow still alive) and regains the ability to summon new ones.
2256     if (mons->type == MONS_RAKSHASA && mons->hit_points == mons->max_hit_points
2257         && !mons->has_ench(ENCH_PHANTOM_MIRROR)
2258         && mons->props.exists("emergency_clone"))
2259     {
2260         mons->props.erase("emergency_clone");
2261         for (monster_iterator mi; mi; ++mi)
2262         {
2263             if (mi->type == MONS_RAKSHASA && mi->summoner == mons->mid)
2264                 mi->del_ench(ENCH_ABJ);
2265         }
2266     }
2267
2268     update_mons_cloud_ring(mons);
2269
2270     const item_def * weapon = mons->mslot_item(MSLOT_WEAPON);
2271     if (weapon && get_weapon_brand(*weapon) == SPWPN_SPECTRAL
2272         && !mons_is_avatar(mons->type)
2273         && !find_spectral_weapon(mons))
2274     {
2275         cast_spectral_weapon(mons, mons->get_experience_level() * 4, mons->god);
2276     }
2277
2278     if (mons->foe != MHITNOT && mons_is_wandering(*mons) && mons_is_batty(*mons))
2279     {
2280         int &bat_turns = mons->props[BATTY_TURNS_KEY].get_int();
2281         bat_turns++;
2282         int turns_to_bat = div_rand_round(mons_base_speed(*mons), 10);
2283         if (turns_to_bat < 2)
2284             turns_to_bat = 2;
2285         if (bat_turns >= turns_to_bat)
2286             mons->behaviour = BEH_SEEK;
2287     }
2288
2289     if (mons->type != MONS_NO_MONSTER && mons->hit_points < 1)
2290         monster_die(*mons, KILL_MISC, NON_MONSTER);
2291 }
2292
2293 priority_queue<pair<monster *, int>,
2294                vector<pair<monster *, int> >,
2295                MonsterActionQueueCompare> monster_queue;
2296
2297 // Inserts a monster into the monster queue (needed to ensure that any monsters
2298 // given energy or an action by a effect can actually make use of that energy
2299 // this round)
2300 void queue_monster_for_action(monster* mons)
2301 {
2302     monster_queue.emplace(mons, mons->speed_increment);
2303 }
2304
2305 static void _clear_monster_flags()
2306 {
2307     // Clear any summoning flags so that lower indiced
2308     // monsters get their actions in the next round.
2309     // Also clear one-turn deep sleep flag.
2310     // XXX: MF_JUST_SLEPT only really works for player-cast hibernation.
2311     for (auto &mons : menv_real)
2312         mons.flags &= ~MF_JUST_SUMMONED & ~MF_JUST_SLEPT;
2313 }
2314
2315 /**
2316 * On each monster turn, check to see if we need to update monster attitude.
2317 * At the time of writing, it just checks for MUT_NO_LOVE from Ru Sacrifice Love.
2318 *
2319 * @param mon     The targeted monster
2320 * @return        Void
2321 **/
2322 static void _update_monster_attitude(monster *mon)
2323 {
2324     if (you.get_mutation_level(MUT_NO_LOVE)
2325         && !mons_is_conjured(mon->type))
2326     {
2327         mon->attitude = ATT_HOSTILE;
2328     }
2329 }
2330
2331 vector<monster *> just_seen_queue;
2332
2333 void mons_set_just_seen(monster *mon)
2334 {
2335     mon->seen_context = SC_JUST_SEEN;
2336     just_seen_queue.push_back(mon);
2337 }
2338
2339 void mons_reset_just_seen()
2340 {
2341     // this may be called when the pointers are not valid, so don't mess with
2342     // seen_context.
2343     just_seen_queue.clear();
2344 }
2345
2346 static void _display_just_seen()
2347 {
2348     // these are monsters that were marked as SC_JUST_SEEN at some point since
2349     // last time this was called. We announce any that leave all at once so
2350     // as to handle monsters that may move multiple times per world_reacts.
2351     if (in_bounds(you.pos()))
2352     {
2353         for (auto m : just_seen_queue)
2354         {
2355             if (!m || invalid_monster(m) || !m->alive())
2356                 continue;
2357             // can't use simple_monster_message here, because m is out of view.
2358             // The monster should be visible to be in this queue.
2359             if (in_bounds(m->pos()) && !you.see_cell(m->pos()))
2360             {
2361                 mprf(MSGCH_PLAIN, "%s moves out of view.",
2362                      m->name(DESC_THE, true).c_str());
2363             }
2364         }
2365     }
2366     mons_reset_just_seen();
2367 }
2368
2369 /**
2370  * Get all monsters to make an action, if they can/want to.
2371  *
2372  * @param with_noise whether to process noises after the loop.
2373  */
2374 void handle_monsters(bool with_noise)
2375 {
2376     for (monster_iterator mi; mi; ++mi)
2377     {
2378         _pre_monster_move(**mi);
2379         if (!invalid_monster(*mi) && mi->alive() && mi->has_action_energy())
2380             monster_queue.emplace(*mi, mi->speed_increment);
2381     }
2382
2383     int tries = 0; // infinite loop protection, shouldn't be ever needed
2384     while (!monster_queue.empty())
2385     {
2386         if (tries++ > 32767)
2387         {
2388             die("infinite handle_monsters() loop, mons[0 of %d] is %s",
2389                 (int)monster_queue.size(),
2390                 monster_queue.top().first->name(DESC_PLAIN, true).c_str());
2391         }
2392
2393         monster *mon = monster_queue.top().first;
2394         const int oldspeed = monster_queue.top().second;
2395         monster_queue.pop();
2396
2397         if (invalid_monster(mon) || !mon->alive() || !mon->has_action_energy())
2398             continue;
2399
2400         _update_monster_attitude(mon);
2401
2402         // Only move the monster if nothing else has played with its energy
2403         // during their turn.
2404         // If something's played with the energy, they get added back to
2405         // the queue just after this.
2406         if (oldspeed == mon->speed_increment)
2407         {
2408             handle_monster_move(mon);
2409             _post_monster_move(mon);
2410             fire_final_effects();
2411         }
2412
2413         if (mon->has_action_energy())
2414             monster_queue.emplace(mon, mon->speed_increment);
2415
2416         // If the player got banished, discard pending monster actions.
2417         if (you.banished)
2418         {
2419             // Clear list of mesmerising monsters.
2420             you.clear_beholders();
2421             you.clear_fearmongers();
2422             you.stop_constricting_all();
2423             you.stop_being_constricted();
2424             break;
2425         }
2426     }
2427     _display_just_seen();
2428
2429     // Process noises now (before clearing the sleep flag).
2430     if (with_noise)
2431         apply_noises();
2432
2433     _clear_monster_flags();
2434 }
2435
2436 static bool _jelly_divide(monster& parent)
2437 {
2438     if (!mons_class_flag(parent.type, M_SPLITS))
2439         return false;
2440
2441     const int reqd = max(parent.get_experience_level() * 8, 50);
2442     if (parent.hit_points < reqd)
2443         return false;
2444
2445     monster* child = nullptr;
2446     coord_def child_spot;
2447     int num_spots = 0;
2448
2449     // First, find a suitable spot for the child {dlb}:
2450     for (adjacent_iterator ai(parent.pos()); ai; ++ai)
2451         if (actor_at(*ai) == nullptr && parent.can_pass_through(*ai)
2452             && one_chance_in(++num_spots))
2453         {
2454             child_spot = *ai;
2455         }
2456
2457     if (num_spots == 0)
2458         return false;
2459
2460     // Now that we have a spot, find a monster slot {dlb}:
2461     child = get_free_monster();
2462     if (!child)
2463         return false;
2464
2465     // Handle impact of split on parent {dlb}:
2466     parent.max_hit_points /= 2;
2467
2468     if (parent.hit_points > parent.max_hit_points)
2469         parent.hit_points = parent.max_hit_points;
2470
2471     parent.init_experience();
2472     parent.experience = parent.experience * 3 / 5 + 1;
2473
2474     // Create child {dlb}:
2475     // This is terribly partial and really requires
2476     // more thought as to generation ... {dlb}
2477     *child = parent;
2478     child->max_hit_points  = child->hit_points;
2479     child->speed_increment = 70 + random2(5);
2480     child->set_new_monster_id();
2481     child->move_to_pos(child_spot);
2482
2483     if (!simple_monster_message(parent, " splits in two!")
2484         && (player_can_hear(parent.pos()) || player_can_hear(child->pos())))
2485     {
2486         mprf(MSGCH_SOUND, "You hear a squelching noise.");
2487     }
2488
2489     if (crawl_state.game_is_arena())
2490         arena_placed_monster(child);
2491
2492     return true;
2493 }
2494
2495 // Only Jiyva jellies eat items.
2496 static bool _monster_eat_item(monster* mons)
2497 {
2498     if (!mons_eats_items(*mons))
2499         return false;
2500
2501     // Off-limit squares are off-limit.
2502     if (testbits(env.pgrid(mons->pos()), FPROP_NO_JIYVA))
2503         return false;
2504
2505     int hps_changed = 0;
2506     int max_eat = roll_dice(1, 10);
2507     int eaten = 0;
2508     bool shown_msg = false;
2509
2510     // Jellies can swim, so don't check water
2511     for (stack_iterator si(mons->pos());
2512          si && eaten < max_eat && hps_changed < 50; ++si)
2513     {
2514         if (!item_is_jelly_edible(*si))
2515             continue;
2516
2517         dprf("%s eating %s", mons->name(DESC_PLAIN, true).c_str(),
2518              si->name(DESC_PLAIN).c_str());
2519
2520         int quant = si->quantity;
2521
2522         if (si->base_type != OBJ_GOLD)
2523         {
2524             quant = min(quant, max_eat - eaten);
2525
2526             hps_changed += quant * 3;
2527             eaten += quant;
2528         }
2529         else
2530         {
2531             // Shouldn't be much trouble to digest a huge pile of gold!
2532             if (quant > 500)
2533                 quant = 500 + roll_dice(2, (quant - 500) / 2);
2534
2535             hps_changed += quant / 10 + 1;
2536             eaten++;
2537         }
2538
2539         if (eaten && !shown_msg && player_can_hear(mons->pos()))
2540         {
2541             mprf(MSGCH_SOUND, "You hear a%s slurping noise.",
2542                  you.see_cell(mons->pos()) ? "" : " distant");
2543             shown_msg = true;
2544         }
2545
2546         if (you_worship(GOD_JIYVA))
2547             jiyva_slurp_item_stack(*si, quant);
2548
2549         if (quant >= si->quantity)
2550             item_was_destroyed(*si);
2551         dec_mitm_item_quantity(si.index(), quant);
2552     }
2553
2554     if (eaten > 0)
2555     {
2556         hps_changed = max(hps_changed, 1);
2557         hps_changed = min(hps_changed, 50);
2558
2559         // This is done manually instead of using heal_monster(),
2560         // because that function doesn't work quite this way. - bwr
2561         const int avg_hp = mons_avg_hp(mons->type);
2562         mons->hit_points += hps_changed;
2563         mons->hit_points = min(MAX_MONSTER_HP,
2564                                min(avg_hp * 4, mons->hit_points));
2565         mons->max_hit_points = max(mons->hit_points, mons->max_hit_points);
2566
2567         _jelly_divide(*mons);
2568     }
2569
2570     return eaten > 0;
2571 }
2572
2573
2574 static bool _handle_pickup(monster* mons)
2575 {
2576     if (env.igrid(mons->pos()) == NON_ITEM
2577         // Summoned monsters never pick anything up.
2578         || mons->is_summoned() || mons->is_perm_summoned()
2579         || mons->asleep() || mons->submerged())
2580     {
2581         return false;
2582     }
2583
2584     // Flying over water doesn't let you pick up stuff. This is inexact, as
2585     // a merfolk could be flying, but that's currently impossible except for
2586     // being tornadoed, and with *that* low life expectancy let's not care.
2587     dungeon_feature_type feat = env.grid(mons->pos());
2588
2589     if ((feat == DNGN_LAVA || feat == DNGN_DEEP_WATER) && mons->airborne())
2590         return false;
2591
2592     int count_pickup = 0;
2593
2594     if (mons_eats_items(*mons) && _monster_eat_item(mons))
2595         return false;
2596
2597     if (mons_itemuse(*mons) < MONUSE_WEAPONS_ARMOUR)
2598         return false;
2599
2600     // Keep neutral, charmed, and friendly monsters from
2601     // picking up stuff.
2602     const bool never_pickup
2603         = mons->neutral() || mons->friendly()
2604           || have_passive(passive_t::neutral_slimes) && mons_is_slime(*mons)
2605           || mons->has_ench(ENCH_CHARM) || mons->has_ench(ENCH_HEXED);
2606
2607
2608     // Note: Monsters only look at stuff near the top of stacks.
2609     //
2610     // XXX: Need to put in something so that monster picks up
2611     // multiple items (e.g. ammunition) identical to those it's
2612     // carrying.
2613     //
2614     // Monsters may now pick up up to two items in the same turn.
2615     // (jpeg)
2616     for (stack_iterator si(mons->pos()); si; ++si)
2617     {
2618         if (!crawl_state.game_is_arena()
2619             && (never_pickup
2620                 // Monsters being able to pick up items you've seen encourages
2621                 // tediously moving everything away from a place where they
2622                 // could use them. Maurice being able to pick up such items
2623                 // encourages killing Maurice, since there's just one of him.
2624                 // Usually.
2625                 || (testbits(si->flags, ISFLAG_SEEN)
2626                     && !mons->has_attack_flavour(AF_STEAL)))
2627             // ...but it's ok if it dropped the item itself.
2628             && !(si->props.exists(DROPPER_MID_KEY)
2629                  && si->props[DROPPER_MID_KEY].get_int() == (int)mons->mid))
2630         {
2631             // don't pick up any items beneath one that the player's seen,
2632             // to prevent seemingly-buggy behavior (monsters picking up items
2633             // from the middle of a stack while the player is watching)
2634             return false;
2635         }
2636
2637         if (si->flags & ISFLAG_NO_PICKUP)
2638             continue;
2639
2640         if (mons->pickup_item(*si, you.see_cell(mons->pos()), false))
2641             count_pickup++;
2642
2643         if (count_pickup > 1 || coinflip())
2644             break;
2645     }
2646
2647     return count_pickup > 0;
2648 }
2649
2650 static void _mons_open_door(monster& mons, const coord_def &pos)
2651 {
2652     const char *adj = "", *noun = "door";
2653
2654     bool was_seen   = false;
2655
2656     set<coord_def> all_door;
2657     find_connected_identical(pos, all_door);
2658     get_door_description(all_door.size(), &adj, &noun);
2659
2660     for (const auto &dc : all_door)
2661     {
2662         if (you.see_cell(dc))
2663             was_seen = true;
2664
2665         dgn_open_door(dc);
2666         set_terrain_changed(dc);
2667     }
2668
2669     if (was_seen)
2670     {
2671         viewwindow();
2672         update_screen();
2673
2674         string open_str = "opens the ";
2675         open_str += adj;
2676         open_str += noun;
2677         open_str += ".";
2678
2679         // Should this be conditionalized on you.can_see(mons?)
2680         mons.seen_context = (all_door.size() <= 2) ? SC_DOOR : SC_GATE;
2681
2682         if (!you.can_see(mons))
2683         {
2684             mprf("Something unseen %s", open_str.c_str());
2685             interrupt_activity(activity_interrupt::force);
2686         }
2687         else if (!you_are_delayed())
2688         {
2689             mprf("%s %s", mons.name(DESC_A).c_str(),
2690                  open_str.c_str());
2691         }
2692     }
2693
2694     mons.lose_energy(EUT_MOVE);
2695
2696     dungeon_events.fire_position_event(DET_DOOR_OPENED, pos);
2697 }
2698
2699 static bool _no_habitable_adjacent_grids(const monster* mon)
2700 {
2701     for (adjacent_iterator ai(mon->pos()); ai; ++ai)
2702         if (monster_habitable_grid(mon, env.grid(*ai)))
2703             return false;
2704
2705     return true;
2706 }
2707
2708 static bool _same_tentacle_parts(const monster* mpusher,
2709                                const monster* mpushee)
2710 {
2711     if (!mons_is_tentacle_head(mons_base_type(*mpusher)))
2712         return false;
2713
2714     if (mpushee->is_child_tentacle_of(mpusher))
2715         return true;
2716
2717     if (mons_tentacle_adjacent(mpusher, mpushee))
2718         return true;
2719
2720     return false;
2721 }
2722
2723 static bool _mons_can_displace(const monster* mpusher,
2724                                const monster* mpushee)
2725 {
2726     if (invalid_monster(mpusher) || invalid_monster(mpushee))
2727         return false;
2728
2729     const int ipushee = mpushee->mindex();
2730     if (invalid_monster_index(ipushee))
2731         return false;
2732
2733     if (mpusher->type == MONS_WANDERING_MUSHROOM
2734         && mpushee->type == MONS_TOADSTOOL
2735         || mpusher->type == MONS_TOADSTOOL
2736            && mpushee->type == MONS_WANDERING_MUSHROOM)
2737     {
2738         return true;
2739     }
2740
2741     // Foxfires can always be pushed
2742     if (mpushee->type == MONS_FOXFIRE)
2743         return !mons_aligned(mpushee, mpusher); // But allies won't do it
2744
2745     if (!mpushee->has_action_energy()
2746         && !_same_tentacle_parts(mpusher, mpushee))
2747     {
2748         return false;
2749     }
2750
2751     // Confused monsters can't be pushed past, sleeping monsters
2752     // can't push. Note that sleeping monsters can't be pushed
2753     // past, either, but they may be woken up by a crowd trying to
2754     // elbow past them, and the wake-up check happens downstream.
2755     // Monsters caught in a net also can't be pushed past.
2756     if (mons_is_confused(*mpusher) || mons_is_confused(*mpushee)
2757         || mpusher->cannot_move() || mpusher->is_stationary()
2758         || mpusher->is_constricted() || mpushee->is_constricted()
2759         || (!_same_tentacle_parts(mpusher, mpushee)
2760            && (mpushee->cannot_move() || mpushee->is_stationary()))
2761         || mpusher->asleep() || mpushee->caught())
2762     {
2763         return false;
2764     }
2765
2766     // OODs should crash into things, not push them around.
2767     if (mons_is_projectile(*mpusher) || mons_is_projectile(*mpushee))
2768         return false;
2769
2770     // Likewise, OOBs (orbs of beetle)
2771     if (mpusher->has_ench(ENCH_ROLLING) || mpushee->has_ench(ENCH_ROLLING))
2772         return false;
2773
2774     // Fleeing monsters cannot push past other fleeing monsters
2775     // (This helps to prevent some traffic jams in confined spaces)
2776     if (mons_is_fleeing(*mpusher) && mons_is_fleeing(*mpushee))
2777         return false;
2778
2779     // Batty monsters are unpushable.
2780     if (mons_is_batty(*mpusher) || mons_is_batty(*mpushee))
2781         return false;
2782
2783     // Anyone can displace a submerged monster.
2784     if (mpushee->submerged())
2785         return true;
2786
2787     if (!monster_shover(*mpusher))
2788         return false;
2789
2790     // Fleeing monsters of the same type may push past higher ranking ones.
2791     if (!monster_senior(*mpusher, *mpushee, mons_is_retreating(*mpusher)))
2792         return false;
2793
2794     return true;
2795 }
2796
2797 // Returns true if the monster should try to avoid that position
2798 // because of taking damage from damaging walls.
2799 static bool _check_damaging_walls(const monster *mon,
2800                                   const coord_def &targ)
2801 {
2802     const bool have_slimy = env.level_state & LSTATE_SLIMY_WALL;
2803     const bool have_icy   = env.level_state & LSTATE_ICY_WALL;
2804
2805     if (!have_slimy && !have_icy)
2806         return false;
2807
2808     if (!have_icy && actor_slime_wall_immune(mon)
2809         || mons_intel(*mon) <= I_BRAINLESS)
2810     {
2811         return false;
2812     }
2813
2814     // Monsters are only ever affected by one wall at a time, so we don't care
2815     // about wall counts past 1.
2816     const bool target_damages = count_adjacent_slime_walls(targ)
2817         + count_adjacent_icy_walls(targ);
2818
2819     // Entirely safe.
2820     if (!target_damages)
2821         return false;
2822
2823     const bool current_damages = count_adjacent_slime_walls(mon->pos())
2824         + count_adjacent_icy_walls(mon->pos());
2825
2826     // We're already taking damage, so moving into damage is fine.
2827     if (current_damages)
2828         return false;
2829
2830     // The monster needs to have a purpose to risk taking damage.
2831     if (!mons_is_seeking(*mon))
2832         return true;
2833
2834     // With enough hit points monsters will consider moving
2835     // onto more dangerous squares.
2836     return mon->hit_points < mon->max_hit_points / 2;
2837 }
2838
2839 // Check whether a monster can move to given square (described by its relative
2840 // coordinates to the current monster position). just_check is true only for
2841 // calls from is_trap_safe when checking the surrounding squares of a trap.
2842 bool mon_can_move_to_pos(const monster* mons, const coord_def& delta,
2843                          bool just_check)
2844 {
2845     const coord_def targ = mons->pos() + delta;
2846
2847     // Bounds check: don't consider moving out of grid!
2848     if (!in_bounds(targ))
2849         return false;
2850
2851     // Non-friendly and non-good neutral monsters won't enter
2852     // sanctuaries.
2853     if (is_sanctuary(targ)
2854         && !is_sanctuary(mons->pos())
2855         && !mons->wont_attack())
2856     {
2857         return false;
2858     }
2859
2860     // Inside a sanctuary don't attack anything!
2861     if (is_sanctuary(mons->pos()) && actor_at(targ))
2862         return false;
2863
2864     const dungeon_feature_type target_grid = env.grid(targ);
2865     const habitat_type habitat = mons_primary_habitat(*mons);
2866
2867     // No monster may enter the open sea.
2868     if (feat_is_endless(target_grid))
2869         return false;
2870
2871     // A confused monster will happily go wherever it can, regardless of
2872     // consequences.
2873     if (mons->confused() && mons->can_pass_through(targ))
2874         return true;
2875
2876     if (mons_avoids_cloud(mons, targ))
2877         return false;
2878
2879     if (_check_damaging_walls(mons, targ))
2880         return false;
2881
2882     const bool digs = _mons_can_cast_dig(mons, false)
2883                       || _mons_can_zap_dig(mons);
2884     if ((target_grid == DNGN_ROCK_WALL || target_grid == DNGN_CLEAR_ROCK_WALL)
2885            && (mons_class_flag(mons->type, M_BURROWS) || digs)
2886         || mons->type == MONS_SPATIAL_MAELSTROM
2887            && feat_is_solid(target_grid) && !feat_is_permarock(target_grid)
2888            && !feat_is_critical(target_grid)
2889         || feat_is_tree(target_grid) && mons_flattens_trees(*mons)
2890         || target_grid == DNGN_GRATE && digs)
2891     {
2892     }
2893     else if (!mons_can_traverse(*mons, targ, false, false)
2894              && !monster_habitable_grid(mons, target_grid))
2895     {
2896         // If the monster somehow ended up in this habitat (and is
2897         // not dead by now), give it a chance to get out again.
2898         if (env.grid(mons->pos()) == target_grid && mons->ground_level()
2899             && _no_habitable_adjacent_grids(mons))
2900         {
2901             return true;
2902         }
2903
2904         return false;
2905     }
2906
2907     // These monsters usually don't move while you are looking.
2908     if (mons->type == MONS_WANDERING_MUSHROOM
2909         || mons->type == MONS_DEATHCAP
2910         || (mons->type == MONS_LURKING_HORROR
2911             && mons->foe_distance() > random2(LOS_DEFAULT_RANGE + 1)))
2912     {
2913         if (!mons->wont_attack() && is_sanctuary(mons->pos()))
2914             return true;
2915
2916         if (!mons->friendly() && you.see_cell(targ)
2917             || mon_enemies_around(mons))
2918         {
2919             return false;
2920         }
2921     }
2922
2923     if (mons->type == MONS_MERFOLK_AVATAR)
2924     {
2925         // Don't voluntarily break LoS with a player we're mesmerising
2926         if (you.beheld_by(*mons) && !you.see_cell(targ))
2927             return false;
2928
2929         // And path around players instead of into them
2930         if (you.pos() == targ)
2931             return false;
2932     }
2933
2934     // Try to avoid deliberately blocking the player's line of fire.
2935     if (mons->type == MONS_SPELLFORGED_SERVITOR)
2936     {
2937         const actor * const summoner = actor_by_mid(mons->summoner);
2938
2939         if (!summoner) // XXX
2940             return false;
2941
2942         // Only check if our target is something the caster could theoretically
2943         // be aiming at.
2944         if (mons->get_foe() && mons->target != summoner->pos()
2945                             && summoner->see_cell_no_trans(mons->target))
2946         {
2947             ray_def ray;
2948             if (find_ray(summoner->pos(), mons->target, ray, opc_immob))
2949             {
2950                 while (ray.advance())
2951                 {
2952                     // Either we've reached the end of the ray, or we're already
2953                     // (maybe) in the player's way and shouldn't care if our
2954                     // next step also is.
2955                     if (ray.pos() == mons->target || ray.pos() == mons->pos())
2956                         break;
2957                     else if (ray.pos() == targ)
2958                         return false;
2959                 }
2960             }
2961         }
2962     }
2963
2964     // Submerged water creatures avoid the shallows where
2965     // they would be forced to surface. -- bwr
2966     // [dshaligram] Monsters now prefer to head for deep water only if
2967     // they're low on hitpoints. No point in hiding if they want a
2968     // fight.
2969     if (habitat == HT_WATER
2970         && targ != you.pos()
2971         && target_grid != DNGN_DEEP_WATER
2972         && env.grid(mons->pos()) == DNGN_DEEP_WATER
2973         && mons->hit_points < (mons->max_hit_points * 3) / 4)
2974     {
2975         return false;
2976     }
2977
2978     // Smacking the player is always a good move if we're
2979     // hostile (even if we're heading somewhere else).
2980     // Also friendlies want to keep close to the player
2981     // so it's okay as well.
2982
2983     // Smacking another monster is good, if the monsters
2984     // are aligned differently.
2985     if (monster* targmonster = monster_at(targ))
2986     {
2987         if (just_check)
2988         {
2989             if (targ == mons->pos())
2990                 return true;
2991
2992             return false; // blocks square
2993         }
2994
2995         if (!summon_can_attack(mons, targ))
2996             return false;
2997
2998         if (targmonster->type == MONS_TOADSTOOL
2999             && mons->type == MONS_WANDERING_MUSHROOM)
3000         {
3001             return true;
3002         }
3003
3004         // Cut down plants only when no alternative, or they're
3005         // our target.
3006         if (mons_is_firewood(*targmonster) && mons->target != targ)
3007             return false;
3008
3009         if ((mons_aligned(mons, targmonster)
3010              || targmonster->type == MONS_FOXFIRE)
3011             && !mons->has_ench(ENCH_INSANE)
3012             && !_mons_can_displace(mons, targmonster))
3013         {
3014             return false;
3015         }
3016         // Prefer to move past enemies instead of hit them, if we're retreating
3017         else if ((!mons_aligned(mons, targmonster)
3018                   || mons->has_ench(ENCH_INSANE))
3019                  && mons->behaviour == BEH_WITHDRAW)
3020         {
3021             return false;
3022         }
3023     }
3024
3025     // Friendlies shouldn't try to move onto the player's
3026     // location, if they are aiming for some other target.
3027     if (mons->foe != MHITYOU
3028         && targ == you.pos()
3029         && (mons->foe != MHITNOT || mons->is_patrolling())
3030         && !_unfriendly_or_impaired(*mons))
3031     {
3032         return false;
3033     }
3034
3035     // Wandering through a trap is OK if we're pretty healthy,
3036     // really stupid, or immune to the trap.
3037     if (!mons->is_trap_safe(targ, just_check))
3038         return false;
3039
3040     // If we end up here the monster can safely move.
3041     return true;
3042 }
3043
3044 // May mons attack targ if it's in its way, despite
3045 // possibly aligned attitudes?
3046 // The aim of this is to have monsters cut down plants
3047 // to get to the player if necessary.
3048 static bool _may_cutdown(monster* mons, monster* targ)
3049 {
3050     // Save friendly plants from allies.
3051     // [ds] I'm deliberately making the alignment checks symmetric here.
3052     // The previous check involved good-neutrals never attacking friendlies
3053     // and friendlies never attacking anything other than hostiles.
3054     if ((mons->friendly() || mons->good_neutral())
3055          && (targ->friendly() || targ->good_neutral()))
3056     {
3057         return false;
3058     }
3059     // Outside of that case, can always cut mundane plants
3060     // (but don't try to attack briars unless their damage will be insignificant)
3061     return mons_is_firewood(*targ)
3062         && (targ->type != MONS_BRIAR_PATCH
3063             || (targ->friendly() && !mons_aligned(mons, targ))
3064             || mons->type == MONS_THORN_HUNTER
3065             || mons->armour_class() * mons->hit_points >= 400);
3066 }
3067
3068 // Uses, and updates the global variable mmov.
3069 static void _find_good_alternate_move(monster* mons,
3070                                       const move_array& good_move)
3071 {
3072     const coord_def target = mons->firing_pos.zero() ? mons->target
3073                                                      : mons->firing_pos;
3074     const int current_distance = distance2(mons->pos(), target);
3075
3076     int dir = _compass_idx(mmov);
3077
3078     // Only handle if the original move is to an adjacent square.
3079     if (dir == -1)
3080         return;
3081
3082     int dist[2];
3083
3084     // First 1 away, then 2 (3 is silly).
3085     for (int j = 1; j <= 2; j++)
3086     {
3087         const int FAR_AWAY = 1000000;
3088
3089         // Try both directions (but randomise which one is first).
3090         const int sdir = random_choose(j, -j);
3091         const int inc = -2 * sdir;
3092
3093         for (int mod = sdir, i = 0; i < 2; mod += inc, i++)
3094         {
3095             const int newdir = (dir + 8 + mod) % 8;
3096             if (good_move[mon_compass[newdir].x+1][mon_compass[newdir].y+1])
3097                 dist[i] = distance2(mons->pos()+mon_compass[newdir], target);
3098             else
3099             {
3100                 // If we can cut firewood there, it's still not a good move,
3101                 // but update mmov so we can fall back to it.
3102                 monster* targ = monster_at(mons->pos() + mon_compass[newdir]);
3103                 const bool retreating = mons_is_retreating(*mons);
3104
3105                 dist[i] = (targ && _may_cutdown(mons, targ))
3106                           ? current_distance
3107                           : retreating ? -FAR_AWAY : FAR_AWAY;
3108             }
3109         }
3110
3111         const int dir0 = ((dir + 8 + sdir) % 8);
3112         const int dir1 = ((dir + 8 - sdir) % 8);
3113
3114         // Now choose.
3115         if (dist[0] == dist[1] && abs(dist[0]) == FAR_AWAY)
3116             continue;
3117
3118         // Which one was better? -- depends on FLEEING or not.
3119         if (mons_is_retreating(*mons))
3120         {
3121             if (dist[0] >= dist[1] && dist[0] >= current_distance)
3122             {
3123                 mmov = mon_compass[dir0];
3124                 break;
3125             }
3126             if (dist[1] >= dist[0] && dist[1] >= current_distance)
3127             {
3128                 mmov = mon_compass[dir1];
3129                 break;
3130             }
3131         }
3132         else
3133         {
3134             if (dist[0] <= dist[1] && dist[0] <= current_distance)
3135             {
3136                 mmov = mon_compass[dir0];
3137                 break;
3138             }
3139             if (dist[1] <= dist[0] && dist[1] <= current_distance)
3140             {
3141                 mmov = mon_compass[dir1];
3142                 break;
3143             }
3144         }
3145     }
3146 }
3147
3148 static void _jelly_grows(monster& mons)
3149 {
3150     if (player_can_hear(mons.pos()))
3151     {
3152         mprf(MSGCH_SOUND, "You hear a%s slurping noise.",
3153              you.see_cell(mons.pos()) ? "" : " distant");
3154     }
3155
3156     const int avg_hp = mons_avg_hp(mons.type);
3157     mons.hit_points += 5;
3158     mons.hit_points = min(MAX_MONSTER_HP,
3159                           min(avg_hp * 4, mons.hit_points));
3160
3161     // note here, that this makes jellies "grow" {dlb}:
3162     if (mons.hit_points > mons.max_hit_points)
3163         mons.max_hit_points = mons.hit_points;
3164
3165     _jelly_divide(mons);
3166 }
3167
3168 bool monster_swaps_places(monster* mon, const coord_def& delta,
3169                           bool takes_time, bool apply_effects)
3170 {
3171     if (delta.origin())
3172         return false;
3173
3174     monster* const m2 = monster_at(mon->pos() + delta);
3175
3176     if (!m2)
3177         return false;
3178
3179     if (!_mons_can_displace(mon, m2))
3180         return false;
3181
3182     if (m2->asleep())
3183     {
3184         if (coinflip())
3185         {
3186             dprf("Alerting monster %s at (%d,%d)",
3187                  m2->name(DESC_PLAIN).c_str(), m2->pos().x, m2->pos().y);
3188             behaviour_event(m2, ME_ALERT);
3189         }
3190         return false;
3191     }
3192
3193     if (!mon->swap_with(m2))
3194         return false;
3195
3196     if (takes_time)
3197     {
3198         _swim_or_move_energy(*mon);
3199         _swim_or_move_energy(*m2);
3200     }
3201
3202     mon->check_redraw(m2->pos(), false);
3203     if (apply_effects)
3204         mon->apply_location_effects(m2->pos());
3205
3206     m2->check_redraw(mon->pos(), false);
3207     if (apply_effects)
3208         m2->apply_location_effects(mon->pos());
3209
3210     // The seen context no longer applies if the monster is moving normally.
3211     mon->seen_context = SC_NONE;
3212     m2->seen_context = SC_NONE;
3213
3214     _handle_manticore_barbs(*mon);
3215     _handle_manticore_barbs(*m2);
3216
3217     // Pushing past a foxfire gets you burned regardless of alignment
3218     if (m2->type == MONS_FOXFIRE)
3219     {
3220         foxfire_attack(m2, mon);
3221         monster_die(*m2, KILL_DISMISSED, NON_MONSTER, true);
3222     }
3223
3224     return false;
3225 }
3226
3227 static bool _do_move_monster(monster& mons, const coord_def& delta)
3228 {
3229     const coord_def f = mons.pos() + delta;
3230
3231     if (!in_bounds(f))
3232         return false;
3233
3234     if (f == you.pos())
3235     {
3236         fight_melee(&mons, &you);
3237         return true;
3238     }
3239
3240     // This includes the case where the monster attacks itself.
3241     if (monster* def = monster_at(f))
3242     {
3243         fight_melee(&mons, def);
3244         return true;
3245     }
3246
3247     if (mons.is_constricted())
3248     {
3249         if (mons.attempt_escape())
3250             simple_monster_message(mons, " escapes!");
3251         else
3252         {
3253             simple_monster_message(mons, " struggles to escape constriction.");
3254             _swim_or_move_energy(mons);
3255             return true;
3256         }
3257     }
3258
3259     ASSERT(!cell_is_runed(f)); // should be checked in mons_can_traverse
3260
3261     if (feat_is_closed_door(env.grid(f)))
3262     {
3263         if (mons_can_destroy_door(mons, f))
3264         {
3265             env.grid(f) = DNGN_FLOOR;
3266             set_terrain_changed(f);
3267
3268             if (you.see_cell(f))
3269             {
3270                 viewwindow();
3271                 update_screen();
3272
3273                 if (!you.can_see(mons))
3274                 {
3275                     mpr("The door bursts into shrapnel!");
3276                     interrupt_activity(activity_interrupt::force);
3277                 }
3278                 else
3279                     simple_monster_message(mons, " bursts through the door, destroying it!");
3280             }
3281         }
3282         else if (mons_can_open_door(mons, f))
3283         {
3284             _mons_open_door(mons, f);
3285             return true;
3286         }
3287         else if (mons_can_eat_door(mons, f))
3288         {
3289             env.grid(f) = DNGN_FLOOR;
3290             set_terrain_changed(f);
3291
3292             _jelly_grows(mons);
3293
3294             if (you.see_cell(f))
3295             {
3296                 viewwindow();
3297                 update_screen();
3298
3299                 if (!you.can_see(mons))
3300                 {
3301                     mpr("The door mysteriously vanishes.");
3302                     interrupt_activity(activity_interrupt::force);
3303                 }
3304                 else
3305                     simple_monster_message(mons, " eats the door!");
3306             }
3307         } // done door-eating jellies
3308     }
3309
3310     // The monster gave a "comes into view" message and then immediately
3311     // moved back out of view, leaing the player nothing to see, so give
3312     // this message to avoid confusion.
3313     else if (crawl_state.game_is_hints() && mons.flags & MF_WAS_IN_VIEW
3314              && !you.see_cell(f))
3315     {
3316         learned_something_new(HINT_MONSTER_LEFT_LOS, mons.pos());
3317     }
3318
3319     // The seen context no longer applies if the monster is moving normally.
3320     mons.seen_context = SC_NONE;
3321
3322     // This appears to be the real one, ie where the movement occurs:
3323     _swim_or_move_energy(mons);
3324
3325     if (mons.type == MONS_FOXFIRE)
3326         --mons.steps_remaining;
3327
3328     _escape_water_hold(mons);
3329
3330     if (env.grid(mons.pos()) == DNGN_DEEP_WATER && env.grid(f) != DNGN_DEEP_WATER
3331         && !monster_habitable_grid(&mons, DNGN_DEEP_WATER))
3332     {
3333         // er, what?  Seems impossible.
3334         mons.seen_context = SC_NONSWIMMER_SURFACES_FROM_DEEP;
3335     }
3336
3337     mons.move_to_pos(f, false);
3338
3339     // Let go of all constrictees; only stop *being* constricted if we are now
3340     // too far away (done in move_to_pos above).
3341     mons.stop_directly_constricting_all(false);
3342
3343     mons.check_redraw(mons.pos() - delta);
3344     mons.apply_location_effects(mons.pos() - delta);
3345     if (!invalid_monster(&mons) && you.can_see(mons))
3346     {
3347         handle_seen_interrupt(&mons);
3348         seen_monster(&mons);
3349     }
3350
3351     _handle_manticore_barbs(mons);
3352
3353     return true;
3354 }
3355
3356 static bool _monster_move(monster* mons)
3357 {
3358     ASSERT(mons); // XXX: change to monster &mons
3359     move_array good_move;
3360
3361     const habitat_type habitat = mons_primary_habitat(*mons);
3362     bool deep_water_available = false;
3363
3364     // Berserking monsters make a lot of racket.
3365     if (mons->berserk_or_insane())
3366     {
3367         int noise_level = get_shout_noise_level(mons_shouts(mons->type));
3368         if (noise_level > 0)
3369         {
3370             if (you.can_see(*mons) && mons->berserk())
3371             {
3372                 if (one_chance_in(10))
3373                 {
3374                     mprf(MSGCH_TALK_VISUAL, "%s rages.",
3375                          mons->name(DESC_THE).c_str());
3376                 }
3377                 noisy(noise_level, mons->pos(), mons->mid);
3378             }
3379             else if (one_chance_in(5))
3380                 monster_attempt_shout(*mons);
3381             else
3382             {
3383                 // Just be noisy without messaging the player.
3384                 noisy(noise_level, mons->pos(), mons->mid);
3385             }
3386         }
3387     }
3388
3389     // If a water (or lava) monster is currently flopping around on land, it
3390     // cannot really control where it wants to move, though there's a 50%
3391     // chance of flopping into an adjacent water (or lava) grid.
3392     if (mons->has_ench(ENCH_AQUATIC_LAND))
3393     {
3394         vector<coord_def> adj_water;
3395         vector<coord_def> adj_move;
3396         for (adjacent_iterator ai(mons->pos()); ai; ++ai)
3397         {
3398             if (!cell_is_solid(*ai))
3399             {
3400                 adj_move.push_back(*ai);
3401                 if (habitat == HT_WATER && feat_is_watery(env.grid(*ai))
3402                     || habitat == HT_LAVA && feat_is_lava(env.grid(*ai)))
3403                 {
3404                     adj_water.push_back(*ai);
3405                 }
3406             }
3407         }
3408         if (adj_move.empty())
3409         {
3410             simple_monster_message(*mons, " flops around on dry land!");
3411             return false;
3412         }
3413
3414         vector<coord_def> moves = adj_water;
3415         if (adj_water.empty() || coinflip())
3416             moves = adj_move;
3417
3418         const coord_def newpos = moves.empty() ? mons->pos()
3419                                                : moves[random2(moves.size())];
3420
3421         const monster* mon2 = monster_at(newpos);
3422         if (!mons->has_ench(ENCH_INSANE)
3423             && (newpos == you.pos() && mons->wont_attack()
3424                 || (mon2 && mons->wont_attack() == mon2->wont_attack())))
3425         {
3426             simple_monster_message(*mons, " flops around on dry land!");
3427             return false;
3428         }
3429
3430         return _do_move_monster(*mons, newpos - mons->pos());
3431     }
3432
3433     // Let's not even bother with this if mmov is zero.
3434     if (mmov.origin())
3435         return false;
3436
3437     for (int count_x = 0; count_x < 3; count_x++)
3438         for (int count_y = 0; count_y < 3; count_y++)
3439         {
3440             const int targ_x = mons->pos().x + count_x - 1;
3441             const int targ_y = mons->pos().y + count_y - 1;
3442
3443             // Bounds check: don't consider moving out of grid!
3444             if (!in_bounds(targ_x, targ_y))
3445             {
3446                 good_move[count_x][count_y] = false;
3447                 continue;
3448             }
3449             dungeon_feature_type target_grid = env.grid[targ_x][targ_y];
3450
3451             if (target_grid == DNGN_DEEP_WATER)
3452                 deep_water_available = true;
3453
3454             good_move[count_x][count_y] =
3455                 mon_can_move_to_pos(mons, coord_def(count_x-1, count_y-1));
3456         }
3457
3458     // Now we know where we _can_ move.
3459
3460     const coord_def newpos = mons->pos() + mmov;
3461     // Water creatures have a preference for water they can hide in -- bwr
3462     // [ds] Weakened the powerful attraction to deep water if the monster
3463     // is in good health.
3464     if (habitat == HT_WATER
3465         && deep_water_available
3466         && env.grid(mons->pos()) != DNGN_DEEP_WATER
3467         && env.grid(newpos) != DNGN_DEEP_WATER
3468         && newpos != you.pos()
3469         && (one_chance_in(3)
3470             || mons->hit_points <= (mons->max_hit_points * 3) / 4))
3471     {
3472         int count = 0;
3473
3474         for (int cx = 0; cx < 3; cx++)
3475             for (int cy = 0; cy < 3; cy++)
3476             {
3477                 if (good_move[cx][cy]
3478                     && env.grid[mons->pos().x + cx - 1][mons->pos().y + cy - 1]
3479                             == DNGN_DEEP_WATER)
3480                 {
3481                     if (one_chance_in(++count))
3482                     {
3483                         mmov.x = cx - 1;
3484                         mmov.y = cy - 1;
3485                     }
3486                 }
3487             }
3488     }
3489
3490     // Now, if a monster can't move in its intended direction, try
3491     // either side. If they're both good, move in whichever dir
3492     // gets it closer (farther for fleeing monsters) to its target.
3493     // If neither does, do nothing.
3494     if (good_move[mmov.x + 1][mmov.y + 1] == false)
3495         _find_good_alternate_move(mons, good_move);
3496
3497     // ------------------------------------------------------------------
3498     // If we haven't found a good move by this point, we're not going to.
3499     // ------------------------------------------------------------------
3500
3501     if (mons->type == MONS_SPATIAL_MAELSTROM)
3502     {
3503         const dungeon_feature_type feat = env.grid(mons->pos() + mmov);
3504         if (!feat_is_permarock(feat) && feat_is_solid(feat))
3505         {
3506             const coord_def target(mons->pos() + mmov);
3507             create_monster(
3508                     mgen_data(MONS_SPATIAL_VORTEX, SAME_ATTITUDE(mons), target)