3 * @brief Monsters doing stuff (monsters acting).
13 #include "attitude-change.h"
14 #include "bloodspatter.h"
21 #include "directn.h" // feature_description_at
23 #include "english.h" // apostrophise
27 #include "god-abil.h" // GOZAG_GOLD_AURA_KEY
28 #include "god-passive.h"
29 #include "god-prayer.h"
31 #include "item-name.h"
32 #include "item-prop.h"
33 #include "item-status-flag-type.h"
35 #include "level-state-type.h"
37 #include "losglobal.h"
45 #include "mon-death.h"
46 #include "mon-movetarget.h"
47 #include "mon-place.h"
49 #include "mon-project.h"
50 #include "mon-speak.h"
51 #include "mon-tentacle.h"
52 #include "nearby-danger.h"
56 #include "spl-clouds.h"
57 #include "spl-damage.h"
58 #include "spl-summoning.h"
59 #include "spl-transloc.h"
63 #include "stringutil.h"
68 #include "timed-effects.h"
73 static bool _handle_pickup(monster* mons);
74 static void _mons_in_cloud(monster& mons);
75 static bool _monster_move(monster* mons);
77 // [dshaligram] Doesn't need to be extern.
78 static coord_def mmov;
81 * Get the monster's "hit dice".
83 * @return The monster's HD.
85 int monster::get_hit_dice() const
87 const int base_hd = get_experience_level();
89 const mon_enchant drain_ench = get_ench(ENCH_DRAINED);
90 const int drained_hd = base_hd - drain_ench.degree;
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);
99 * Get the monster's "experience level" - their hit dice, unmodified by
100 * temporary enchantments (draining).
102 * @return The monster's XL.
104 int monster::get_experience_level() const
109 static const coord_def mon_compass[8] =
111 { -1,-1 }, { 0,-1 }, { 1,-1 }, { 1,0 }, // bjnl
112 { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1,0 } // ukyh
115 static int _compass_idx(const coord_def& mov)
117 for (int i = 0; i < 8; i++)
118 if (mon_compass[i] == mov)
123 static inline bool _mons_natural_regen_roll(monster* mons)
125 const int regen_rate = mons->natural_regen_rate();
126 return x_chance_in_y(regen_rate, 25);
129 // Do natural regeneration for monster.
130 static void _monster_regenerate(monster* mons)
132 // Early bailout so that regen-based triggers don't get spammed
133 if (mons->hit_points == mons->max_hit_points)
136 if (crawl_state.disables[DIS_MON_REGEN])
139 if (mons->has_ench(ENCH_SICK)
140 || !mons_can_regenerate(*mons) && !(mons->has_ench(ENCH_REGENERATION)))
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())))
152 if (mons_class_fast_regen(mons->type)
153 || mons->has_ench(ENCH_REGENERATION)
154 || _mons_natural_regen_roll(mons))
159 if (mons_is_hepliaklqana_ancestor(mons->type))
161 if (mons->hit_points == mons->max_hit_points && you.can_see(*mons))
162 interrupt_activity(activity_interrupt::ancestor_hp);
166 static void _escape_water_hold(monster& mons)
168 if (mons.has_ench(ENCH_WATER_HOLD))
170 simple_monster_message(mons, " slips free of the water.");
171 mons.del_ench(ENCH_WATER_HOLD);
175 static void _handle_manticore_barbs(monster& mons)
177 if (mons.has_ench(ENCH_BARBS))
179 mon_enchant barbs = mons.get_ench(ENCH_BARBS);
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);
190 mons.update_ench(barbs);
195 static bool _swap_monsters(monster& mover, monster& moved)
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())
203 // If the target monster is constricted it is stuck
204 // and not eligible to be swapped with
205 if (moved.is_constricted())
207 dprf("%s fails to swap with %s, constricted.",
208 mover.name(DESC_THE).c_str(),
209 moved.name(DESC_THE).c_str());
213 // Swapping is a purposeful action.
214 if (mover.confused())
217 // Right now just happens in sanctuary.
218 if (!is_sanctuary(mover.pos()) || !is_sanctuary(moved.pos()))
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))
229 // Don't swap places if the player explicitly ordered their pet to
231 if ((mover.friendly() || moved.friendly())
232 && you.pet_target != MHITYOU && you.pet_target != MHITNOT)
237 // Okay, we can probably do the swap.
238 if (!mover.swap_with(&moved))
241 if (you.can_see(mover) && you.can_see(moved))
243 mprf("%s and %s swap places.", mover.name(DESC_THE).c_str(),
244 moved.name(DESC_THE).c_str());
247 _escape_water_hold(mover);
249 _handle_manticore_barbs(mover);
250 _handle_manticore_barbs(moved);
252 if (moved.type == MONS_FOXFIRE)
254 mprf(MSGCH_GOD, "By Zin's power the foxfire is contained!");
255 monster_die(moved, KILL_DISMISSED, NON_MONSTER, true);
261 static bool _do_mon_spell(monster* mons)
263 if (handle_mon_spell(mons))
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;
278 static void _swim_or_move_energy(monster& mon)
280 const dungeon_feature_type feat = env.grid(mon.pos());
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);
287 static bool _unfriendly_or_impaired(const monster& mon)
289 return !mon.wont_attack() || mon.has_ench(ENCH_INSANE) || mon.confused();
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)
298 coord_def pos = mon->pos();
300 for (int i = 1; i <= LOS_RADIUS; i++)
306 const actor* ally = actor_at(pos);
310 if (mons_aligned(mon, ally))
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))
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
326 if (ally->is_monster())
327 return mons_has_ranged_attack(*(ally->as_monster()));
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,
340 for (coord_def delta : { a, b, c })
342 coord_def pos = mon->pos() + delta;
346 const monster* ally = monster_at(pos);
350 if (ally->is_stationary() || ally->reach_range() > REACH_NONE)
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))
361 if (mons_aligned(mon, ally))
368 // Altars as well as branch entrances are considered interesting for
369 // some monster types.
370 static bool _mon_on_interesting_grid(monster* mon)
372 const dungeon_feature_type feat = env.grid(mon->pos());
376 // Holy beings will tend to patrol around altars to the good gods.
377 case DNGN_ALTAR_ELYVILON:
378 if (!one_chance_in(3))
382 case DNGN_ALTAR_SHINING_ONE:
383 return mon->is_holy();
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:
390 return mons_is_native_in_branch(*mon, BRANCH_ORC);
392 // Same for elves and the Elven Halls.
395 return mons_is_native_in_branch(*mon, BRANCH_ELF);
398 case DNGN_ENTER_SPIDER:
399 return mons_is_native_in_branch(*mon, BRANCH_SPIDER);
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)
411 if (_mon_on_interesting_grid(mons) // Patrolling shouldn't always happen
413 && mons_is_wandering(*mons)
414 && !mons->is_patrolling()
415 && !mons->friendly())
417 mons->patrol_point = mons->pos();
421 static bool _mons_can_cast_dig(const monster* mons, bool random)
423 if (mons->foe == MHITNOT || !mons->has_spell(SPELL_DIG) || mons->confused()
424 || mons->berserk_or_insane())
429 const bool antimagiced = mons->has_ench(ENCH_ANTIMAGIC)
431 && !x_chance_in_y(4 * BASELINE_DELAY,
433 + mons->get_ench(ENCH_ANTIMAGIC).duration)
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);
442 static bool _mons_can_zap_dig(const monster* mons)
444 return mons->foe != MHITNOT
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;
455 static void _set_mons_move_dir(const monster* mons,
456 coord_def* dir, coord_def* delta)
461 // Some calculations.
462 if ((mons_class_flag(mons->type, M_BURROWS)
463 || _mons_can_cast_dig(mons, false))
464 && mons->foe == MHITYOU)
466 // Digging monsters always move in a straight line in your direction.
467 *delta = you.pos() - mons->pos();
471 *delta = (mons->firing_pos.zero() ? mons->target : mons->firing_pos)
478 if (mons_is_retreating(*mons)
479 && (!mons->friendly() || mons->target != you.pos()))
485 typedef FixedArray< bool, 3, 3 > move_array;
487 static void _fill_good_move(const monster* mons, move_array* good_move)
489 for (int count_x = 0; count_x < 3; count_x++)
490 for (int count_y = 0; count_y < 3; count_y++)
492 const int targ_x = mons->pos().x + count_x - 1;
493 const int targ_y = mons->pos().y + count_y - 1;
495 // Bounds check: don't consider moving out of grid!
496 if (!in_bounds(targ_x, targ_y))
498 (*good_move)[count_x][count_y] = false;
502 (*good_move)[count_x][count_y] =
503 mon_can_move_to_pos(mons, coord_def(count_x-1, count_y-1));
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)
511 coord_def mov, delta;
512 _set_mons_move_dir(mon, &mov, &delta);
514 move_array good_move;
515 _fill_good_move(mon, &good_move);
517 int dir = _compass_idx(mov);
518 for (int i = -1; i <= 1; ++i)
520 const int altdir = (dir + i + 8) % 8;
521 const coord_def p = mon_compass[altdir] + coord_def(1, 1);
529 static const string BATTY_TURNS_KEY = "BATTY_TURNS";
531 static void _be_batty(monster &mons)
533 mons.behaviour = BEH_WANDER;
534 set_random_target(&mons);
535 mons.props[BATTY_TURNS_KEY] = 0;
538 static void _handle_movement(monster* mons)
540 _maybe_set_patrol_route(mons);
542 if (sanctuary_exists())
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))
549 mons_start_fleeing_from_sanctuary(*mons);
551 else if (mons_is_fleeing_sanctuary(*mons)
552 && !is_sanctuary(mons->pos()))
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
558 if (mons->is_nonliving()
560 || mons->has_ench(ENCH_INSANE)
561 || x_chance_in_y(2, 5))
563 mons_stop_fleeing_from_sanctuary(*mons);
569 _set_mons_move_dir(mons, &mmov, &delta);
571 if (sanctuary_exists())
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()))
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))
587 if (!in_bounds_y(s.y))
590 if (delta.rdist() > 3)
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
597 // Added a check so that oblique movement paths aren't used when
598 // close to the target square. -- bwr
600 // Sometimes we'll just move parallel the x axis.
601 if (abs(delta.x) > abs(delta.y) && coinflip())
604 // Sometimes we'll just move parallel the y axis.
605 if (abs(delta.y) > abs(delta.x) && coinflip())
609 // Now quit if we can't move.
613 const coord_def newpos(mons->pos() + mmov);
615 // Filling this is relatively costly and not always needed, so be a bit
617 move_array good_move;
618 bool good_move_filled = false;
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.
626 // First, check whether the monster is smart enough to even consider
628 if ((newpos == you.pos()
629 || monster_at(newpos) && mons->foe == env.mgrid(newpos))
630 && mons_intel(*mons) > I_BRAINLESS
632 && !mons_is_confused(*mons) && !mons->caught()
633 && !mons->berserk_or_insane())
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
641 // a) the neighbouring grids are blocked and an ally is behind us,
643 // b) we're intelligent and blocking a ranged attack
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))))
654 if (good_move[mmov.x+1][0])
656 if (good_move[mmov.x+1][2] && (mmov.y == 0 || coinflip()))
660 else if (mmov.x == 0)
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))))
670 if (good_move[0][mmov.y+1])
672 if (good_move[2][mmov.y+1] && (mmov.x == 0 || coinflip()))
676 else // We're moving diagonally.
678 if (good_move[mmov.x+1][1])
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)))
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)))
702 // Now quit if we can't move.
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()))
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
718 // Doesn't matter for arena mode.
719 if (crawl_state.game_is_arena())
722 // Did we just come into view?
723 // TODO: This doesn't seem to work right. Fix, or remove?
725 if (mons->seen_context != SC_JUST_SEEN)
727 if (testbits(mons->flags, MF_WAS_IN_VIEW))
730 const coord_def old_pos = mons->pos();
731 const int old_dist = grid_distance(you.pos(), old_pos);
733 // We're already staying in the player's LOS.
734 if (you.see_cell(old_pos + mmov))
737 // We're not moving towards the player.
738 if (grid_distance(you.pos(), old_pos + mmov) >= old_dist)
740 // Instead of moving out of view, we stay put.
741 if (you.see_cell(old_pos))
746 // Try to find a move that brings us closer to the player while
747 // keeping us in view.
749 for (int i = 0; i < 3; i++)
750 for (int j = 0; j < 3; j++)
752 if (i == 0 && j == 0)
755 coord_def d(i - 1, j - 1);
756 coord_def tmp = old_pos + d;
757 if (!you.see_cell(tmp))
760 if (!good_move_filled)
762 _fill_good_move(mons, &good_move);
763 good_move_filled = true;
765 if (!good_move[i][j])
768 if (grid_distance(you.pos(), tmp) < old_dist)
770 if (one_chance_in(++matches))
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))
782 static bool _handle_potion(monster& mons)
784 item_def* potion = mons.mslot_item(MSLOT_POTION);
788 || mons_itemuse(mons) < MONUSE_STARTING_EQUIPMENT
789 || potion->base_type != OBJ_POTIONS)
796 const potion_type ptype = static_cast<potion_type>(potion->sub_type);
798 if (mons.can_drink_potion(ptype) && mons.should_drink_potion(ptype))
800 const bool was_visible = you.can_see(mons);
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();
807 // Drink the potion, and identify it.
808 if (mons.drink_potion_effect(ptype) && was_visible)
809 set_ident_type(OBJ_POTIONS, ptype, true);
811 // Remove it from inventory.
812 if (dec_mitm_item_quantity(potion->index(), 1))
813 mons.inv[MSLOT_POTION] = NON_ITEM;
815 mons.lose_energy(EUT_ITEM);
822 static bool _handle_evoke_equipment(monster& mons)
824 // TODO: check non-ring, non-amulet equipment
825 item_def* jewel = mons.mslot_item(MSLOT_JEWELLERY);
827 || mons_is_confused(mons)
830 || mons_itemuse(mons) < MONUSE_STARTING_EQUIPMENT
831 || jewel->base_type != OBJ_JEWELLERY)
838 const jewellery_type jtype = static_cast<jewellery_type>(jewel->sub_type);
840 if (mons.can_evoke_jewellery(jtype) && mons.should_evoke_jewellery(jtype))
842 const bool was_visible = you.can_see(mons);
844 // Evoke the item, and identify it.
845 if (mons.evoke_jewellery_effect(jtype) && was_visible)
846 set_ident_type(OBJ_JEWELLERY, jtype, true);
848 mons.lose_energy(EUT_ITEM);
856 * Check if the monster has a swooping attack and is in a position to
857 * use it, and do so if they can.
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
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
868 static bool _handle_swoop(monster& mons)
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)
874 actor *defender = mons.get_foe();
875 if (mons.confused() || !defender || !mons.can_see(*defender))
878 if (mons.foe_distance() >= 5 || mons.foe_distance() == 1)
881 if (!one_chance_in(4))
884 if (mons.props.exists("swoop_cooldown")
885 && (you.elapsed_time < mons.props["swoop_cooldown"].get_int()))
890 coord_def target = defender->pos();
893 tracer.source = mons.pos();
894 tracer.target = target;
895 tracer.is_tracer = true;
896 tracer.pierce = true;
897 tracer.range = LOS_RADIUS;
900 for (unsigned int j = 0; j < tracer.path_taken.size() - 1; ++j)
902 if (tracer.path_taken[j] != target)
905 if (!monster_habitable_grid(&mons, env.grid(tracer.path_taken[j+1]))
906 || actor_at(tracer.path_taken[j+1]))
911 if (you.can_see(mons))
913 mprf("%s swoops through the air toward %s!",
914 mons.name(DESC_THE).c_str(),
915 defender->name(DESC_THE).c_str());
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
928 * Check whether this monster can make a reaching attack, and do so if
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.
936 static bool _handle_reaching(monster* mons)
939 const reach_type range = mons->reach_range();
940 actor *foe = mons->get_foe();
943 || mons_is_confused(*mons)
945 || range <= REACH_NONE
946 || is_sanctuary(mons->pos())
947 || is_sanctuary(foe->pos())
949 || (mons_aligned(mons, foe) && !mons->has_ench(ENCH_INSANE))
950 || (mons_is_fleeing(*mons)
951 || mons->pacified()))
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);
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
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))
976 ASSERT(foe->is_player() || foe->is_monster());
978 fight_melee(mons, foe);
984 static bool _handle_scroll(monster& mons)
986 item_def* scroll = mons.mslot_item(MSLOT_SCROLL);
988 // Yes, there is a logic to this ordering {dlb}:
990 || mons_is_confused(mons)
993 || mons.has_ench(ENCH_BLIND)
995 || mons_itemuse(mons) < MONUSE_STARTING_EQUIPMENT
996 || silenced(mons.pos())
997 || scroll->base_type != OBJ_SCROLLS)
1003 bool was_visible = you.can_see(mons);
1005 // Notice how few cases are actually accounted for here {dlb}:
1006 const int scroll_type = scroll->sub_type;
1007 switch (scroll_type)
1009 case SCR_TELEPORTATION:
1010 if (!mons.has_ench(ENCH_TP) && !mons.no_tele(true, false))
1012 if (mons.caught() || mons_is_fleeing(mons) || mons.pacified())
1014 simple_monster_message(mons, " reads a scroll.");
1016 monster_teleport(&mons, false);
1022 if ((mons.caught() || mons_is_fleeing(mons) || mons.pacified())
1023 && mons.can_see(you) && !mons.no_tele(true, false))
1025 simple_monster_message(mons, " reads a scroll.");
1028 monster_blink(&mons);
1035 if (mons.can_see(you))
1037 simple_monster_message(mons, " reads a scroll.");
1038 mprf("Wisps of shadow swirl around %s.", mons.name(DESC_THE).c_str());
1040 int count = roll_dice(2, 2);
1041 for (int i = 0; i < count; ++i)
1044 mgen_data(RANDOM_MOBILE_MONSTER, SAME_ATTITUDE((&mons)),
1045 mons.pos(), mons.foe)
1046 .set_summoned(&mons, 3, MON_SUMM_SCROLL));
1054 if (dec_mitm_item_quantity(mons.inv[MSLOT_SCROLL], 1))
1055 mons.inv[MSLOT_SCROLL] = NON_ITEM;
1058 set_ident_type(OBJ_SCROLLS, scroll_type, true);
1060 mons.lose_energy(EUT_ITEM);
1066 static void _mons_fire_wand(monster& mons, item_def &wand, bolt &beem,
1069 if (!simple_monster_message(mons, " zaps a wand."))
1071 if (!silenced(you.pos()))
1072 mprf(MSGCH_SOUND, "You hear a zap.");
1075 // charge expenditure {dlb}
1077 const spell_type mzap =
1078 spell_in_wand(static_cast<wand_type>(wand.sub_type));
1080 mons_cast(&mons, beem, mzap, MON_SPELL_EVOKE, false);
1084 if (wand.charges <= 0)
1085 mprf("The now-empty wand crumbles to dust.");
1087 mons.flags |= MF_SEEN_RANGED;
1090 if (wand.charges <= 0)
1091 dec_mitm_item_quantity(wand.index(), 1);
1093 mons.lose_energy(EUT_ITEM);
1096 static bool _handle_wand(monster& mons)
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())
1104 || mons_is_fleeing(mons)
1107 || mons_itemuse(mons) < MONUSE_STARTING_EQUIPMENT
1108 || mons.has_ench(ENCH_SUBMERGED)
1109 || x_chance_in_y(3, 4)
1111 || wand->base_type != OBJ_WANDS)
1116 if (wand->charges <= 0)
1119 if (item_type_removed(wand->base_type, wand->sub_type))
1122 // XXX: Teach monsters to use random effects
1123 // Digging is handled elsewhere so that sensible (wall) targets are
1125 if (wand->sub_type == WAND_RANDOM_EFFECTS
1126 || wand->sub_type == WAND_DIGGING)
1133 const spell_type mzap =
1134 spell_in_wand(static_cast<wand_type>(wand->sub_type));
1136 if (!setup_mons_cast(&mons, beem, mzap, true))
1139 beem.source = mons.pos();
1141 wand->name(DESC_QUALNAME, false, true, false, false);
1143 bool should_fire = false;
1144 const wand_type kind = (wand_type)wand->sub_type;
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;
1152 // Intentional fallthrough
1154 fire_tracer(&mons, beem);
1155 should_fire = mons_should_fire(beem);
1161 _mons_fire_wand(mons, *wand, beem, you.see_cell(mons.pos()));
1168 bool handle_throw(monster* mons, bolt & beem, bool teleport, bool check_only)
1170 // Yes, there is a logic to this ordering {dlb}:
1171 if (mons->incapacitated()
1172 || mons->submerged()
1174 || mons_is_confused(*mons))
1179 if (mons_itemuse(*mons) < MONUSE_STARTING_EQUIPMENT
1180 && mons->type != MONS_SPECTRAL_THING)
1185 const bool prefer_ranged_attack = mons_class_flag(mons->type,
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.
1193 const bool liquefied = mons->liquefied_ground();
1195 // Don't allow offscreen throwing for now.
1196 if (mons->foe == MHITYOU && !you.see_cell(mons->pos()))
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()))
1204 if (!prefer_ranged_attack)
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.
1209 else if (!teleport &&
1210 (liquefied && !master_archer && one_chance_in(9)
1211 || !liquefied && one_chance_in(master_archer ? 9 : 5)))
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?
1223 // Don't let fleeing (or pacified creatures) stop to shoot at things
1224 if (mons_is_fleeing(*mons) || mons->pacified())
1227 item_def *launcher = nullptr;
1228 const item_def *weapon = nullptr;
1229 const int mon_item = mons_usable_missile(mons, &launcher);
1231 if (mon_item == NON_ITEM || !env.item[mon_item].defined())
1234 if (player_or_mon_in_sanct(*mons))
1237 item_def *missile = &env.item[mon_item];
1239 const actor *act = actor_at(beem.target);
1240 ASSERT(missile->base_type == OBJ_MISSILES);
1241 if (act && missile->sub_type == MI_THROWING_NET)
1243 // Throwing a net at a target that is already caught would be
1244 // completely useless, so bail out.
1247 // Netting targets that are already permanently stuck in place
1248 // is similarly useless.
1249 if (mons_class_is_stationary(act->type))
1253 // If the attack needs a launcher that we can't wield, bail out.
1256 weapon = mons->mslot_item(MSLOT_WEAPON);
1257 if (weapon && weapon != launcher && weapon->cursed())
1261 // Ok, we'll try it.
1262 setup_monster_throw_beam(mons, beem);
1264 // Set fake damage for the tracer.
1265 beem.damage = dice_def(10, 10);
1267 // Set item for tracer, even though it probably won't be used
1268 beem.item = missile;
1270 ru_interference interference = DO_NOTHING;
1271 // See if Ru worshippers block or redirect the attack.
1272 if (does_ru_wanna_redirect(mons))
1274 interference = get_ru_attack_interference_level();
1275 if (interference == DO_BLOCK_ATTACK)
1277 simple_monster_message(*mons,
1278 " is stunned by your will and fails to attack.",
1282 else if (interference == DO_REDIRECT_ATTACK)
1284 mprf(MSGCH_GOD, "You redirect %s's attack!",
1285 mons->name(DESC_THE).c_str());
1287 for (radius_iterator ri(you.pos(),
1288 LOS_DEFAULT); ri; ++ri)
1290 monster* new_target = monster_at(*ri);
1292 if (new_target == nullptr
1293 || mons_is_projectile(new_target->type)
1294 || mons_is_firewood(*new_target)
1295 || new_target->friendly())
1302 if (one_chance_in(++pfound))
1304 mons->target = new_target->pos();
1305 mons->foe = new_target->mindex();
1306 beem.target = mons->target;
1314 fire_tracer(mons, beem);
1316 // Clear fake damage (will be set correctly in mons_throw).
1317 beem.damage = dice_def();
1320 if (teleport || mons_should_fire(beem) || interference != DO_NOTHING)
1325 // Monsters shouldn't shoot if fleeing, so let them "turn to attack".
1326 make_mons_stop_fleeing(mons);
1328 if (launcher && launcher != weapon)
1329 mons->swap_weapons();
1332 return mons_throw(mons, beem, mon_item, teleport);
1338 // Give the monster its action energy (aka speed_increment).
1339 static void _monster_add_energy(monster& mons)
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;
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());
1357 # define DEBUG_ENERGY_USE(problem) ((void) 0)
1360 static void _confused_move_dir(monster *mons)
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();
1369 static int _tentacle_move_speed(monster_type type)
1371 if (type == MONS_KRAKEN)
1373 else if (type == MONS_TENTACLED_STARSPAWN)
1379 static void _pre_monster_move(monster& mons)
1381 mons.hit_points = min(mons.max_hit_points, mons.hit_points);
1383 if (mons.type == MONS_SPATIAL_MAELSTROM
1384 && !player_in_branch(BRANCH_ABYSS)
1385 && !player_in_branch(BRANCH_ZIGGURAT))
1387 for (int i = 0; i < you.time_taken; ++i)
1389 if (one_chance_in(100))
1397 if (mons.has_ench(ENCH_HEXED))
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);
1405 if (mons.type == MONS_SNAPLASHER_VINE
1406 && mons.props.exists("vine_awakener"))
1408 monster* awakener = monster_by_mid(mons.props["vine_awakener"].get_int());
1409 if (awakener && !awakener->can_see(mons))
1411 simple_monster_message(mons, " falls limply to the ground.");
1412 monster_die(mons, KILL_RESET, NON_MONSTER);
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))
1424 if (mons.type == MONS_FOXFIRE)
1425 check_place_cloud(CLOUD_FLAME, mons.pos(), 2, &mons);
1426 monster_die(mons, KILL_RESET, NON_MONSTER);
1430 if (mons_stores_tracking_data(mons))
1432 actor* foe = mons.get_foe();
1435 if (!mons.props.exists("foe_pos"))
1436 mons.props["foe_pos"].get_coord() = foe->pos();
1439 if (mons.props["foe_pos"].get_coord().distance_from(mons.pos())
1440 > foe->pos().distance_from(mons.pos()))
1442 mons.props["foe_approaching"].get_bool() = true;
1445 mons.props["foe_approaching"].get_bool() = false;
1447 mons.props["foe_pos"].get_coord() = foe->pos();
1451 mons.props.erase("foe_pos");
1454 reset_battlesphere(&mons);
1455 reset_spectral_weapon(&mons);
1457 fedhas_neutralise(&mons);
1458 slime_convert(&mons);
1460 // Monster just summoned (or just took stairs), skip this action.
1461 if (testbits(mons.flags, MF_JUST_SUMMONED))
1463 mons.flags &= ~MF_JUST_SUMMONED;
1467 mon_acting mact(&mons);
1469 _monster_add_energy(mons);
1471 // Handle clouds on nonmoving monsters.
1472 if (mons.speed == 0)
1474 _mons_in_cloud(mons);
1476 // Update constriction durations
1477 mons.accum_has_constricted();
1479 if (mons.type == MONS_NO_MONSTER)
1483 // Apply monster enchantments once for every normal-speed
1485 mons.ench_countdown -= you.time_taken;
1486 while (mons.ench_countdown < 0)
1488 mons.ench_countdown += 10;
1489 mons.apply_enchantments();
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)
1498 else if (mons.hit_points < 1)
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;
1507 // Otherwise there are potential problems with summonings.
1508 if (mons.type == MONS_GLOWING_SHAPESHIFTER)
1509 mons.add_ench(ENCH_GLOWING_SHAPESHIFTER);
1511 if (mons.type == MONS_SHAPESHIFTER)
1512 mons.add_ench(ENCH_SHAPESHIFTER);
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())
1524 simple_monster_message(mons, " hums quietly as it recharges.");
1528 void handle_monster_move(monster* mons)
1530 ASSERT(mons); // XXX: change to monster &mons
1531 const monsterentry* entry = get_monster_data(mons->type);
1535 const bool disabled = crawl_state.disables[DIS_MON_ACT]
1536 && _unfriendly_or_impaired(*mons);
1538 int old_energy = mons->speed_increment;
1539 int non_move_energy = min(entry->energy_usage.move,
1540 entry->energy_usage.swim);
1542 #ifdef DEBUG_MONS_SCAN
1543 bool monster_was_floating = env.mgrid(mons->pos()) != mons->mindex();
1545 coord_def old_pos = mons->pos();
1547 if (!mons->has_action_energy())
1551 move_solo_tentacle(mons);
1556 if (!disabled && mons_is_tentacle_head(mons_base_type(*mons)))
1557 move_child_tentacles(mons);
1559 old_pos = mons->pos();
1561 #ifdef DEBUG_MONS_SCAN
1562 if (!monster_was_floating
1563 && env.mgrid(mons->pos()) != mons->mindex())
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, "[[[[[[[[[[[[[[[[[[");
1570 mprf(MSGCH_WARN, "]]]]]]]]]]]]]]]]]]");
1571 monster_was_floating = true;
1573 else if (monster_was_floating
1574 && env.mgrid(mons->pos()) == mons->mindex())
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;
1583 if (mons_is_projectile(*mons))
1585 if (iood_act(*mons))
1587 mons->lose_energy(EUT_MOVE);
1591 if (mons->type == MONS_BATTLESPHERE)
1593 if (fire_battlesphere(mons))
1594 mons->lose_energy(EUT_SPECIAL);
1597 if (mons->type == MONS_FULMINANT_PRISM)
1599 ++mons->prism_charge;
1600 if (mons->prism_charge == 2)
1604 if (player_can_hear(mons->pos()))
1606 if (you.can_see(*mons))
1608 simple_monster_message(*mons, " crackles loudly.",
1612 mprf(MSGCH_SOUND, "You hear a loud crackle.");
1614 // Done this way to keep the detonation timer predictable
1615 mons->speed_increment -= BASELINE_DELAY;
1620 if (mons->type == MONS_FOXFIRE)
1622 if (mons->steps_remaining == 0)
1624 check_place_cloud(CLOUD_FLAME, mons->pos(), 2, mons);
1630 mons->shield_blocks = 0;
1632 _mons_in_cloud(*mons);
1633 actor_apply_toxic_bog(mons);
1638 if (env.level_state & LSTATE_SLIMY_WALL)
1639 slime_wall_damage(mons, speed_to_duration(mons->speed));
1644 if (env.level_state & LSTATE_ICY_WALL)
1645 ice_wall_damage(*mons, speed_to_duration(mons->speed));
1650 if (mons->type == MONS_TIAMAT && one_chance_in(3))
1651 draconian_change_colour(mons);
1653 _monster_regenerate(mons);
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))
1662 mons->speed_increment -= non_move_energy;
1666 if (mons->has_ench(ENCH_DAZED) && one_chance_in(4))
1668 simple_monster_message(*mons, " is lost in a daze.");
1669 mons->speed_increment -= non_move_energy;
1673 if (mons->has_ench(ENCH_GOLD_LUST))
1675 mons->speed_increment -= non_move_energy;
1679 if (mons->has_ench(ENCH_BRILLIANCE_AURA))
1680 aura_of_brilliance(mons);
1682 if (you.duration[DUR_GOZAG_GOLD_AURA]
1683 && have_passive(passive_t::gold_aura)
1684 && you.see_cell(mons->pos())
1686 && !mons_is_conjured(mons->type)
1687 && !mons_is_tentacle_or_tentacle_segment(mons->type)
1688 && !mons_is_firewood(*mons)
1689 && !mons->wont_attack())
1691 const int gold = you.props[GOZAG_GOLD_AURA_KEY].get_int();
1692 if (bernoulli(gold, 3.0/100.0))
1694 if (gozag_gold_in_los(mons))
1696 simple_monster_message(*mons,
1697 " becomes distracted by the nearby gold, dreaming of "
1698 "imaginary riches.");
1700 else if (you.gold > 0)
1702 simple_monster_message(*mons,
1703 " becomes distracted by your gold, dreaming of "
1704 "imaginary riches.");
1709 simple_monster_message(*mons,
1710 " is distracted by dreams of imaginary riches.");
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;
1725 mons->speed_increment -= non_move_energy;
1729 handle_behaviour(mons);
1731 // handle_behaviour() could make the monster leave the level.
1735 ASSERT(!crawl_state.game_is_arena() || mons->foe != MHITYOU);
1736 ASSERT_IN_BOUNDS_OR_ORIGIN(mons->target);
1738 if (mons->speed >= 100)
1740 mons->speed_increment -= non_move_energy;
1744 if (_handle_pickup(mons))
1746 DEBUG_ENERGY_USE("handle_pickup()");
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))
1754 if (mons->foe != MHITNOT
1755 && grid_distance(mons->target, mons->pos()) <= 1)
1757 if (mons->submerged())
1759 if (!mons->del_ench(ENCH_SUBMERGED))
1761 // Couldn't unsubmerge.
1762 mons->speed_increment -= non_move_energy;
1766 mons->behaviour = BEH_SEEK;
1770 mons->speed_increment -= non_move_energy;
1777 // Struggling against the net takes time.
1778 _swim_or_move_energy(*mons);
1780 else if (!mons->petrified())
1782 // Calculates mmov based on monster target.
1783 _handle_movement(mons);
1785 // Confused monsters sometimes stumble about instead of moving with
1787 if (mons_is_confused(*mons) && !one_chance_in(3))
1789 set_random_target(mons);
1790 _confused_move_dir(mons);
1793 if (!mons->asleep() && !mons->submerged())
1794 maybe_mons_speaks(mons);
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;
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)
1811 // Prevents unfriendlies from nuking you from offscreen.
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)
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))
1829 DEBUG_ENERGY_USE("spell or special");
1835 const bool prefer_ranged = mons_class_flag(mons->type, M_PREFER_RANGED);
1837 if (friendly_or_near)
1839 if (_handle_potion(*mons))
1841 DEBUG_ENERGY_USE("_handle_potion()");
1845 if (_handle_scroll(*mons))
1847 DEBUG_ENERGY_USE("_handle_scroll()");
1851 if (_handle_evoke_equipment(*mons))
1853 DEBUG_ENERGY_USE("_handle_evoke_equipment()");
1857 if (_handle_wand(*mons))
1859 DEBUG_ENERGY_USE("_handle_wand()");
1863 if (_handle_swoop(*mons))
1865 DEBUG_ENERGY_USE("_handle_swoop()");
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))
1873 DEBUG_ENERGY_USE("_handle_reaching()");
1878 bolt beem = setup_targetting_beam(*mons);
1879 if (handle_throw(mons, beem, false, false))
1881 DEBUG_ENERGY_USE("_handle_throw()");
1885 if (friendly_or_near && prefer_ranged && _handle_reaching(mons))
1887 DEBUG_ENERGY_USE("_handle_reaching()");
1892 if (!mons->caught())
1894 if (mons->pos() + mmov == you.pos())
1896 ASSERT(!crawl_state.game_is_arena());
1898 if (_unfriendly_or_impaired(*mons)
1899 && !mons->has_ench(ENCH_CHARM)
1900 && !mons->has_ench(ENCH_HEXED))
1902 monster* new_target = 0;
1903 if (!mons->wont_attack())
1905 // Otherwise, if it steps into you, cancel other targets.
1906 mons->foe = MHITYOU;
1907 mons->target = you.pos();
1909 // Check to see if your religion redirects the attack
1910 if (does_ru_wanna_redirect(mons))
1912 ru_interference interference =
1913 get_ru_attack_interference_level();
1914 if (interference == DO_BLOCK_ATTACK)
1916 simple_monster_message(*mons,
1917 " is stunned by your will and fails to attack.",
1919 mons->speed_increment -= non_move_energy;
1922 else if (interference == DO_REDIRECT_ATTACK)
1926 for (adjacent_iterator ai(mons->pos(), false); ai; ++ai)
1928 monster* candidate = monster_at(*ai);
1929 if (candidate == nullptr
1930 || mons_is_projectile(candidate->type)
1931 || mons_is_firewood(*candidate)
1932 || candidate->friendly())
1937 if (one_chance_in(++pfound))
1938 new_target = candidate;
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);
1954 fight_melee(mons, &you);
1956 if (mons_is_batty(*mons))
1958 DEBUG_ENERGY_USE("fight_melee()");
1964 // See if we move into (and fight) an unfriendly monster.
1965 monster* targ = monster_at(mons->pos() + mmov);
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))
1971 const bool basis = targ->props.exists("outwards");
1972 monster* outward = basis ? monster_by_mid(targ->props["outwards"].get_int()) : nullptr;
1974 outward->props["inwards"].get_int() = mons->mid;
1976 monster_die(*targ, KILL_MISC, NON_MONSTER, true);
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))
1987 // Maybe they can swap places?
1988 if (_swap_monsters(*mons, *targ))
1990 _swim_or_move_energy(*mons);
1993 // Figure out if they fight.
1994 else if ((!mons_is_firewood(*targ)
1995 || mons->is_child_tentacle())
1996 && fight_melee(mons, targ))
1998 if (mons_is_batty(*mons))
2002 DEBUG_ENERGY_USE("fight_melee()");
2006 else if (mons->behaviour == BEH_WITHDRAW
2007 && ((targ && targ != mons && targ->friendly())
2008 || (you.pos() == mons->pos() + mmov)))
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");
2015 if (invalid_monster(mons) || mons->is_stationary())
2017 if (mons->speed_increment == old_energy)
2018 mons->speed_increment -= non_move_energy;
2022 if (mons->cannot_move() || !_monster_move(mons))
2023 mons->speed_increment -= non_move_energy;
2025 you.update_beholder(mons);
2026 you.update_fearmonger(mons);
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. :)
2033 handle_behaviour(mons);
2034 ASSERT_IN_BOUNDS_OR_ORIGIN(mons->target);
2037 if (mons_is_tentacle_head(mons_base_type(*mons)))
2039 move_child_tentacles(mons);
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)
2046 move_child_tentacles(mons);
2047 mons->move_spurt -= 100;
2053 * Let trapped monsters struggle against nets, webs, etc.
2055 void monster::struggle_against_net()
2057 if (is_stationary() || cannot_act() || asleep())
2060 if (props.exists(NEWLY_TRAPPED_KEY))
2062 props.erase(NEWLY_TRAPPED_KEY);
2063 return; // don't try to escape on the same turn you were trapped!
2066 int net = get_trapping_net(pos(), true);
2068 if (net == NON_ITEM)
2070 trap_def *trap = trap_at(pos());
2071 if (trap && trap->type == TRAP_WEB)
2075 if (you.see_cell(pos()))
2077 if (!visible_to(&you))
2078 mpr("Something you can't see is thrashing in a web.");
2080 simple_monster_message(*this,
2081 " struggles to get unstuck from the web.");
2086 monster_web_cleanup(*this);
2087 del_ench(ENCH_HELD);
2091 if (you.see_cell(pos()))
2093 if (!visible_to(&you))
2094 mpr("Something wriggles in the net.");
2096 simple_monster_message(*this, " struggles against the net.");
2099 int damage = 1 + random2(2);
2101 // Faster monsters can damage the net more often per
2104 damage = div_rand_round(damage * speed, 10);
2106 env.item[net].net_durability -= damage;
2108 if (env.item[net].net_durability < NET_MIN_DURABILITY)
2110 if (you.see_cell(pos()))
2112 if (visible_to(&you))
2114 mprf("The net rips apart, and %s comes free!",
2115 name(DESC_THE).c_str());
2118 mpr("All of a sudden the net rips apart!");
2122 del_ench(ENCH_HELD, true);
2126 static void _ancient_zyme_sicken(monster* mons)
2128 if (is_sanctuary(mons->pos()))
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))
2139 if (!you.duration[DUR_SICKENING])
2141 mprf(MSGCH_WARN, "You feel yourself growing ill in the "
2143 mons->name(DESC_THE).c_str());
2146 you.duration[DUR_SICKENING] += (2 + random2(4)) * BASELINE_DELAY;
2147 if (you.duration[DUR_SICKENING] > 100)
2149 you.sicken(40 + random2(30));
2150 you.duration[DUR_SICKENING] = 0;
2155 if (x_chance_in_y(you.time_taken, 60))
2156 you.sicken(15 + random2(30));
2160 for (radius_iterator ri(mons->pos(), LOS_RADIUS, C_SQUARE); ri; ++ri)
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))
2167 m->sicken(2 * you.time_taken);
2173 * Apply the torpor snail slowing effect.
2175 * @param mons The snail applying the effect.
2177 static void _torpor_snail_slow(monster* mons)
2179 // XXX: might be nice to refactor together with _ancient_zyme_sicken().
2180 // XXX: also with torpor_slowed().... so many duplicated checks :(
2182 if (is_sanctuary(mons->pos())
2183 || mons->attitude != ATT_HOSTILE
2184 || mons->has_ench(ENCH_CHARM))
2189 if (!is_sanctuary(you.pos())
2191 && cell_see_cell(you.pos(), mons->pos(), LOS_SOLID_SEE))
2193 if (!you.duration[DUR_SLOW])
2195 mprf("Being near %s leaves you feeling lethargic.",
2196 mons->name(DESC_THE).c_str());
2199 if (you.duration[DUR_SLOW] <= 1)
2200 you.set_duration(DUR_SLOW, 1);
2201 you.props[TORPOR_SLOWED_KEY] = true;
2204 for (monster_near_iterator ri(mons->pos(), LOS_SOLID_SEE); ri; ++ri)
2207 if (m && !mons_aligned(mons, m) && !m->stasis()
2208 && !mons_is_conjured(m->type) && !m->is_stationary()
2209 && !is_sanctuary(m->pos()))
2211 m->add_ench(mon_enchant(ENCH_SLOW, 0, mons, 1));
2212 m->props[TORPOR_SLOWED_KEY] = true;
2217 static void _post_monster_move(monster* mons)
2219 if (invalid_monster(mons))
2222 mons->handle_constriction();
2224 if (mons->has_ench(ENCH_HELD))
2225 mons->struggle_against_net();
2227 if (mons->type == MONS_ANCIENT_ZYME)
2228 _ancient_zyme_sicken(mons);
2230 if (mons->type == MONS_TORPOR_SNAIL)
2231 _torpor_snail_slow(mons);
2233 if (mons->type == MONS_WATER_NYMPH)
2235 for (adjacent_iterator ai(mons->pos(), false); ai; ++ai)
2236 if (feat_has_solid_floor(env.grid(*ai))
2237 && (coinflip() || *ai == mons->pos()))
2239 if (env.grid(*ai) != DNGN_SHALLOW_WATER && env.grid(*ai) != DNGN_FLOOR
2240 && you.see_cell(*ai))
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());
2246 temp_change_terrain(*ai, DNGN_SHALLOW_WATER, random_range(50, 80),
2247 TERRAIN_CHANGE_FLOOD, mons);
2251 if (mons->type == MONS_GUARDIAN_GOLEM)
2252 guardian_golem_bond(*mons);
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"))
2260 mons->props.erase("emergency_clone");
2261 for (monster_iterator mi; mi; ++mi)
2263 if (mi->type == MONS_RAKSHASA && mi->summoner == mons->mid)
2264 mi->del_ench(ENCH_ABJ);
2268 update_mons_cloud_ring(mons);
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))
2275 cast_spectral_weapon(mons, mons->get_experience_level() * 4, mons->god);
2278 if (mons->foe != MHITNOT && mons_is_wandering(*mons) && mons_is_batty(*mons))
2280 int &bat_turns = mons->props[BATTY_TURNS_KEY].get_int();
2282 int turns_to_bat = div_rand_round(mons_base_speed(*mons), 10);
2283 if (turns_to_bat < 2)
2285 if (bat_turns >= turns_to_bat)
2286 mons->behaviour = BEH_SEEK;
2289 if (mons->type != MONS_NO_MONSTER && mons->hit_points < 1)
2290 monster_die(*mons, KILL_MISC, NON_MONSTER);
2293 priority_queue<pair<monster *, int>,
2294 vector<pair<monster *, int> >,
2295 MonsterActionQueueCompare> monster_queue;
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
2300 void queue_monster_for_action(monster* mons)
2302 monster_queue.emplace(mons, mons->speed_increment);
2305 static void _clear_monster_flags()
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;
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.
2319 * @param mon The targeted monster
2322 static void _update_monster_attitude(monster *mon)
2324 if (you.get_mutation_level(MUT_NO_LOVE)
2325 && !mons_is_conjured(mon->type))
2327 mon->attitude = ATT_HOSTILE;
2331 vector<monster *> just_seen_queue;
2333 void mons_set_just_seen(monster *mon)
2335 mon->seen_context = SC_JUST_SEEN;
2336 just_seen_queue.push_back(mon);
2339 void mons_reset_just_seen()
2341 // this may be called when the pointers are not valid, so don't mess with
2343 just_seen_queue.clear();
2346 static void _display_just_seen()
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()))
2353 for (auto m : just_seen_queue)
2355 if (!m || invalid_monster(m) || !m->alive())
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()))
2361 mprf(MSGCH_PLAIN, "%s moves out of view.",
2362 m->name(DESC_THE, true).c_str());
2366 mons_reset_just_seen();
2370 * Get all monsters to make an action, if they can/want to.
2372 * @param with_noise whether to process noises after the loop.
2374 void handle_monsters(bool with_noise)
2376 for (monster_iterator mi; mi; ++mi)
2378 _pre_monster_move(**mi);
2379 if (!invalid_monster(*mi) && mi->alive() && mi->has_action_energy())
2380 monster_queue.emplace(*mi, mi->speed_increment);
2383 int tries = 0; // infinite loop protection, shouldn't be ever needed
2384 while (!monster_queue.empty())
2386 if (tries++ > 32767)
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());
2393 monster *mon = monster_queue.top().first;
2394 const int oldspeed = monster_queue.top().second;
2395 monster_queue.pop();
2397 if (invalid_monster(mon) || !mon->alive() || !mon->has_action_energy())
2400 _update_monster_attitude(mon);
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)
2408 handle_monster_move(mon);
2409 _post_monster_move(mon);
2410 fire_final_effects();
2413 if (mon->has_action_energy())
2414 monster_queue.emplace(mon, mon->speed_increment);
2416 // If the player got banished, discard pending monster actions.
2419 // Clear list of mesmerising monsters.
2420 you.clear_beholders();
2421 you.clear_fearmongers();
2422 you.stop_constricting_all();
2423 you.stop_being_constricted();
2427 _display_just_seen();
2429 // Process noises now (before clearing the sleep flag).
2433 _clear_monster_flags();
2436 static bool _jelly_divide(monster& parent)
2438 if (!mons_class_flag(parent.type, M_SPLITS))
2441 const int reqd = max(parent.get_experience_level() * 8, 50);
2442 if (parent.hit_points < reqd)
2445 monster* child = nullptr;
2446 coord_def child_spot;
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))
2460 // Now that we have a spot, find a monster slot {dlb}:
2461 child = get_free_monster();
2465 // Handle impact of split on parent {dlb}:
2466 parent.max_hit_points /= 2;
2468 if (parent.hit_points > parent.max_hit_points)
2469 parent.hit_points = parent.max_hit_points;
2471 parent.init_experience();
2472 parent.experience = parent.experience * 3 / 5 + 1;
2474 // Create child {dlb}:
2475 // This is terribly partial and really requires
2476 // more thought as to generation ... {dlb}
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);
2483 if (!simple_monster_message(parent, " splits in two!")
2484 && (player_can_hear(parent.pos()) || player_can_hear(child->pos())))
2486 mprf(MSGCH_SOUND, "You hear a squelching noise.");
2489 if (crawl_state.game_is_arena())
2490 arena_placed_monster(child);
2495 // Only Jiyva jellies eat items.
2496 static bool _monster_eat_item(monster* mons)
2498 if (!mons_eats_items(*mons))
2501 // Off-limit squares are off-limit.
2502 if (testbits(env.pgrid(mons->pos()), FPROP_NO_JIYVA))
2505 int hps_changed = 0;
2506 int max_eat = roll_dice(1, 10);
2508 bool shown_msg = false;
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)
2514 if (!item_is_jelly_edible(*si))
2517 dprf("%s eating %s", mons->name(DESC_PLAIN, true).c_str(),
2518 si->name(DESC_PLAIN).c_str());
2520 int quant = si->quantity;
2522 if (si->base_type != OBJ_GOLD)
2524 quant = min(quant, max_eat - eaten);
2526 hps_changed += quant * 3;
2531 // Shouldn't be much trouble to digest a huge pile of gold!
2533 quant = 500 + roll_dice(2, (quant - 500) / 2);
2535 hps_changed += quant / 10 + 1;
2539 if (eaten && !shown_msg && player_can_hear(mons->pos()))
2541 mprf(MSGCH_SOUND, "You hear a%s slurping noise.",
2542 you.see_cell(mons->pos()) ? "" : " distant");
2546 if (you_worship(GOD_JIYVA))
2547 jiyva_slurp_item_stack(*si, quant);
2549 if (quant >= si->quantity)
2550 item_was_destroyed(*si);
2551 dec_mitm_item_quantity(si.index(), quant);
2556 hps_changed = max(hps_changed, 1);
2557 hps_changed = min(hps_changed, 50);
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);
2567 _jelly_divide(*mons);
2574 static bool _handle_pickup(monster* mons)
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())
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());
2589 if ((feat == DNGN_LAVA || feat == DNGN_DEEP_WATER) && mons->airborne())
2592 int count_pickup = 0;
2594 if (mons_eats_items(*mons) && _monster_eat_item(mons))
2597 if (mons_itemuse(*mons) < MONUSE_WEAPONS_ARMOUR)
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);
2608 // Note: Monsters only look at stuff near the top of stacks.
2610 // XXX: Need to put in something so that monster picks up
2611 // multiple items (e.g. ammunition) identical to those it's
2614 // Monsters may now pick up up to two items in the same turn.
2616 for (stack_iterator si(mons->pos()); si; ++si)
2618 if (!crawl_state.game_is_arena()
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.
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))
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)
2637 if (si->flags & ISFLAG_NO_PICKUP)
2640 if (mons->pickup_item(*si, you.see_cell(mons->pos()), false))
2643 if (count_pickup > 1 || coinflip())
2647 return count_pickup > 0;
2650 static void _mons_open_door(monster& mons, const coord_def &pos)
2652 const char *adj = "", *noun = "door";
2654 bool was_seen = false;
2656 set<coord_def> all_door;
2657 find_connected_identical(pos, all_door);
2658 get_door_description(all_door.size(), &adj, &noun);
2660 for (const auto &dc : all_door)
2662 if (you.see_cell(dc))
2666 set_terrain_changed(dc);
2674 string open_str = "opens the ";
2679 // Should this be conditionalized on you.can_see(mons?)
2680 mons.seen_context = (all_door.size() <= 2) ? SC_DOOR : SC_GATE;
2682 if (!you.can_see(mons))
2684 mprf("Something unseen %s", open_str.c_str());
2685 interrupt_activity(activity_interrupt::force);
2687 else if (!you_are_delayed())
2689 mprf("%s %s", mons.name(DESC_A).c_str(),
2694 mons.lose_energy(EUT_MOVE);
2696 dungeon_events.fire_position_event(DET_DOOR_OPENED, pos);
2699 static bool _no_habitable_adjacent_grids(const monster* mon)
2701 for (adjacent_iterator ai(mon->pos()); ai; ++ai)
2702 if (monster_habitable_grid(mon, env.grid(*ai)))
2708 static bool _same_tentacle_parts(const monster* mpusher,
2709 const monster* mpushee)
2711 if (!mons_is_tentacle_head(mons_base_type(*mpusher)))
2714 if (mpushee->is_child_tentacle_of(mpusher))
2717 if (mons_tentacle_adjacent(mpusher, mpushee))
2723 static bool _mons_can_displace(const monster* mpusher,
2724 const monster* mpushee)
2726 if (invalid_monster(mpusher) || invalid_monster(mpushee))
2729 const int ipushee = mpushee->mindex();
2730 if (invalid_monster_index(ipushee))
2733 if (mpusher->type == MONS_WANDERING_MUSHROOM
2734 && mpushee->type == MONS_TOADSTOOL
2735 || mpusher->type == MONS_TOADSTOOL
2736 && mpushee->type == MONS_WANDERING_MUSHROOM)
2741 // Foxfires can always be pushed
2742 if (mpushee->type == MONS_FOXFIRE)
2743 return !mons_aligned(mpushee, mpusher); // But allies won't do it
2745 if (!mpushee->has_action_energy()
2746 && !_same_tentacle_parts(mpusher, mpushee))
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())
2766 // OODs should crash into things, not push them around.
2767 if (mons_is_projectile(*mpusher) || mons_is_projectile(*mpushee))
2770 // Fleeing monsters cannot push past other fleeing monsters
2771 // (This helps to prevent some traffic jams in confined spaces)
2772 if (mons_is_fleeing(*mpusher) && mons_is_fleeing(*mpushee))
2775 // Batty monsters are unpushable.
2776 if (mons_is_batty(*mpusher) || mons_is_batty(*mpushee))
2779 // Anyone can displace a submerged monster.
2780 if (mpushee->submerged())
2783 if (!monster_shover(*mpusher))
2786 // Fleeing monsters of the same type may push past higher ranking ones.
2787 if (!monster_senior(*mpusher, *mpushee, mons_is_retreating(*mpusher)))
2793 // Returns true if the monster should try to avoid that position
2794 // because of taking damage from damaging walls.
2795 static bool _check_damaging_walls(const monster *mon,
2796 const coord_def &targ)
2798 const bool have_slimy = env.level_state & LSTATE_SLIMY_WALL;
2799 const bool have_icy = env.level_state & LSTATE_ICY_WALL;
2801 if (!have_slimy && !have_icy)
2804 if (!have_icy && actor_slime_wall_immune(mon)
2805 || mons_intel(*mon) <= I_BRAINLESS)
2810 // Monsters are only ever affected by one wall at a time, so we don't care
2811 // about wall counts past 1.
2812 const bool target_damages = count_adjacent_slime_walls(targ)
2813 + count_adjacent_icy_walls(targ);
2816 if (!target_damages)
2819 const bool current_damages = count_adjacent_slime_walls(mon->pos())
2820 + count_adjacent_icy_walls(mon->pos());
2822 // We're already taking damage, so moving into damage is fine.
2823 if (current_damages)
2826 // The monster needs to have a purpose to risk taking damage.
2827 if (!mons_is_seeking(*mon))
2830 // With enough hit points monsters will consider moving
2831 // onto more dangerous squares.
2832 return mon->hit_points < mon->max_hit_points / 2;
2835 // Check whether a monster can move to given square (described by its relative
2836 // coordinates to the current monster position). just_check is true only for
2837 // calls from is_trap_safe when checking the surrounding squares of a trap.
2838 bool mon_can_move_to_pos(const monster* mons, const coord_def& delta,
2841 const coord_def targ = mons->pos() + delta;
2843 // Bounds check: don't consider moving out of grid!
2844 if (!in_bounds(targ))
2847 // Non-friendly and non-good neutral monsters won't enter
2849 if (is_sanctuary(targ)
2850 && !is_sanctuary(mons->pos())
2851 && !mons->wont_attack())
2856 // Inside a sanctuary don't attack anything!
2857 if (is_sanctuary(mons->pos()) && actor_at(targ))
2860 const dungeon_feature_type target_grid = env.grid(targ);
2861 const habitat_type habitat = mons_primary_habitat(*mons);
2863 // No monster may enter the open sea.
2864 if (feat_is_endless(target_grid))
2867 // A confused monster will happily go wherever it can, regardless of
2869 if (mons->confused() && mons->can_pass_through(targ))
2872 if (mons_avoids_cloud(mons, targ))
2875 if (_check_damaging_walls(mons, targ))
2878 const bool digs = _mons_can_cast_dig(mons, false)
2879 || _mons_can_zap_dig(mons);
2880 if ((target_grid == DNGN_ROCK_WALL || target_grid == DNGN_CLEAR_ROCK_WALL)
2881 && (mons_class_flag(mons->type, M_BURROWS) || digs)
2882 || mons->type == MONS_SPATIAL_MAELSTROM
2883 && feat_is_solid(target_grid) && !feat_is_permarock(target_grid)
2884 && !feat_is_critical(target_grid)
2885 || feat_is_tree(target_grid) && mons_flattens_trees(*mons)
2886 || target_grid == DNGN_GRATE && digs)
2889 else if (!mons_can_traverse(*mons, targ, false, false)
2890 && !monster_habitable_grid(mons, target_grid))
2892 // If the monster somehow ended up in this habitat (and is
2893 // not dead by now), give it a chance to get out again.
2894 if (env.grid(mons->pos()) == target_grid && mons->ground_level()
2895 && _no_habitable_adjacent_grids(mons))
2903 // These monsters usually don't move while you are looking.
2904 if (mons->type == MONS_WANDERING_MUSHROOM
2905 || mons->type == MONS_DEATHCAP
2906 || (mons->type == MONS_LURKING_HORROR
2907 && mons->foe_distance() > random2(LOS_DEFAULT_RANGE + 1)))
2909 if (!mons->wont_attack() && is_sanctuary(mons->pos()))
2912 if (!mons->friendly() && you.see_cell(targ)
2913 || mon_enemies_around(mons))
2919 if (mons->type == MONS_MERFOLK_AVATAR)
2921 // Don't voluntarily break LoS with a player we're mesmerising
2922 if (you.beheld_by(*mons) && !you.see_cell(targ))
2925 // And path around players instead of into them
2926 if (you.pos() == targ)
2930 // Try to avoid deliberately blocking the player's line of fire.
2931 if (mons->type == MONS_SPELLFORGED_SERVITOR)
2933 const actor * const summoner = actor_by_mid(mons->summoner);
2935 if (!summoner) // XXX
2938 // Only check if our target is something the caster could theoretically
2940 if (mons->get_foe() && mons->target != summoner->pos()
2941 && summoner->see_cell_no_trans(mons->target))
2944 if (find_ray(summoner->pos(), mons->target, ray, opc_immob))
2946 while (ray.advance())
2948 // Either we've reached the end of the ray, or we're already
2949 // (maybe) in the player's way and shouldn't care if our
2950 // next step also is.
2951 if (ray.pos() == mons->target || ray.pos() == mons->pos())
2953 else if (ray.pos() == targ)
2960 // Submerged water creatures avoid the shallows where
2961 // they would be forced to surface. -- bwr
2962 // [dshaligram] Monsters now prefer to head for deep water only if
2963 // they're low on hitpoints. No point in hiding if they want a
2965 if (habitat == HT_WATER
2966 && targ != you.pos()
2967 && target_grid != DNGN_DEEP_WATER
2968 && env.grid(mons->pos()) == DNGN_DEEP_WATER
2969 && mons->hit_points < (mons->max_hit_points * 3) / 4)
2974 // Smacking the player is always a good move if we're
2975 // hostile (even if we're heading somewhere else).
2976 // Also friendlies want to keep close to the player
2977 // so it's okay as well.
2979 // Smacking another monster is good, if the monsters
2980 // are aligned differently.
2981 if (monster* targmonster = monster_at(targ))
2985 if (targ == mons->pos())
2988 return false; // blocks square
2991 if (!summon_can_attack(mons, targ))
2994 if (targmonster->type == MONS_TOADSTOOL
2995 && mons->type == MONS_WANDERING_MUSHROOM)
3000 // Cut down plants only when no alternative, or they're
3002 if (mons_is_firewood(*targmonster) && mons->target != targ)
3005 if ((mons_aligned(mons, targmonster)
3006 || targmonster->type == MONS_FOXFIRE)
3007 && !mons->has_ench(ENCH_INSANE)
3008 && !_mons_can_displace(mons, targmonster))
3012 // Prefer to move past enemies instead of hit them, if we're retreating
3013 else if ((!mons_aligned(mons, targmonster)
3014 || mons->has_ench(ENCH_INSANE))
3015 && mons->behaviour == BEH_WITHDRAW)
3021 // Friendlies shouldn't try to move onto the player's
3022 // location, if they are aiming for some other target.
3023 if (mons->foe != MHITYOU
3024 && targ == you.pos()
3025 && (mons->foe != MHITNOT || mons->is_patrolling())
3026 && !_unfriendly_or_impaired(*mons))
3031 // Wandering through a trap is OK if we're pretty healthy,
3032 // really stupid, or immune to the trap.
3033 if (!mons->is_trap_safe(targ, just_check))
3036 // If we end up here the monster can safely move.
3040 // May mons attack targ if it's in its way, despite
3041 // possibly aligned attitudes?
3042 // The aim of this is to have monsters cut down plants
3043 // to get to the player if necessary.
3044 static bool _may_cutdown(monster* mons, monster* targ)
3046 // Save friendly plants from allies.
3047 // [ds] I'm deliberately making the alignment checks symmetric here.
3048 // The previous check involved good-neutrals never attacking friendlies
3049 // and friendlies never attacking anything other than hostiles.
3050 if ((mons->friendly() || mons->good_neutral())
3051 && (targ->friendly() || targ->good_neutral()))
3055 // Outside of that case, can always cut mundane plants
3056 // (but don't try to attack briars unless their damage will be insignificant)
3057 return mons_is_firewood(*targ)
3058 && (targ->type != MONS_BRIAR_PATCH
3059 || (targ->friendly() && !mons_aligned(mons, targ))
3060 || mons->type == MONS_THORN_HUNTER
3061 || mons->armour_class() * mons->hit_points >= 400);
3064 // Uses, and updates the global variable mmov.
3065 static void _find_good_alternate_move(monster* mons,
3066 const move_array& good_move)
3068 const coord_def target = mons->firing_pos.zero() ? mons->target
3070 const int current_distance = distance2(mons->pos(), target);
3072 int dir = _compass_idx(mmov);
3074 // Only handle if the original move is to an adjacent square.
3080 // First 1 away, then 2 (3 is silly).
3081 for (int j = 1; j <= 2; j++)
3083 const int FAR_AWAY = 1000000;
3085 // Try both directions (but randomise which one is first).
3086 const int sdir = random_choose(j, -j);
3087 const int inc = -2 * sdir;
3089 for (int mod = sdir, i = 0; i < 2; mod += inc, i++)
3091 const int newdir = (dir + 8 + mod) % 8;
3092 if (good_move[mon_compass[newdir].x+1][mon_compass[newdir].y+1])
3093 dist[i] = distance2(mons->pos()+mon_compass[newdir], target);
3096 // If we can cut firewood there, it's still not a good move,
3097 // but update mmov so we can fall back to it.
3098 monster* targ = monster_at(mons->pos() + mon_compass[newdir]);
3099 const bool retreating = mons_is_retreating(*mons);
3101 dist[i] = (targ && _may_cutdown(mons, targ))
3103 : retreating ? -FAR_AWAY : FAR_AWAY;
3107 const int dir0 = ((dir + 8 + sdir) % 8);
3108 const int dir1 = ((dir + 8 - sdir) % 8);
3111 if (dist[0] == dist[1] && abs(dist[0]) == FAR_AWAY)
3114 // Which one was better? -- depends on FLEEING or not.
3115 if (mons_is_retreating(*mons))
3117 if (dist[0] >= dist[1] && dist[0] >= current_distance)
3119 mmov = mon_compass[dir0];
3122 if (dist[1] >= dist[0] && dist[1] >= current_distance)
3124 mmov = mon_compass[dir1];
3130 if (dist[0] <= dist[1] && dist[0] <= current_distance)
3132 mmov = mon_compass[dir0];
3135 if (dist[1] <= dist[0] && dist[1] <= current_distance)
3137 mmov = mon_compass[dir1];
3144 static void _jelly_grows(monster& mons)
3146 if (player_can_hear(mons.pos()))
3148 mprf(MSGCH_SOUND, "You hear a%s slurping noise.",
3149 you.see_cell(mons.pos()) ? "" : " distant");
3152 const int avg_hp = mons_avg_hp(mons.type);
3153 mons.hit_points += 5;
3154 mons.hit_points = min(MAX_MONSTER_HP,
3155 min(avg_hp * 4, mons.hit_points));
3157 // note here, that this makes jellies "grow" {dlb}:
3158 if (mons.hit_points > mons.max_hit_points)
3159 mons.max_hit_points = mons.hit_points;
3161 _jelly_divide(mons);
3164 bool monster_swaps_places(monster* mon, const coord_def& delta,
3165 bool takes_time, bool apply_effects)
3170 monster* const m2 = monster_at(mon->pos() + delta);
3175 if (!_mons_can_displace(mon, m2))
3182 dprf("Alerting monster %s at (%d,%d)",
3183 m2->name(DESC_PLAIN).c_str(), m2->pos().x, m2->pos().y);
3184 behaviour_event(m2, ME_ALERT);
3189 if (!mon->swap_with(m2))
3194 _swim_or_move_energy(*mon);
3195 _swim_or_move_energy(*m2);
3198 mon->check_redraw(m2->pos(), false);
3200 mon->apply_location_effects(m2->pos());
3202 m2->check_redraw(mon->pos(), false);
3204 m2->apply_location_effects(mon->pos());
3206 // The seen context no longer applies if the monster is moving normally.
3207 mon->seen_context = SC_NONE;
3208 m2->seen_context = SC_NONE;
3210 _handle_manticore_barbs(*mon);
3211 _handle_manticore_barbs(*m2);
3213 // Pushing past a foxfire gets you burned regardless of alignment
3214 if (m2->type == MONS_FOXFIRE)
3216 foxfire_attack(m2, mon);
3217 monster_die(*m2, KILL_DISMISSED, NON_MONSTER, true);
3223 static bool _do_move_monster(monster& mons, const coord_def& delta)
3225 const coord_def f = mons.pos() + delta;
3232 fight_melee(&mons, &you);
3236 // This includes the case where the monster attacks itself.
3237 if (monster* def = monster_at(f))
3239 fight_melee(&mons, def);
3243 if (mons.is_constricted())
3245 if (mons.attempt_escape())
3246 simple_monster_message(mons, " escapes!");
3249 simple_monster_message(mons, " struggles to escape constriction.");
3250 _swim_or_move_energy(mons);
3255 ASSERT(!cell_is_runed(f)); // should be checked in mons_can_traverse
3257 if (feat_is_closed_door(env.grid(f)))
3259 if (mons_can_destroy_door(mons, f))
3261 env.grid(f) = DNGN_FLOOR;
3262 set_terrain_changed(f);
3264 if (you.see_cell(f))
3269 if (!you.can_see(mons))
3271 mpr("The door bursts into shrapnel!");
3272 interrupt_activity(activity_interrupt::force);
3275 simple_monster_message(mons, " bursts through the door, destroying it!");
3278 else if (mons_can_open_door(mons, f))
3280 _mons_open_door(mons, f);
3283 else if (mons_can_eat_door(mons, f))
3285 env.grid(f) = DNGN_FLOOR;
3286 set_terrain_changed(f);
3290 if (you.see_cell(f))
3295 if (!you.can_see(mons))
3297 mpr("The door mysteriously vanishes.");
3298 interrupt_activity(activity_interrupt::force);
3301 simple_monster_message(mons, " eats the door!");
3303 } // done door-eating jellies
3306 // The monster gave a "comes into view" message and then immediately
3307 // moved back out of view, leaing the player nothing to see, so give
3308 // this message to avoid confusion.
3309 else if (crawl_state.game_is_hints() && mons.flags & MF_WAS_IN_VIEW
3310 && !you.see_cell(f))
3312 learned_something_new(HINT_MONSTER_LEFT_LOS, mons.pos());
3315 // The seen context no longer applies if the monster is moving normally.
3316 mons.seen_context = SC_NONE;
3318 // This appears to be the real one, ie where the movement occurs:
3319 _swim_or_move_energy(mons);
3321 if (mons.type == MONS_FOXFIRE)
3322 --mons.steps_remaining;
3324 _escape_water_hold(mons);
3326 if (env.grid(mons.pos()) == DNGN_DEEP_WATER && env.grid(f) != DNGN_DEEP_WATER
3327 && !monster_habitable_grid(&mons, DNGN_DEEP_WATER))
3329 // er, what? Seems impossible.
3330 mons.seen_context = SC_NONSWIMMER_SURFACES_FROM_DEEP;
3333 mons.move_to_pos(f, false);
3335 // Let go of all constrictees; only stop *being* constricted if we are now
3336 // too far away (done in move_to_pos above).
3337 mons.stop_directly_constricting_all(false);
3339 mons.check_redraw(mons.pos() - delta);
3340 mons.apply_location_effects(mons.pos() - delta);
3341 if (!invalid_monster(&mons) && you.can_see(mons))
3343 handle_seen_interrupt(&mons);
3344 seen_monster(&mons);
3347 _handle_manticore_barbs(mons);
3352 static bool _monster_move(monster* mons)
3354 ASSERT(mons); // XXX: change to monster &mons
3355 move_array good_move;
3357 const habitat_type habitat = mons_primary_habitat(*mons);
3358 bool deep_water_available = false;
3360 // Berserking monsters make a lot of racket.
3361 if (mons->berserk_or_insane())
3363 int noise_level = get_shout_noise_level(mons_shouts(mons->type));
3364 if (noise_level > 0)
3366 if (you.can_see(*mons) && mons->berserk())
3368 if (one_chance_in(10))
3370 mprf(MSGCH_TALK_VISUAL, "%s rages.",
3371 mons->name(DESC_THE).c_str());
3373 noisy(noise_level, mons->pos(), mons->mid);
3375 else if (one_chance_in(5))
3376 monster_attempt_shout(*mons);
3379 // Just be noisy without messaging the player.
3380 noisy(noise_level, mons->pos(), mons->mid);
3385 // If a water (or lava) monster is currently flopping around on land, it
3386 // cannot really control where it wants to move, though there's a 50%
3387 // chance of flopping into an adjacent water (or lava) grid.
3388 if (mons->has_ench(ENCH_AQUATIC_LAND))
3390 vector<coord_def> adj_water;
3391 vector<coord_def> adj_move;
3392 for (adjacent_iterator ai(mons->pos()); ai; ++ai)
3394 if (!cell_is_solid(*ai))
3396 adj_move.push_back(*ai);
3397 if (habitat == HT_WATER && feat_is_watery(env.grid(*ai))
3398 || habitat == HT_LAVA && feat_is_lava(env.grid(*ai)))
3400 adj_water.push_back(*ai);
3404 if (adj_move.empty())
3406 simple_monster_message(*mons, " flops around on dry land!");
3410 vector<coord_def> moves = adj_water;
3411 if (adj_water.empty() || coinflip())
3414 const coord_def newpos = moves.empty() ? mons->pos()
3415 : moves[random2(moves.size())];
3417 const monster* mon2 = monster_at(newpos);
3418 if (!mons->has_ench(ENCH_INSANE)
3419 && (newpos == you.pos() && mons->wont_attack()
3420 || (mon2 && mons->wont_attack() == mon2->wont_attack())))
3422 simple_monster_message(*mons, " flops around on dry land!");
3426 return _do_move_monster(*mons, newpos - mons->pos());
3429 // Let's not even bother with this if mmov is zero.
3433 for (int count_x = 0; count_x < 3; count_x++)
3434 for (int count_y = 0; count_y < 3; count_y++)
3436 const int targ_x = mons->pos().x + count_x - 1;
3437 const int targ_y = mons->pos().y + count_y - 1;
3439 // Bounds check: don't consider moving out of grid!
3440 if (!in_bounds(targ_x, targ_y))
3442 good_move[count_x][count_y] = false;
3445 dungeon_feature_type target_grid = env.grid[targ_x][targ_y];
3447 if (target_grid == DNGN_DEEP_WATER)
3448 deep_water_available = true;
3450 good_move[count_x][count_y] =
3451 mon_can_move_to_pos(mons, coord_def(count_x-1, count_y-1));
3454 // Now we know where we _can_ move.
3456 const coord_def newpos = mons->pos() + mmov;
3457 // Water creatures have a preference for water they can hide in -- bwr
3458 // [ds] Weakened the powerful attraction to deep water if the monster
3459 // is in good health.
3460 if (habitat == HT_WATER
3461 && deep_water_available
3462 && env.grid(mons->pos()) != DNGN_DEEP_WATER
3463 && env.grid(newpos) != DNGN_DEEP_WATER
3464 && newpos != you.pos()
3465 && (one_chance_in(3)
3466 || mons->hit_points <= (mons->max_hit_points * 3) / 4))
3470 for (int cx = 0; cx < 3; cx++)
3471 for (int cy = 0; cy < 3; cy++)
3473 if (good_move[cx][cy]
3474 && env.grid[mons->pos().x + cx - 1][mons->pos().y + cy - 1]
3477 if (one_chance_in(++count))
3486 // Now, if a monster can't move in its intended direction, try
3487 // either side. If they're both good, move in whichever dir
3488 // gets it closer (farther for fleeing monsters) to its target.
3489 // If neither does, do nothing.
3490 if (good_move[mmov.x + 1][mmov.y + 1] == false)
3491 _find_good_alternate_move(mons, good_move);
3493 // ------------------------------------------------------------------
3494 // If we haven't found a good move by this point, we're not going to.
3495 // ------------------------------------------------------------------
3497 if (mons->type == MONS_SPATIAL_MAELSTROM)
3499 const dungeon_feature_type feat = env.grid(mons->pos() + mmov);
3500 if (!feat_is_permarock(feat) && feat_is_solid(feat))
3502 const coord_def target(mons->pos() + mmov);
3504 mgen_data(MONS_SPATIAL_VORTEX, SAME_ATTITUDE(mons), target)
3505 .set_summoned(mons, 2, MON_SUMM_ANIMATE, GOD_LUGONU));
3506 destroy_wall(target);
3510 const bool burrows = mons_class_flag(mons->type, M_BURROWS);
3511 const bool flattens_trees = mons_flattens_trees(*mons);
3512 const bool digs = _mons_can_cast_dig(mons, false)
3513 || _mons_can_zap_dig(mons);
3514 // Take care of Dissolution burrowing, lerny, etc
3515 if (burrows || flattens_trees || digs)
3517 const dungeon_feature_type feat = env.grid(mons->pos() + mmov);
3518 if ((feat == DNGN_ROCK_WALL || feat == DNGN_CLEAR_ROCK_WALL)
3520 || feat == DNGN_GRATE && digs)
3523 if (_mons_can_cast_dig(mons, true))
3525 setup_mons_cast(mons, beem, SPELL_DIG);
3526 beem.target = mons->pos() + mmov;
3527 mons_cast(mons, beem, SPELL_DIG,
3528 mons->spell_slot_flags(SPELL_DIG));
3530 else if (_mons_can_zap_dig(mons))
3532 ASSERT(mons->mslot_item(MSLOT_WAND));
3533 item_def &wand = *mons->mslot_item(MSLOT_WAND);
3534 setup_mons_cast(mons, beem, SPELL_DIG, true);
3535 beem.target = mons->pos() + mmov;
3536 _mons_fire_wand(*mons, wand, beem, you.can_see(*mons));
3538 //_setup_wand_beam(beem, *mons, wand);
3539 //_mons_fire_wand(*mons, wand, beem, you.can_see(*mons), false);
3542 simple_monster_message(*mons, " falters for a moment.");
3543 mons->lose_energy(EUT_SPELL);
3546 else if ((((feat == DNGN_ROCK_WALL || feat == DNGN_CLEAR_ROCK_WALL)
3548 || (flattens_trees && feat_is_tree(feat)))
3549 && good_move[mmov.x + 1][mmov.y + 1] == true)
3551 const coord_def target(mons->pos() + mmov);
3552 destroy_wall(target);
3556 // Flattening trees has a movement cost to the monster
3557 // - 100% over and above its normal move cost.
3558 _swim_or_move_energy(*mons);
3559 if (you.see_cell(target))
3561 const bool actor_visible = you.can_see(*mons);
3562 mprf("%s knocks down a tree!",
3564 mons->name(DESC_THE).c_str() : "Something");
3568 noisy(25, target, "You hear a crashing sound.");
3570 // Dissolution dissolves walls.
3571 else if (player_can_hear(mons->pos() + mmov))
3572 mprf(MSGCH_SOUND, "You hear a sizzling sound.");
3577 if (good_move[mmov.x + 1][mmov.y + 1] && !mmov.origin())
3579 // Check for attacking player.
3580 if (mons->pos() + mmov == you.pos())
3582 ret = fight_melee(mons, &you);
3586 // If we're following the player through stairs, the only valid
3587 // movement is towards the player. -- bwr
3588 if (testbits(mons->flags, MF_TAKING_STAIRS))
3590 if (!player_stair_delay())
3592 mons->flags &= ~MF_TAKING_STAIRS;
3594 dprf("BUG: %s was marked as follower when not following!",
3595 mons->name(DESC_PLAIN).c_str());
3602 dprf("%s is skipping movement in order to follow.",
3603 mons->name(DESC_THE).c_str());
3607 // Check for attacking another monster.
3608 if (monster* targ = monster_at(mons->pos() + mmov))
3610 if ((mons_aligned(mons, targ) || targ->type == MONS_FOXFIRE)
3611 && !(mons->has_ench(ENCH_INSANE)
3612 || mons->confused()))
3614 bool takes_time = !(mons->type == MONS_WANDERING_MUSHROOM
3615 && targ->type == MONS_TOADSTOOL
3616 || mons->type == MONS_TOADSTOOL
3617 && targ->type == MONS_WANDERING_MUSHROOM);
3618 ret = monster_swaps_places(mons, mmov, takes_time);
3622 fight_melee(mons, targ);
3626 // If the monster swapped places, the work's already done.
3630 // The monster could die after a melee attack due to a mummy
3631 // death curse or something.
3635 if (mons_genus(mons->type) == MONS_EFREET
3636 || mons->type == MONS_FIRE_ELEMENTAL)
3638 place_cloud(CLOUD_FIRE, mons->pos(), 2 + random2(4), mons);
3641 if (mons->has_ench(ENCH_ROLLING))
3642 place_cloud(CLOUD_DUST, mons->pos(), 2, mons);
3644 if (mons->type == MONS_FOXFIRE)
3645 check_place_cloud(CLOUD_FLAME, mons->pos(), 2, mons);
3647 if (mons->type == MONS_CURSE_TOE)
3648 place_cloud(CLOUD_MIASMA, mons->pos(), 2 + random2(3), mons);
3652 monster* targ = monster_at(mons->pos() + mmov);
3653 if (!mmov.origin() && targ && _may_cutdown(mons, targ))
3655 fight_melee(mons, targ);
3661 // Fleeing monsters that can't move will panic and possibly
3662 // turn to face their attacker.
3663 make_mons_stop_fleeing(mons);
3666 // This handles the chance for the monster to hit itself.
3667 if (mmov.x || mmov.y || (mons->confused() && one_chance_in(6)))
3668 return _do_move_monster(*mons, mmov);
3670 // Battlespheres need to preserve their tracking targets after each move
3671 if (mons_is_wandering(*mons)
3672 && mons->type != MONS_BATTLESPHERE)
3674 // trigger a re-evaluation of our wander target on our next move -cao
3675 mons->target = mons->pos();
3676 if (!mons->is_patrolling())
3678 mons->travel_target = MTRAV_NONE;
3679 mons->travel_path.clear();
3681 mons->firing_pos.reset();
3687 static void _mons_in_cloud(monster& mons)
3689 // Submerging in water or lava saves from clouds.
3690 if (mons.submerged() && env.grid(mons.pos()) != DNGN_FLOOR)
3693 actor_apply_cloud(&mons);