1 /**
2  * @file
3  * @brief Monster spell casting.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "mon-cast.h"
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <functional>
13 #include <unordered_set>
14 
15 #include "act-iter.h"
16 #include "areas.h"
17 #include "attack.h"
18 #include "bloodspatter.h"
19 #include "branch.h"
20 #include "cleansing-flame-source-type.h"
21 #include "cloud.h"
22 #include "colour.h"
23 #include "coordit.h"
24 #include "database.h"
25 #include "delay.h"
26 #include "directn.h"
27 #include "english.h"
28 #include "env.h"
29 #include "tile-env.h"
30 #include "evoke.h"
31 #include "exclude.h"
32 #include "fight.h"
33 #include "fprop.h"
34 #include "god-passive.h"
35 #include "items.h"
36 #include "level-state-type.h"
37 #include "libutil.h"
38 #include "losglobal.h"
39 #include "mapmark.h"
40 #include "message.h"
41 #include "misc.h"
42 #include "mon-act.h"
43 #include "mon-ai-action.h"
44 #include "mon-behv.h"
45 #include "mon-clone.h"
46 #include "mon-death.h"
47 #include "mon-gear.h"
48 #include "mon-pathfind.h"
49 #include "mon-pick.h"
50 #include "mon-place.h"
51 #include "mon-project.h"
52 #include "mon-speak.h"
53 #include "mon-tentacle.h"
54 #include "mutation.h"
55 #include "player-stats.h"
56 #include "random.h"
57 #include "religion.h"
58 #include "shout.h"
59 #include "spl-clouds.h"
60 #include "spl-damage.h"
61 #include "spl-goditem.h"
62 #include "spl-monench.h"
63 #include "spl-summoning.h"
64 #include "spl-transloc.h"
65 #include "spl-util.h"
66 #include "spl-zap.h" // spell_to_zap
67 #include "state.h"
68 #include "stepdown.h"
69 #include "stringutil.h"
70 #include "tag-version.h"
71 #include "target.h"
72 #include "teleport.h"
73 #include "terrain.h"
74 #ifdef USE_TILE
75 #include "rltiles/tiledef-dngn.h"
76 #endif
77 #include "timed-effects.h"
78 #include "traps.h"
79 #include "travel.h"
80 #include "unwind.h"
81 #include "view.h"
82 #include "viewchar.h"
83 #include "xom.h"
84 
85 static bool _valid_mon_spells[NUM_SPELLS];
86 
87 static const string MIRROR_RECAST_KEY = "mirror_recast_time";
88 
89 static god_type _find_god(const monster &mons, mon_spell_slot_flags flags);
90 static monster* _get_allied_target(const monster &caster, bolt &tracer);
91 static void _fire_simple_beam(monster &caster, mon_spell_slot, bolt &beam);
92 static void _fire_direct_explosion(monster &caster, mon_spell_slot, bolt &beam);
93 static int  _mons_mesmerise(monster* mons, bool actual = true);
94 static int  _mons_cause_fear(monster* mons, bool actual = true);
95 static int  _mons_mass_confuse(monster* mons, bool actual = true);
96 static coord_def _mons_fragment_target(const monster &mons);
97 static coord_def _mons_awaken_earth_target(const monster& mon);
98 static void _maybe_throw_ally(const monster &mons);
99 static void _siren_sing(monster* mons, bool avatar);
100 static void _doom_howl(monster &mon);
101 static void _mons_awaken_earth(monster &mon, const coord_def &target);
102 static ai_action::goodness _monster_spell_goodness(monster* mon, mon_spell_slot slot);
103 static string _god_name(god_type god);
104 static bool _mons_can_bind_soul(monster* binder, monster* bound);
105 static coord_def _mons_ghostly_sacrifice_target(const monster &caster,
106                                                 bolt tracer);
107 static function<void(bolt&, const monster&, int)>
108     _selfench_beam_setup(beam_type flavour);
109 static function<void(bolt&, const monster&, int)>
110     _zap_setup(spell_type spell);
111 static function<void(bolt&, const monster&, int)>
112     _buff_beam_setup(beam_type flavour);
113 static function<void(bolt&, const monster&, int)>
114     _target_beam_setup(function<coord_def(const monster&)> targeter);
115 static void _setup_minor_healing(bolt &beam, const monster &caster,
116                                  int = -1);
117 static void _setup_heal_other(bolt &beam, const monster &caster, int = -1);
118 static void _setup_creeping_frost(bolt &beam, const monster &caster, int pow);
119 static void _setup_pyroclastic_surge(bolt &beam, const monster &caster, int pow);
120 static ai_action::goodness _negative_energy_spell_goodness(const actor* foe);
121 static ai_action::goodness _caster_sees_foe(const monster &caster);
122 static ai_action::goodness _foe_sleep_viable(const monster &caster);
123 static ai_action::goodness _foe_tele_goodness(const monster &caster);
124 static ai_action::goodness _foe_mr_lower_goodness(const monster &caster);
125 static ai_action::goodness _still_winds_goodness(const monster &caster);
126 static ai_action::goodness _foe_near_wall(const monster &caster);
127 static ai_action::goodness _foe_not_nearby(const monster &caster);
128 static ai_action::goodness _foe_near_lava(const monster &caster);
129 static void _cast_cantrip(monster &mons, mon_spell_slot, bolt&);
130 static void _cast_injury_mirror(monster &mons, mon_spell_slot, bolt&);
131 static void _cast_smiting(monster &mons, mon_spell_slot slot, bolt&);
132 static void _cast_resonance_strike(monster &mons, mon_spell_slot, bolt&);
133 static void _cast_creeping_frost(monster &caster, mon_spell_slot, bolt&);
134 static void _cast_call_down_lightning(monster &caster, mon_spell_slot, bolt&);
135 static void _cast_pyroclastic_surge(monster &caster, mon_spell_slot, bolt&);
136 static void _cast_flay(monster &caster, mon_spell_slot, bolt&);
137 static void _flay(const monster &caster, actor &defender, int damage);
138 static void _cast_still_winds(monster &caster, mon_spell_slot, bolt&);
139 static void _mons_summon_elemental(monster &caster, mon_spell_slot, bolt&);
140 static bool _los_spell_worthwhile(const monster &caster, spell_type spell);
141 static void _setup_fake_beam(bolt& beam, const monster&, int = -1);
142 static void _branch_summon(monster &caster, mon_spell_slot slot, bolt&);
143 static void _branch_summon_helper(monster* mons, spell_type spell_cast);
144 static void _cast_marshlight(monster &caster, mon_spell_slot slot, bolt&);
145 static bool _prepare_ghostly_sacrifice(monster &caster, bolt &beam);
146 static void _setup_ghostly_beam(bolt &beam, int power, int dice);
147 static void _setup_ghostly_sacrifice_beam(bolt& beam, const monster& caster,
148                                           int power);
149 static function<ai_action::goodness(const monster&)> _setup_hex_check(spell_type spell);
150 static ai_action::goodness _hexing_goodness(const monster &caster, spell_type spell);
151 static bool _torment_vulnerable(const actor* victim);
152 static void _cast_grasping_roots(monster &caster, mon_spell_slot, bolt&);
153 static int _monster_abjuration(const monster& caster, bool actual);
154 static ai_action::goodness _mons_will_abjure(const monster& mons);
155 
156 enum spell_logic_flag
157 {
158     MSPELL_NO_AUTO_NOISE = 1 << 0, ///< silent, or noise generated specially
159 };
160 
161 DEF_BITFIELD(spell_logic_flags, spell_logic_flag);
162 constexpr spell_logic_flags MSPELL_LOGIC_NONE{};
163 
164 struct mons_spell_logic
165 {
166     /// Can casting this spell right now accomplish anything useful?
167     function<ai_action::goodness(const monster&)> calc_goodness;
168     /// Actually cast the given spell.
169     function<void(monster&, mon_spell_slot, bolt&)> cast;
170     /// Setup a targeting/effect beam for the given spell, if applicable.
171     function<void(bolt&, const monster&, int)> setup_beam;
172     /// What special behaviors does this spell have for monsters?
173     spell_logic_flags flags;
174     /// How much 'power' is this spell cast with per caster HD? If 0, ignore
175     int power_hd_factor;
176 };
177 
_always_worthwhile(const monster &)178 static ai_action::goodness _always_worthwhile(const monster &/*caster*/)
179 {
180     return ai_action::good(); // or neutral?
181 }
182 
183 static function<ai_action::goodness(const monster&)> _should_selfench(enchant_type ench);
184 static mons_spell_logic _conjuration_logic(spell_type spell);
185 static mons_spell_logic _hex_logic(spell_type spell,
186                                    function<ai_action::goodness(const monster&)> extra_logic
187                                    = nullptr,
188                                    int power_hd_factor = 0);
189 
190 /// How do monsters go about casting spells?
191 static const map<spell_type, mons_spell_logic> spell_to_logic = {
192     { SPELL_MIGHT, {
193         _should_selfench(ENCH_MIGHT),
194         _fire_simple_beam,
195         _selfench_beam_setup(BEAM_MIGHT),
196     } },
197     { SPELL_INVISIBILITY, {
198         _should_selfench(ENCH_INVIS),
199         _fire_simple_beam,
200         _selfench_beam_setup(BEAM_INVISIBILITY),
201     } },
202     { SPELL_HASTE, {
203         _should_selfench(ENCH_HASTE),
204         _fire_simple_beam,
205         _selfench_beam_setup(BEAM_HASTE),
206     } },
207     { SPELL_MINOR_HEALING, {
__anon2840f9480102() 208         [](const monster &caster) {
209             return ai_action::good_or_bad(caster.hit_points <= caster.max_hit_points / 2);
210         },
211         _fire_simple_beam,
212         _setup_minor_healing,
213     } },
214     { SPELL_TELEPORT_SELF, {
215         [](const monster &caster)
__anon2840f9480202() 216         {
217             // Monsters aren't smart enough to know when to cancel teleport.
218             // TODO: could work emergency logic in here?
219             return (caster.no_tele(true, false) || caster.has_ench(ENCH_TP))
220                             ? ai_action::impossible() : ai_action::neutral();
221         },
222         _fire_simple_beam,
223         _selfench_beam_setup(BEAM_TELEPORT),
224     } },
225     { SPELL_SLUG_DART, _conjuration_logic(SPELL_SLUG_DART) },
226     { SPELL_VAMPIRIC_DRAINING, {
227         [](const monster &caster)
__anon2840f9480302() 228         {
229             const actor* foe = caster.get_foe();
230             ASSERT(foe);
231             // always cast at < 1/3rd hp, never at > 2/3rd hp
232             const bool low_hp = x_chance_in_y(caster.max_hit_points * 2 / 3
233                                                 - caster.hit_points,
234                                               caster.max_hit_points / 3);
235             if (!adjacent(caster.pos(), foe->pos()))
236                 return ai_action::impossible();
237 
238             if (!actor_is_susceptible_to_vampirism(*foe))
239                 return ai_action::impossible();
240 
241             return min(_negative_energy_spell_goodness(foe),
242                        ai_action::good_or_bad(low_hp));
243         },
244         _fire_simple_beam,
245         _zap_setup(SPELL_VAMPIRIC_DRAINING),
246         MSPELL_NO_AUTO_NOISE,
247     } },
248     { SPELL_CANTRIP, {
249         [](const monster &caster)
__anon2840f9480402() 250         {
251             return ai_action::good_or_bad(caster.get_foe());
252         },
253         _cast_cantrip,
254         nullptr,
255         MSPELL_NO_AUTO_NOISE,
256     } },
257     { SPELL_INJURY_MIRROR, {
__anon2840f9480502() 258         [](const monster &caster) {
259             return ai_action::good_or_impossible(
260                     !caster.has_ench(ENCH_MIRROR_DAMAGE)
261                     && (!caster.props.exists(MIRROR_RECAST_KEY)
262                         || you.elapsed_time >=
263                            caster.props[MIRROR_RECAST_KEY].get_int()));
264         },
265         _cast_injury_mirror,
266         nullptr,
267         MSPELL_NO_AUTO_NOISE,
268     } },
269     { SPELL_DRAIN_LIFE, {
__anon2840f9480602() 270         [](const monster &caster) {
271             return ai_action::good_or_bad(
272                    _los_spell_worthwhile(caster, SPELL_DRAIN_LIFE)
273                    && (!caster.friendly()
274                        || !you.visible_to(&caster)
275                        || player_prot_life(false) >= 3));
276         },
__anon2840f9480702() 277         [](monster &caster, mon_spell_slot slot, bolt&) {
278             const int splpow = mons_spellpower(caster, slot.spell);
279 
280             int damage = 0;
281             fire_los_attack_spell(slot.spell, splpow, &caster, false, &damage);
282             if (damage > 0 && caster.heal(damage))
283                 simple_monster_message(caster, " is healed.");
284         },
285         _zap_setup(SPELL_DRAIN_LIFE),
286         MSPELL_NO_AUTO_NOISE,
287         1,
288     } },
289     { SPELL_OZOCUBUS_REFRIGERATION, {
__anon2840f9480802() 290         [](const monster &caster) {
291             return ai_action::good_or_bad(
292                 _los_spell_worthwhile(caster, SPELL_OZOCUBUS_REFRIGERATION)
293                    && (!caster.friendly() || !you.visible_to(&caster)));
294         },
__anon2840f9480902() 295         [](monster &caster, mon_spell_slot slot, bolt&) {
296             const int splpow = mons_spellpower(caster, slot.spell);
297             fire_los_attack_spell(slot.spell, splpow, &caster, false);
298         },
299         _zap_setup(SPELL_OZOCUBUS_REFRIGERATION),
300         MSPELL_LOGIC_NONE,
301         5,
302     } },
303     { SPELL_TROGS_HAND, {
__anon2840f9480a02() 304         [](const monster &caster) {
305             return ai_action::good_or_impossible(
306                                        !caster.has_ench(ENCH_STRONG_WILLED)
307                                     && !caster.has_ench(ENCH_REGENERATION));
308         },
__anon2840f9480b02() 309         [](monster &caster, mon_spell_slot, bolt&) {
310             const string god = apostrophise(god_name(caster.god));
311             const string msg = make_stringf(" invokes %s protection!",
312                                             god.c_str());
313             simple_monster_message(caster, msg.c_str(), MSGCH_MONSTER_SPELL);
314             // Not spell_hd(spell_cast); this is an invocation
315             const int dur = BASELINE_DELAY
316                 * min(5 + roll_dice(2, (caster.get_hit_dice() * 10) / 3 + 1),
317                       100);
318             caster.add_ench(mon_enchant(ENCH_STRONG_WILLED, 0, &caster, dur));
319             caster.add_ench(mon_enchant(ENCH_REGENERATION, 0, &caster, dur));
320             dprf("Trog's Hand cast (dur: %d aut)", dur);
321         },
322         nullptr,
323         MSPELL_NO_AUTO_NOISE,
324     } },
325     { SPELL_LEDAS_LIQUEFACTION, {
__anon2840f9480c02() 326         [](const monster &caster) {
327             return ai_action::good_or_impossible(!caster.has_ench(ENCH_LIQUEFYING));
328         },
__anon2840f9480d02() 329         [](monster &caster, mon_spell_slot, bolt&) {
330             if (you.can_see(caster))
331             {
332                 mprf("%s liquefies the ground around %s!",
333                      caster.name(DESC_THE).c_str(),
334                      caster.pronoun(PRONOUN_REFLEXIVE).c_str());
335                 flash_view_delay(UA_MONSTER, BROWN, 80);
336             }
337 
338             caster.add_ench(ENCH_LIQUEFYING);
339             invalidate_agrid(true);
340         },
341         nullptr,
342         MSPELL_NO_AUTO_NOISE,
343     } },
344     { SPELL_FORCEFUL_INVITATION, {
345         _always_worthwhile,
346         _branch_summon,
347         nullptr,
348         MSPELL_NO_AUTO_NOISE,
349     } },
350     { SPELL_PLANEREND, {
351         _always_worthwhile,
352         _branch_summon,
353         nullptr,
354         MSPELL_NO_AUTO_NOISE,
355     } },
356     { SPELL_MARSHLIGHT, {
357        _always_worthwhile,
358        _cast_marshlight,
359     } },
360     { SPELL_STILL_WINDS, { _still_winds_goodness, _cast_still_winds } },
361     { SPELL_SMITING, { _always_worthwhile, _cast_smiting, } },
362     { SPELL_CALL_DOWN_LIGHTNING, { _foe_not_nearby, _cast_call_down_lightning, _zap_setup(SPELL_CALL_DOWN_LIGHTNING) } },
363     { SPELL_RESONANCE_STRIKE, { _always_worthwhile, _cast_resonance_strike, } },
364     { SPELL_CREEPING_FROST, { _foe_near_wall, _cast_creeping_frost, _setup_creeping_frost } },
365     { SPELL_PYROCLASTIC_SURGE, { _foe_near_lava, _cast_pyroclastic_surge, _setup_pyroclastic_surge } },
366     { SPELL_FLAY, {
__anon2840f9480e02() 367         [](const monster &caster) {
368             const actor* foe = caster.get_foe(); // XXX: check vis?
369             ASSERT(foe);
370             return ai_action::good_or_impossible(!!(foe->holiness() & MH_NATURAL));
371         },
372         _cast_flay,
373     } },
374     { SPELL_PARALYSIS_GAZE, {
375         _caster_sees_foe,
__anon2840f9480f02() 376         [](monster &caster, mon_spell_slot, bolt&) {
377             caster.get_foe()->paralyse(&caster, 2 + random2(3));
378         },
379     } },
380     { SPELL_DRAINING_GAZE, {
381         _caster_sees_foe,
__anon2840f9481002() 382         [](monster &caster, mon_spell_slot slot, bolt&) {
383             enchant_actor_with_flavour(caster.get_foe(), &caster,
384                                        BEAM_DRAIN_MAGIC,
385                                        mons_spellpower(caster, slot.spell));
386         },
387     } },
388     { SPELL_WEAKENING_GAZE, {
389         _caster_sees_foe,
__anon2840f9481102() 390         [](monster &caster, mon_spell_slot, bolt&) {
391             caster.get_foe()->weaken(&caster, caster.get_hit_dice());
392         },
393     } },
394     { SPELL_WATER_ELEMENTALS, { _always_worthwhile, _mons_summon_elemental } },
395     { SPELL_EARTH_ELEMENTALS, { _always_worthwhile, _mons_summon_elemental } },
396     { SPELL_AIR_ELEMENTALS, { _always_worthwhile, _mons_summon_elemental } },
397     { SPELL_FIRE_ELEMENTALS, { _always_worthwhile, _mons_summon_elemental } },
398     { SPELL_HASTE_OTHER, {
399         _always_worthwhile,
400         _fire_simple_beam,
401         _buff_beam_setup(BEAM_HASTE)
402     } },
403     { SPELL_MIGHT_OTHER, {
404         _always_worthwhile,
405         _fire_simple_beam,
406         _buff_beam_setup(BEAM_MIGHT)
407     } },
408     { SPELL_INVISIBILITY_OTHER, {
409         _always_worthwhile,
410         _fire_simple_beam,
411         _buff_beam_setup(BEAM_INVISIBILITY)
412     } },
413     { SPELL_HEAL_OTHER, {
414         _always_worthwhile,
415         _fire_simple_beam,
416         _setup_heal_other,
417     } },
418     { SPELL_LRD, {
419         _always_worthwhile,
__anon2840f9481202() 420         [](monster &caster, mon_spell_slot slot, bolt& pbolt) {
421             const int splpow = mons_spellpower(caster, slot.spell);
422             cast_fragmentation(splpow, &caster, pbolt.target, false);
423         },
424         _target_beam_setup(_mons_fragment_target),
425         MSPELL_LOGIC_NONE, 6
426     } },
427     { SPELL_AWAKEN_EARTH, {
428         _always_worthwhile,
__anon2840f9481302() 429         [](monster &caster, mon_spell_slot, bolt& pbolt) {
430             _mons_awaken_earth(caster, pbolt.target);
431         },
432         _target_beam_setup(_mons_awaken_earth_target),
433     } },
434     { SPELL_GHOSTLY_SACRIFICE, {
435         _always_worthwhile,
__anon2840f9481402() 436         [](monster &caster, mon_spell_slot slot, bolt& pbolt) {
437             if (_prepare_ghostly_sacrifice(caster, pbolt))
438                 _fire_direct_explosion(caster, slot, pbolt);
439             else if (you.can_see(caster))
440                 canned_msg(MSG_NOTHING_HAPPENS);
441         },
442         _setup_ghostly_sacrifice_beam,
443     } },
444     { SPELL_SLOW, _hex_logic(SPELL_SLOW) },
445     { SPELL_CONFUSE, _hex_logic(SPELL_CONFUSE) },
446     { SPELL_BANISHMENT, _hex_logic(SPELL_BANISHMENT) },
447     { SPELL_PARALYSE, _hex_logic(SPELL_PARALYSE) },
448     { SPELL_PETRIFY, _hex_logic(SPELL_PETRIFY) },
__anon2840f9481502() 449     { SPELL_PAIN, _hex_logic(SPELL_PAIN, [](const monster& caster) {
450             const actor* foe = caster.get_foe();
451             ASSERT(foe);
452             // why does this check rTorment, not rN?
453             return ai_action::good_or_impossible(_torment_vulnerable(foe));
454     }) },
455     { SPELL_MINDBURST, _hex_logic(SPELL_MINDBURST) },
__anon2840f9481602() 456     { SPELL_CORONA, _hex_logic(SPELL_CORONA, [](const monster& caster) {
457             const actor* foe = caster.get_foe();
458             ASSERT(foe);
459             return ai_action::good_or_impossible(!foe->backlit());
460     }) },
__anon2840f9481702() 461     { SPELL_POLYMORPH, _hex_logic(SPELL_POLYMORPH, [](const monster& caster) {
462         return ai_action::good_or_bad(!caster.friendly()); // too dangerous to let allies use
463     }) },
464 
465     { SPELL_SLEEP, _hex_logic(SPELL_SLEEP, _foe_sleep_viable, 6) },
466     { SPELL_HIBERNATION, _hex_logic(SPELL_HIBERNATION, _foe_sleep_viable) },
467     { SPELL_TELEPORT_OTHER, _hex_logic(SPELL_TELEPORT_OTHER,
468                                          _foe_tele_goodness) },
469     { SPELL_DIMENSION_ANCHOR, _hex_logic(SPELL_DIMENSION_ANCHOR, nullptr, 6)},
__anon2840f9481802() 470     { SPELL_AGONY_RANGE, _hex_logic(SPELL_AGONY_RANGE, [](const monster &caster) {
471             const actor* foe = caster.get_foe();
472             ASSERT(foe);
473             return ai_action::good_or_impossible(_torment_vulnerable(foe));
474         }, 6)
475     },
__anon2840f9481902() 476     { SPELL_AGONY, _hex_logic(SPELL_AGONY, [](const monster &caster) {
477             const actor* foe = caster.get_foe();
478             ASSERT(foe);
479             return ai_action::good_or_impossible(_torment_vulnerable(foe));
480         }, 6)
481     },
482     { SPELL_STRIP_WILLPOWER,
483         _hex_logic(SPELL_STRIP_WILLPOWER, _foe_mr_lower_goodness, 6)
484     },
485     { SPELL_SENTINEL_MARK, _hex_logic(SPELL_SENTINEL_MARK, nullptr, 16) },
486     { SPELL_SAP_MAGIC, {
487         _always_worthwhile, _fire_simple_beam, _zap_setup(SPELL_SAP_MAGIC),
488         MSPELL_LOGIC_NONE, 10,
489     } },
490     { SPELL_DRAIN_MAGIC, _hex_logic(SPELL_DRAIN_MAGIC, nullptr, 6) },
__anon2840f9481a02() 491     { SPELL_VIRULENCE, _hex_logic(SPELL_VIRULENCE, [](const monster &caster) {
492             const actor* foe = caster.get_foe();
493             ASSERT(foe);
494             return ai_action::good_or_impossible(foe->res_poison(false) < 3);
495     }, 6) },
496     { SPELL_GRASPING_ROOTS, {
497         [](const monster &caster)
__anon2840f9481b02() 498         {
499             const actor* foe = caster.get_foe();
500             ASSERT(foe);
501             return ai_action::good_or_impossible(caster.can_constrict(foe, false));
502         }, _cast_grasping_roots, } },
503     { SPELL_ABJURATION, {
504         _mons_will_abjure,
__anon2840f9481c02() 505         [] (const monster &caster, mon_spell_slot /*slot*/, bolt& /*beem*/) {
506             _monster_abjuration(caster, true);
507         }, nullptr, MSPELL_LOGIC_NONE, 20, } },
508     { SPELL_CONCENTRATE_VENOM, {
509         _always_worthwhile,
510         _fire_simple_beam,
511         _buff_beam_setup(BEAM_CONCENTRATE_VENOM)
512     } },
513 };
514 
515 /// Create the appropriate casting logic for a simple conjuration.
_conjuration_logic(spell_type spell)516 static mons_spell_logic _conjuration_logic(spell_type spell)
517 {
518     return { _always_worthwhile, _fire_simple_beam, _zap_setup(spell), };
519 }
520 
521 /**
522  * Create the appropriate casting logic for a simple mr-checking hex.
523  *
524  * @param spell             The hex in question; e.g. SPELL_CORONA.
525  * @param extra_logic       An additional pre-casting condition, beyond the
526  *                          normal hex logic.
527  * @param power_hd_factor   If nonzero, how much spellpower the spell has per
528  *                          caster HD.
529  */
_hex_logic(spell_type spell,function<ai_action::goodness (const monster &)> extra_logic,int power_hd_factor)530 static mons_spell_logic _hex_logic(spell_type spell,
531                                    function<ai_action::goodness(const monster&)> extra_logic,
532                                    int power_hd_factor)
533 {
534     function<ai_action::goodness(const monster&)> calc_goodness = nullptr;
535     if (!extra_logic)
536         calc_goodness = _setup_hex_check(spell);
537     else
538     {
539         calc_goodness = [spell, extra_logic](const monster& caster) {
540             return min(_hexing_goodness(caster, spell), extra_logic(caster));
541         };
542     }
543     return { calc_goodness, _fire_simple_beam, _zap_setup(spell),
544              MSPELL_LOGIC_NONE, power_hd_factor * ENCH_POW_FACTOR };
545 }
546 
547 /**
548  * Take the given beam and fire it, handling screen-refresh issues in the
549  * process.
550  *
551  * @param caster    The monster casting the spell that produced the beam.
552  * @param pbolt     A pre-setup & aimed spell beam. (For e.g. FIREBALL.)
553  */
_fire_simple_beam(monster &,mon_spell_slot,bolt & pbolt)554 static void _fire_simple_beam(monster &/*caster*/, mon_spell_slot, bolt &pbolt)
555 {
556     // If a monster just came into view and immediately cast a spell,
557     // we need to refresh the screen before drawing the beam.
558     viewwindow();
559     update_screen();
560     pbolt.fire();
561 }
562 
563 /**
564  * Take the given explosion and fire it, handling screen-refresh issues in the
565  * process.
566  *
567  * @param caster    The monster casting the spell that produced the beam.
568  * @param pbolt     A pre-setup & aimed spell beam. (For e.g. FIRE_STORM.)
569  */
_fire_direct_explosion(monster & caster,mon_spell_slot,bolt & pbolt)570 static void _fire_direct_explosion(monster &caster, mon_spell_slot, bolt &pbolt)
571 {
572     // If a monster just came into view and immediately cast a spell,
573     // we need to refresh the screen before drawing the beam.
574     viewwindow();
575     update_screen();
576     const actor* foe = caster.get_foe();
577     const bool need_more = foe && (foe->is_player()
578                                    || you.see_cell(foe->pos()));
579     pbolt.in_explosion_phase = false;
580     pbolt.refine_for_explosion();
581     pbolt.explode(need_more);
582 }
583 
_caster_sees_foe(const monster & caster)584 static ai_action::goodness _caster_sees_foe(const monster &caster)
585 {
586     const actor* foe = caster.get_foe();
587     ASSERT(foe);
588     return ai_action::good_or_impossible(caster.can_see(*foe));
589 }
590 
_foe_sleep_viable(const monster & caster)591 static ai_action::goodness _foe_sleep_viable(const monster &caster)
592 {
593     const actor* foe = caster.get_foe();
594     ASSERT(foe);
595     return ai_action::good_or_impossible(foe->can_sleep());
596 }
597 
598 /// use when a dur/ench-type effect can only be cast once
_foe_effect_viable(const monster & caster,duration_type d,enchant_type e)599 static ai_action::goodness _foe_effect_viable(const monster &caster, duration_type d, enchant_type e)
600 {
601     const actor* foe = caster.get_foe();
602     ASSERT(foe);
603     if (foe->is_player())
604         return ai_action::good_or_impossible(!you.duration[d]);
605     else
606         return ai_action::good_or_impossible(!foe->as_monster()->has_ench(e));
607 }
608 
_foe_tele_goodness(const monster & caster)609 static ai_action::goodness _foe_tele_goodness(const monster &caster)
610 {
611     return _foe_effect_viable(caster, DUR_TELEPORT, ENCH_TP);
612 }
613 
_foe_mr_lower_goodness(const monster & caster)614 static ai_action::goodness _foe_mr_lower_goodness(const monster &caster)
615 {
616     return _foe_effect_viable(caster, DUR_LOWERED_WL, ENCH_LOWERED_WL);
617 }
618 
619 /**
620  * Build a function to set up a beam to buff the caster.
621  *
622  * @param flavour   The flavour to buff a caster with.
623  * @return          A function that sets up a beam to buff its caster with
624  *                  the given flavour.
625  */
626 static function<void(bolt&, const monster&, int)>
_selfench_beam_setup(beam_type flavour)627     _selfench_beam_setup(beam_type flavour)
628 {
629     return [flavour](bolt &beam, const monster &caster, int)
630     {
631         beam.flavour = flavour;
632         if (!mons_is_player_shadow(caster))
633             beam.target = caster.pos();
634     };
635 }
636 
637 /**
638  * Build a function that tests whether it's worth casting a buff spell that
639  * applies the given enchantment to the caster.
640  */
_should_selfench(enchant_type ench)641 static function<ai_action::goodness(const monster&)> _should_selfench(enchant_type ench)
642 {
643     return [ench](const monster &caster)
644     {
645         // keep non-summoned pals with haste from spamming constantly
646         if (caster.friendly() && !caster.get_foe() && !caster.is_summoned())
647             return ai_action::bad();
648         return ai_action::good_or_impossible(!caster.has_ench(ench));
649     };
650 }
651 
652 /**
653  * Build a function that sets up and targets a buffing beam at one of the
654  * caster's allies. If the function fails to find an ally, the beam will be
655  * targeted at an out-of-bounds tile to signal failure.
656  *
657  * @param flavour   The flavour to buff an ally with.
658  * @return          A function that sets up a single-target buff beam.
659  */
660 static function<void(bolt&, const monster&, int)>
_buff_beam_setup(beam_type flavour)661     _buff_beam_setup(beam_type flavour)
662 {
663     return [flavour](bolt &beam, const monster &caster, int)
664     {
665         beam.flavour = flavour;
666         const monster* target = _get_allied_target(caster, beam);
667         beam.target = target ? target->pos() : coord_def(GXM+1, GYM+1);
668     };
669 }
670 
671 /**
672  * Build a function to set up a beam with spl-to-zap.
673  *
674  * @param spell     The spell for which beams will be set up.
675  * @return          A function that sets up a beam to zap the given spell.
676  */
_zap_setup(spell_type spell)677 static function<void(bolt&, const monster&, int)> _zap_setup(spell_type spell)
678 {
679     return [spell](bolt &beam, const monster &, int power)
680     {
681         zappy(spell_to_zap(spell), power, true, beam);
682     };
683 }
684 
_setup_healing_beam(bolt & beam,const monster & caster)685 static void _setup_healing_beam(bolt &beam, const monster &caster)
686 {
687     beam.damage   = dice_def(2, caster.spell_hd(SPELL_MINOR_HEALING) / 2);
688     beam.flavour  = BEAM_HEALING;
689 }
690 
_setup_minor_healing(bolt & beam,const monster & caster,int)691 static void _setup_minor_healing(bolt &beam, const monster &caster, int)
692 {
693     _setup_healing_beam(beam, caster);
694     if (!mons_is_player_shadow(caster))
695         beam.target = caster.pos();
696 }
697 
_setup_heal_other(bolt & beam,const monster & caster,int)698 static void _setup_heal_other(bolt &beam, const monster &caster, int)
699 {
700     _setup_healing_beam(beam, caster);
701     const monster* target = _get_allied_target(caster, beam);
702     beam.target = target ? target->pos() : coord_def(GXM+1, GYM+1);
703 }
704 
705 /**
706  * Build a function that sets up a fake beam for targeting special spells.
707  *
708  * @param targeter     A function that finds a target for the given spell.
709  *                      Expected to return an out-of-bounds coord on failure.
710  * @return              A function that initializes a fake targetting beam.
711  */
712 static function<void(bolt&, const monster&, int)>
_target_beam_setup(function<coord_def (const monster &)> targeter)713     _target_beam_setup(function<coord_def(const monster&)> targeter)
714 {
715     return [targeter](bolt& beam, const monster& caster, int)
716     {
717         _setup_fake_beam(beam, caster);
718         // Your shadow keeps your targetting.
719         if (mons_is_player_shadow(caster))
720             return;
721         beam.target = targeter(caster);
722         beam.aimed_at_spot = true;  // to get noise to work properly
723     };
724 }
725 
726 /// Returns true if a message referring to the player's legs makes sense.
_legs_msg_applicable()727 static bool _legs_msg_applicable()
728 {
729     // XX forms
730     return !(you.has_mutation(MUT_CONSTRICTING_TAIL)
731                 || you.fishtail
732                 || you.has_mutation(MUT_TENTACLE_ARMS));
733 }
734 
735 // Monster spell of uselessness, just prints a message.
736 // This spell exists so that some monsters with really strong
737 // spells (ie orc priest) can be toned down a bit. -- bwr
_cast_cantrip(monster & mons,mon_spell_slot slot,bolt & pbolt)738 static void _cast_cantrip(monster &mons, mon_spell_slot slot, bolt& pbolt)
739 {
740     // only messaging; don't bother if you can't see anything anyway.
741     if (!you.see_cell(mons.pos()))
742         return;
743 
744     const bool friendly  = mons.friendly();
745     const bool buff_only = !friendly && is_sanctuary(you.pos());
746     const msg_channel_type channel = (friendly) ? MSGCH_FRIEND_ENCHANT
747                                                 : MSGCH_MONSTER_ENCHANT;
748 
749     if (mons.type != MONS_GASTRONOK)
750     {
751         const char* msgs[] =
752         {
753             " casts a cantrip, but nothing happens.",
754             " begins to cast a cantrip, but forgets the words!",
755             " miscasts a cantrip.",
756             " looks braver for a moment.",
757             " looks encouraged for a moment.",
758             " looks satisfied for a moment.",
759         };
760 
761         simple_monster_message(mons, RANDOM_ELEMENT(msgs), channel);
762         return;
763     }
764 
765     bool has_mon_foe = !invalid_monster_index(mons.foe);
766     if (buff_only
767         || crawl_state.game_is_arena() && !has_mon_foe
768         || friendly && !has_mon_foe
769         || coinflip())
770     {
771         string slugform = getSpeakString("gastronok_self_buff");
772         if (!slugform.empty())
773         {
774             slugform = replace_all(slugform, "@The_monster@",
775                                    mons.name(DESC_THE));
776             mprf(channel, "%s", slugform.c_str());
777         }
778     }
779     else if (!friendly && !has_mon_foe)
780     {
781         mons_cast_noise(&mons, pbolt, slot.spell, slot.flags);
782 
783         // "Enchant" the player.
784         const string slugform = getSpeakString("gastronok_debuff");
785         if (!slugform.empty()
786             && (slugform.find("legs") == string::npos
787                 || _legs_msg_applicable()))
788         {
789             mpr(slugform);
790         }
791     }
792     else
793     {
794         // "Enchant" another monster.
795         string slugform = getSpeakString("gastronok_other_buff");
796         if (!slugform.empty())
797         {
798             slugform = replace_all(slugform, "@The_monster@",
799                                    mons.get_foe()->name(DESC_THE));
800             mprf(channel, "%s", slugform.c_str());
801         }
802     }
803 }
804 
_cast_injury_mirror(monster & mons,mon_spell_slot,bolt &)805 static void _cast_injury_mirror(monster &mons, mon_spell_slot /*slot*/, bolt&)
806 {
807     const string msg
808         = make_stringf(" offers %s to %s, and fills with unholy energy.",
809                        mons.pronoun(PRONOUN_REFLEXIVE).c_str(),
810                        god_name(mons.god).c_str());
811     simple_monster_message(mons, msg.c_str(), MSGCH_MONSTER_SPELL);
812     mons.add_ench(mon_enchant(ENCH_MIRROR_DAMAGE, 0, &mons,
813                               random_range(7, 9) * BASELINE_DELAY));
814     mons.props[MIRROR_RECAST_KEY].get_int()
815         = you.elapsed_time + 150 + random2(60);
816 }
817 
_cast_smiting(monster & caster,mon_spell_slot slot,bolt &)818 static void _cast_smiting(monster &caster, mon_spell_slot slot, bolt&)
819 {
820     const god_type god = _find_god(caster, slot.flags);
821     actor* foe = caster.get_foe();
822     ASSERT(foe);
823 
824     if (foe->is_player())
825         mprf("%s smites you!", _god_name(god).c_str());
826     else
827         simple_monster_message(*foe->as_monster(), " is smitten.");
828 
829     foe->hurt(&caster, 7 + random2avg(11, 2), BEAM_MISSILE, KILLED_BY_BEAM,
830               "", "by divine providence");
831 }
832 
_cast_grasping_roots(monster & caster,mon_spell_slot,bolt &)833 static void _cast_grasping_roots(monster &caster, mon_spell_slot, bolt&)
834 {
835     actor* foe = caster.get_foe();
836     ASSERT(foe);
837 
838     const int turns = 4 + random2avg(div_rand_round(
839                 mons_spellpower(caster, SPELL_GRASPING_ROOTS), 10), 2);
840     dprf("Grasping roots turns: %d", turns);
841     mpr("Roots burst forth from the earth!");
842     if (foe->is_player())
843     {
844         you.increase_duration(DUR_GRASPING_ROOTS, turns);
845         caster.start_constricting(you);
846         mprf(MSGCH_WARN, "The grasping roots grab you!");
847     }
848     else
849     {
850         foe->as_monster()->add_ench(mon_enchant(ENCH_GRASPING_ROOTS, 0, &caster,
851                     turns * BASELINE_DELAY));
852     }
853 }
854 
855 /// Is the given full-LOS attack spell worth casting for the given monster?
_los_spell_worthwhile(const monster & mons,spell_type spell)856 static bool _los_spell_worthwhile(const monster &mons, spell_type spell)
857 {
858     return trace_los_attack_spell(spell, mons_spellpower(mons, spell), &mons)
859            == spret::success;
860 }
861 
862 /// Set up a fake beam, for noise-generating purposes (?)
_setup_fake_beam(bolt & beam,const monster &,int)863 static void _setup_fake_beam(bolt& beam, const monster&, int)
864 {
865     beam.flavour  = BEAM_DEVASTATION;
866     beam.pierce   = true;
867     // Doesn't take distance into account, but this is just a tracer so
868     // we'll ignore that. We need some damage on the tracer so the monster
869     // doesn't think the spell is useless against other monsters.
870     beam.damage   = CONVENIENT_NONZERO_DAMAGE;
871     beam.range    = LOS_RADIUS;
872 }
873 
874 /**
875  * Create a summoned monster.
876  *
877  * @param summoner      The monster doing the summoning.
878  * @param mtyp          The type of monster to summon.
879  * @param dur           The duration for which the monster should last.
880  *                      Not in aut or turns; nonlinear. Sorry!
881  * @param slot          The spell & slot flags.
882  * @return              The summoned creature, if any.
883  */
884 
_summon(const monster & summoner,monster_type mtyp,int dur,mon_spell_slot slot)885 static monster* _summon(const monster &summoner, monster_type mtyp, int dur,
886                         mon_spell_slot slot)
887 {
888     const god_type god = _find_god(summoner, slot.flags);
889     return create_monster(
890             mgen_data(mtyp, SAME_ATTITUDE((&summoner)), summoner.pos(),
891                       summoner.foe)
892             .set_summoned(&summoner, dur, slot.spell, god));
893 }
894 
init_mons_spells()895 void init_mons_spells()
896 {
897     monster fake_mon;
898     fake_mon.type       = MONS_BLACK_DRACONIAN;
899     fake_mon.hit_points = 1;
900     fake_mon.mid = MID_NOBODY; // used indirectly, through _mon_special_name
901 
902     bolt pbolt;
903 
904     for (int i = 0; i < NUM_SPELLS; i++)
905     {
906         spell_type spell = (spell_type) i;
907 
908         _valid_mon_spells[i] = false;
909 
910         if (!is_valid_spell(spell))
911             continue;
912 
913         if (setup_mons_cast(&fake_mon, pbolt, spell, false, true))
914             _valid_mon_spells[i] = true;
915     }
916 }
917 
is_valid_mon_spell(spell_type spell)918 bool is_valid_mon_spell(spell_type spell)
919 {
920     if (spell < 0 || spell >= NUM_SPELLS)
921         return false;
922 
923     return _valid_mon_spells[spell];
924 }
925 
926 /// Is the current spell being cast via player wizmode &z by a dummy mons?
_is_wiz_cast()927 static bool _is_wiz_cast()
928 {
929 #ifdef WIZARD
930     // iffy logic but might be right enough
931     return crawl_state.prev_cmd == CMD_WIZARD;
932 #else
933     return false;
934 #endif
935 }
936 
_flavour_benefits_monster(beam_type flavour,monster & monster)937 static bool _flavour_benefits_monster(beam_type flavour, monster& monster)
938 {
939     switch (flavour)
940     {
941     case BEAM_HASTE:
942         return !monster.has_ench(ENCH_HASTE);
943 
944     case BEAM_MIGHT:
945         return !monster.has_ench(ENCH_MIGHT);
946 
947     case BEAM_INVISIBILITY:
948         return !monster.has_ench(ENCH_INVIS);
949 
950     case BEAM_HEALING:
951         return monster.hit_points != monster.max_hit_points;
952 
953     case BEAM_AGILITY:
954         return !monster.has_ench(ENCH_AGILE);
955 
956     case BEAM_RESISTANCE:
957         return !monster.has_ench(ENCH_RESISTANCE);
958 
959     case BEAM_CONCENTRATE_VENOM:
960         return !monster.has_ench(ENCH_CONCENTRATE_VENOM)
961                && (monster.has_spell(SPELL_SPIT_POISON)
962                    || monster.has_attack_flavour(AF_POISON)
963                    || monster.has_attack_flavour(AF_POISON_STRONG));
964 
965     default:
966         return false;
967     }
968 }
969 
970 /**
971  * Will the given monster consider buffing the given target? (Are they close
972  * enough in type, genus, attitude, etc?)
973  *
974  * @param caster    The monster casting a targeted buff spell.
975  * @param targ      The monster to be buffed.
976  * @return          Whether the monsters are similar enough.
977  */
_monster_will_buff(const monster & caster,const monster & targ)978 static bool _monster_will_buff(const monster &caster, const monster &targ)
979 {
980     if (mons_is_firewood(targ))
981         return false;
982 
983     if (!mons_aligned(&targ, &caster))
984         return false;
985 
986     // don't buff only temporarily-aligned pals (charmed, hexed)
987     if (!mons_atts_aligned(caster.temp_attitude(), targ.real_attitude()))
988         return false;
989 
990     if (caster.type == MONS_IRONBOUND_CONVOKER || mons_enslaved_soul(caster))
991         return true; // will buff any ally
992 
993     if (targ.is_holy() && caster.is_holy())
994         return true;
995 
996     const monster_type caster_genus = mons_genus(caster.type);
997 
998     // Order level buffs
999     if (caster_genus == MONS_NAGA && mons_genus(targ.type) == MONS_SNAKE)
1000         return true;
1001 
1002     return mons_genus(targ.type) == caster_genus
1003            || mons_genus(targ.base_monster) == caster_genus;
1004 }
1005 
1006 /// Find an allied monster to cast a beneficial beam spell at.
_get_allied_target(const monster & caster,bolt & tracer)1007 static monster* _get_allied_target(const monster &caster, bolt &tracer)
1008 {
1009     monster* selected_target = nullptr;
1010     int min_distance = tracer.range;
1011 
1012     for (monster_near_iterator targ(&caster, LOS_NO_TRANS); targ; ++targ)
1013     {
1014         if (*targ == &caster
1015             || !_monster_will_buff(caster, **targ)
1016             || !_flavour_benefits_monster(tracer.flavour, **targ))
1017         {
1018             continue;
1019         }
1020 
1021         // prefer the closest ally we can find (why?)
1022         const int targ_distance = grid_distance(targ->pos(), caster.pos());
1023         if (targ_distance < min_distance)
1024         {
1025             // Make sure we won't hit someone other than we're aiming at.
1026             tracer.target = targ->pos();
1027             fire_tracer(&caster, tracer);
1028             if (!mons_should_fire(tracer)
1029                 || tracer.path_taken.back() != tracer.target)
1030             {
1031                 continue;
1032             }
1033 
1034             min_distance = targ_distance;
1035             selected_target = *targ;
1036         }
1037     }
1038 
1039     return selected_target;
1040 }
1041 
1042 // Find an ally of the target to cast a hex at.
1043 // Note that this deliberately does not target the player.
_set_hex_target(monster * caster,bolt & pbolt)1044 static bool _set_hex_target(monster* caster, bolt& pbolt)
1045 {
1046     monster* selected_target = nullptr;
1047     int min_distance = INT_MAX;
1048 
1049     const actor *foe = caster->get_foe();
1050     if (!foe)
1051         return false;
1052 
1053     for (monster_near_iterator targ(caster, LOS_NO_TRANS); targ; ++targ)
1054     {
1055         if (*targ == caster)
1056             continue;
1057 
1058         const int targ_distance = grid_distance(targ->pos(), foe->pos());
1059 
1060         bool got_target = false;
1061 
1062         if (mons_aligned(*targ, foe)
1063             && !targ->has_ench(ENCH_CHARM)
1064             && !targ->has_ench(ENCH_HEXED)
1065             && !mons_is_firewood(**targ)
1066             && !_flavour_benefits_monster(pbolt.flavour, **targ))
1067         {
1068             got_target = true;
1069         }
1070 
1071         if (got_target && targ_distance < min_distance
1072             && targ_distance < pbolt.range)
1073         {
1074             // Make sure we won't hit an invalid target with this aim.
1075             pbolt.target = targ->pos();
1076             fire_tracer(caster, pbolt);
1077             if (!mons_should_fire(pbolt)
1078                 || pbolt.path_taken.back() != pbolt.target)
1079             {
1080                 continue;
1081             }
1082 
1083             min_distance = targ_distance;
1084             selected_target = *targ;
1085         }
1086     }
1087 
1088     if (selected_target)
1089     {
1090         pbolt.target = selected_target->pos();
1091         return true;
1092     }
1093 
1094     // Didn't find a target.
1095     return false;
1096 }
1097 
1098 /**
1099  * What value do monsters multiply their hd with to get spellpower, for the
1100  * given spell?
1101  *
1102  * XXX: everything could be trivially exported to data.
1103  *
1104  * @param spell     The spell in question.
1105  * @return          A multiplier to HD for spellpower.
1106  *                  Value may exceed 200.
1107  */
_mons_power_hd_factor(spell_type spell)1108 static int _mons_power_hd_factor(spell_type spell)
1109 {
1110     const mons_spell_logic* logic = map_find(spell_to_logic, spell);
1111     if (logic && logic->power_hd_factor)
1112         return logic->power_hd_factor;
1113 
1114     switch (spell)
1115     {
1116         case SPELL_CONFUSION_GAZE:
1117             return 8 * ENCH_POW_FACTOR;
1118 
1119         case SPELL_CAUSE_FEAR:
1120             return 18 * ENCH_POW_FACTOR;
1121 
1122         case SPELL_MESMERISE:
1123             return 10 * ENCH_POW_FACTOR;
1124 
1125         case SPELL_SIREN_SONG:
1126         case SPELL_AVATAR_SONG:
1127             return 9 * ENCH_POW_FACTOR;
1128 
1129         case SPELL_MASS_CONFUSION:
1130             return 8 * ENCH_POW_FACTOR;
1131 
1132         case SPELL_CALL_DOWN_LIGHTNING:
1133             return 16;
1134 
1135         case SPELL_OLGREBS_TOXIC_RADIANCE:
1136             return 8;
1137 
1138         case SPELL_MONSTROUS_MENAGERIE:
1139         case SPELL_BATTLESPHERE:
1140         case SPELL_IGNITE_POISON:
1141         case SPELL_IOOD:
1142         case SPELL_FREEZE:
1143             return 6;
1144 
1145         case SPELL_SUMMON_DRAGON:
1146         case SPELL_SUMMON_HYDRA:
1147             return 5;
1148 
1149         case SPELL_CHAIN_OF_CHAOS:
1150             return 4;
1151 
1152         default:
1153             return 12;
1154     }
1155 }
1156 
1157 /**
1158  * Does this spell use spell_hd or just hit_dice for damage and accuracy?
1159  *
1160  * @param spell The spell in question.
1161  * @return True iff the spell should use spell_hd.
1162  */
mons_spell_is_spell(spell_type spell)1163 bool mons_spell_is_spell(spell_type spell)
1164 {
1165     switch (spell)
1166     {
1167         case SPELL_HOLY_BREATH:
1168         case SPELL_SPIT_ACID:
1169         case SPELL_ACID_SPLASH:
1170         case SPELL_CHAOS_BREATH:
1171         case SPELL_COLD_BREATH:
1172         case SPELL_CHILLING_BREATH:
1173         case SPELL_FIRE_BREATH:
1174         case SPELL_SEARING_BREATH:
1175         case SPELL_ELECTRICAL_BOLT:
1176         case SPELL_FLAMING_CLOUD:
1177             return false;
1178         default:
1179             return true;
1180     }
1181 }
1182 
1183 /**
1184  * What spellpower does a monster with the given spell_hd cast the given spell
1185  * at?
1186  *
1187  * @param spell     The spell in question.
1188  * @param hd        The spell_hd of the given monster.
1189  * @return          A spellpower value for the spell.
1190  */
mons_power_for_hd(spell_type spell,int hd)1191 int mons_power_for_hd(spell_type spell, int hd)
1192 {
1193     const int power = hd * _mons_power_hd_factor(spell);
1194     if (spell == SPELL_PAIN)
1195         return max(50 * ENCH_POW_FACTOR, power);
1196     return power;
1197 }
1198 
1199 /**
1200  * What power does the given monster cast the given spell with?
1201  *
1202  * @param spell     The spell in question.
1203  * @param mons      The monster in question.
1204  * @return          A spellpower value for the spell.
1205  *                  May vary from call to call for certain weird spells.
1206  */
mons_spellpower(const monster & mons,spell_type spell)1207 int mons_spellpower(const monster &mons, spell_type spell)
1208 {
1209     return mons_power_for_hd(spell, mons.spell_hd(spell));
1210 }
1211 
1212 /**
1213  * What power does the given monster cast the given enchantment with?
1214  *
1215  * @param spell     The spell in question.
1216  * @param mons      The monster in question.
1217  * @param cap       The maximum power of the spell.
1218  * @return          A spellpower value for the spell, with ENCH_POW_FACTOR
1219  *                  removed & capped at maximum spellpower.
1220  */
_ench_power(spell_type spell,const monster & mons)1221 static int _ench_power(spell_type spell, const monster &mons)
1222 {
1223     const int cap = 200;
1224     return min(cap, mons_spellpower(mons, spell) / ENCH_POW_FACTOR);
1225 }
1226 
_mons_spell_range(const monster & mons,spell_type spell)1227 static int _mons_spell_range(const monster &mons, spell_type spell)
1228 {
1229     return mons_spell_range_for_hd(spell, mons.spell_hd());
1230 }
1231 
1232 /**
1233  * How much range does a monster of the given spell HD have with the given
1234  * spell?
1235  *
1236  * @param spell     The spell in question.
1237  * @param hd        The monster's effective HD for spellcasting purposes.
1238  * @return          -1 if the spell has an undefined range; else its range.
1239  */
mons_spell_range_for_hd(spell_type spell,int hd)1240 int mons_spell_range_for_hd(spell_type spell, int hd)
1241 {
1242     switch (spell)
1243     {
1244         case SPELL_FLAME_TONGUE:
1245             // HD:1 monsters would get range 2, HD:2 -- 3, other 4, let's
1246             // use the mighty Throw Flame for big ranges.
1247             return min(2, hd);
1248         default:
1249             break;
1250     }
1251 
1252     const int power = mons_power_for_hd(spell, hd);
1253     return spell_range(spell, power, false);
1254 }
1255 
1256 /**
1257  * What god is responsible for a spell cast by the given monster with the
1258  * given flags?
1259  *
1260  * Relevant for Smite messages & summons, sometimes.
1261  *
1262  * @param mons      The monster casting the spell.
1263  * @param flags     The slot flags;
1264  *                  e.g. MON_SPELL_NATURAL | MON_SPELL_NOISY.
1265  * @return          The god that is responsible for the spell.
1266  */
_find_god(const monster & mons,mon_spell_slot_flags flags)1267 static god_type _find_god(const monster &mons, mon_spell_slot_flags flags)
1268 {
1269     // Permanent wizard summons of Yred should have the same god even
1270     // though they aren't priests. This is so that e.g. the zombies of
1271     // Yred's enslaved souls will properly turn on you if you abandon
1272     // Yred.
1273     if (mons.god == GOD_YREDELEMNUL)
1274         return mons.god;
1275 
1276     // If this is a wizard spell, summons won't necessarily have the
1277     // same god. But intrinsic/priestly summons should.
1278     return flags & MON_SPELL_WIZARD ? GOD_NO_GOD : mons.god;
1279 }
1280 
_major_destruction_spell()1281 static spell_type _major_destruction_spell()
1282 {
1283     return random_choose(SPELL_BOLT_OF_FIRE,
1284                          SPELL_FIREBALL,
1285                          SPELL_LIGHTNING_BOLT,
1286                          SPELL_STICKY_FLAME,
1287                          SPELL_IRON_SHOT,
1288                          SPELL_BOLT_OF_DRAINING,
1289                          SPELL_ORB_OF_ELECTRICITY);
1290 }
1291 
_legendary_destruction_spell()1292 static spell_type _legendary_destruction_spell()
1293 {
1294     return random_choose_weighted(25, SPELL_FIREBALL,
1295                                   20, SPELL_ICEBLAST,
1296                                   15, SPELL_GHOSTLY_FIREBALL);
1297 }
1298 
1299 // TODO: documentme
1300 // NOTE: usually doesn't set target, but if set, should take precedence
mons_spell_beam(const monster * mons,spell_type spell_cast,int power,bool check_validity)1301 bolt mons_spell_beam(const monster* mons, spell_type spell_cast, int power,
1302                      bool check_validity)
1303 {
1304     ASSERT(power > 0);
1305 
1306     bolt beam;
1307 
1308     // Initialise to some bogus values so we can catch problems.
1309     beam.name         = "****";
1310     beam.colour       = 255;
1311     beam.hit          = -1;
1312     beam.damage       = dice_def(1, 0);
1313     beam.ench_power   = max(1, power / ENCH_POW_FACTOR); // U G H
1314     beam.glyph        = 0;
1315     beam.flavour      = BEAM_NONE;
1316     beam.thrower      = KILL_MISC;
1317     beam.pierce       = false;
1318     beam.is_explosion = false;
1319     beam.attitude     = mons_attitude(*mons);
1320 
1321     beam.range = _mons_spell_range(*mons, spell_cast);
1322 
1323     spell_type real_spell = spell_cast;
1324 
1325     if (spell_cast == SPELL_MAJOR_DESTRUCTION)
1326         real_spell = _major_destruction_spell();
1327     else if (spell_cast == SPELL_LEGENDARY_DESTRUCTION)
1328     {
1329         // ones with ranges too small are fixed in setup_mons_cast
1330         real_spell = _legendary_destruction_spell();
1331     }
1332     else if (spell_is_soh_breath(spell_cast))
1333     {
1334         // this will be fixed up later in mons_cast
1335         // XXX: is this necessary?
1336         real_spell = SPELL_FIRE_BREATH;
1337     }
1338     beam.glyph = dchar_glyph(DCHAR_FIRED_ZAP); // default
1339     beam.thrower = KILL_MON_MISSILE;
1340     beam.origin_spell = real_spell;
1341     beam.source_id = mons->mid;
1342     beam.source_name = mons->name(DESC_A, true);
1343 
1344     if (!mons_spell_is_spell(real_spell))
1345         power = mons_power_for_hd(real_spell, mons->get_hit_dice());
1346 
1347     const mons_spell_logic* logic = map_find(spell_to_logic, spell_cast);
1348     if (logic && logic->setup_beam)
1349         logic->setup_beam(beam, *mons, power);
1350 
1351     // FIXME: more of these should use the zap_data[] struct from beam.cc!
1352     switch (real_spell)
1353     {
1354     case SPELL_ORB_OF_ELECTRICITY:
1355         beam.foe_ratio      = random_range(40, 55); // ...
1356         // fallthrough to other zaps
1357     case SPELL_MAGIC_DART:
1358     case SPELL_THROW_FLAME:
1359     case SPELL_THROW_FROST:
1360     case SPELL_FLAME_TONGUE:
1361     case SPELL_VENOM_BOLT:
1362     case SPELL_POISON_ARROW:
1363     case SPELL_BOLT_OF_MAGMA:
1364     case SPELL_BOLT_OF_FIRE:
1365     case SPELL_BOLT_OF_COLD:
1366     case SPELL_THROW_ICICLE:
1367     case SPELL_SHOCK:
1368     case SPELL_LIGHTNING_BOLT:
1369     case SPELL_FIREBALL:
1370     case SPELL_ICEBLAST:
1371     case SPELL_LEHUDIBS_CRYSTAL_SPEAR:
1372     case SPELL_BOLT_OF_DRAINING:
1373     case SPELL_STICKY_FLAME:
1374     case SPELL_STICKY_FLAME_RANGE:
1375     case SPELL_STING:
1376     case SPELL_IRON_SHOT:
1377     case SPELL_STONE_ARROW:
1378     case SPELL_FORCE_LANCE:
1379     case SPELL_CORROSIVE_BOLT:
1380     case SPELL_HIBERNATION:
1381     case SPELL_SLEEP:
1382     case SPELL_DIG:
1383     case SPELL_CHARMING:
1384     case SPELL_QUICKSILVER_BOLT:
1385     case SPELL_PRIMAL_WAVE:
1386     case SPELL_BLINKBOLT:
1387     case SPELL_STEAM_BALL:
1388     case SPELL_TELEPORT_OTHER:
1389     case SPELL_SANDBLAST:
1390     case SPELL_HARPOON_SHOT:
1391     case SPELL_THROW_PIE:
1392     case SPELL_NOXIOUS_CLOUD:
1393     case SPELL_POISONOUS_CLOUD:
1394     case SPELL_THORN_VOLLEY:
1395     case SPELL_HURL_DAMNATION:
1396     case SPELL_SPIT_POISON:
1397     case SPELL_MIASMA_BREATH:      // death drake
1398     case SPELL_GHOSTLY_FIREBALL:
1399     case SPELL_FLASH_FREEZE:
1400     case SPELL_CRYSTAL_BOLT:
1401     case SPELL_SPIT_LAVA:
1402     case SPELL_HURL_SLUDGE:
1403     case SPELL_HOLY_BREATH:
1404     case SPELL_SPIT_ACID:
1405     case SPELL_ACID_SPLASH:
1406     case SPELL_ELECTRICAL_BOLT:
1407     case SPELL_DISPEL_UNDEAD_RANGE:
1408     case SPELL_STUNNING_BURST:
1409         zappy(spell_to_zap(real_spell), power, true, beam);
1410         break;
1411 
1412     case SPELL_FREEZING_CLOUD: // battlesphere special-case
1413         zappy(ZAP_FREEZING_BLAST, power, true, beam);
1414         break;
1415 
1416     case SPELL_ENERGY_BOLT:
1417         zappy(spell_to_zap(real_spell), power, true, beam);
1418         beam.short_name = "energy";
1419         break;
1420 
1421     case SPELL_MALMUTATE:
1422         beam.flavour  = BEAM_MALMUTATE;
1423         break;
1424 
1425     case SPELL_FIRE_STORM:
1426         setup_fire_storm(mons, power / 2, beam);
1427         beam.foe_ratio = random_range(40, 55);
1428         break;
1429 
1430     case SPELL_CALL_DOWN_DAMNATION: // Set explosion size for tracer
1431         zappy(spell_to_zap(real_spell), power, true, beam);
1432         beam.ex_size = 1;
1433         break;
1434 
1435     case SPELL_MEPHITIC_CLOUD:
1436         beam.name     = "stinking cloud";
1437         beam.damage   = dice_def(1, 0);
1438         beam.colour   = GREEN;
1439         beam.flavour  = BEAM_MEPHITIC;
1440         beam.hit      = 14 + power / 30;
1441         beam.is_explosion = true;
1442         break;
1443 
1444     case SPELL_METAL_SPLINTERS:
1445         zappy(spell_to_zap(real_spell), power, true, beam);
1446         beam.short_name = "metal splinters";
1447         break;
1448 
1449     case SPELL_SPLINTERSPRAY:
1450         zappy(spell_to_zap(real_spell), power, true, beam);
1451         beam.short_name = "splinters";
1452         break;
1453 
1454     case SPELL_BLINK_OTHER:
1455         beam.flavour    = BEAM_BLINK;
1456         break;
1457 
1458     case SPELL_BLINK_OTHER_CLOSE:
1459         beam.flavour    = BEAM_BLINK_CLOSE;
1460         break;
1461 
1462     case SPELL_FIRE_BREATH:
1463         zappy(spell_to_zap(real_spell), power, true, beam);
1464         beam.aux_source = "blast of fiery breath";
1465         beam.short_name = "flames";
1466         break;
1467 
1468     case SPELL_SEARING_BREATH:
1469         if (mons && mons->type == MONS_XTAHUA)
1470             power = power * 3/2;
1471         zappy(spell_to_zap(real_spell), power, true, beam);
1472         beam.aux_source  = "blast of searing breath";
1473         break;
1474 
1475     case SPELL_CHAOS_BREATH:
1476         zappy(spell_to_zap(real_spell), power, true, beam);
1477         beam.aux_source   = "blast of chaotic breath";
1478         break;
1479 
1480     case SPELL_COLD_BREATH:
1481         if (mons && mons_is_draconian(mons->type))
1482             power = power * 2 / 3;
1483         zappy(spell_to_zap(real_spell), power, true, beam);
1484         beam.aux_source = "blast of icy breath";
1485         beam.short_name = "frost";
1486         break;
1487 
1488     case SPELL_CHILLING_BREATH:
1489         zappy(spell_to_zap(real_spell), power, true, beam);
1490         beam.name = "chilling breath";
1491         beam.aux_source  = "blast of chilling breath";
1492         beam.short_name  = "frost";
1493         break;
1494 
1495     case SPELL_PORKALATOR:
1496         beam.name     = "porkalator";
1497         beam.glyph    = 0;
1498         beam.flavour  = BEAM_PORKALATOR;
1499         beam.thrower  = KILL_MON_MISSILE;
1500         break;
1501 
1502     case SPELL_IOOD:                  // tracer only
1503     case SPELL_PORTAL_PROJECTILE:     // for noise generation purposes
1504     case SPELL_GLACIATE:              // ditto
1505         _setup_fake_beam(beam, *mons);
1506         break;
1507 
1508     case SPELL_PETRIFYING_CLOUD:
1509         zappy(spell_to_zap(real_spell), power, true, beam);
1510         beam.foe_ratio = 30;
1511         break;
1512 
1513     case SPELL_ENSNARE:
1514         beam.name     = "stream of webbing";
1515         beam.colour   = WHITE;
1516         beam.glyph    = dchar_glyph(DCHAR_FIRED_MISSILE);
1517         beam.flavour  = BEAM_ENSNARE;
1518         beam.hit      = 22 + power / 20;
1519         break;
1520 
1521     case SPELL_SPECTRAL_CLOUD:
1522         beam.name     = "spectral mist";
1523         beam.damage   = dice_def(0, 1);
1524         beam.colour   = CYAN;
1525         beam.flavour  = BEAM_MMISSILE;
1526         beam.hit      = AUTOMATIC_HIT;
1527         beam.pierce   = true;
1528         break;
1529 
1530     case SPELL_DIMENSION_ANCHOR:
1531         beam.flavour    = BEAM_DIMENSION_ANCHOR;
1532         break;
1533 
1534     // XXX: This seems needed to give proper spellcasting messages, even though
1535     //      damage is done via another means
1536     case SPELL_FREEZE:
1537         beam.flavour    = BEAM_COLD;
1538         break;
1539 
1540     case SPELL_MALIGN_OFFERING:
1541         beam.flavour    = BEAM_MALIGN_OFFERING;
1542         beam.damage     = dice_def(2, 7 + (power / 13));
1543         break;
1544 
1545     case SPELL_SHADOW_BOLT:
1546         beam.name     = "shadow bolt";
1547         beam.pierce   = true;
1548         // deliberate fall-through
1549     case SPELL_SHADOW_SHARD:
1550         if (real_spell == SPELL_SHADOW_SHARD)
1551             beam.name  = "shadow shard";
1552         beam.damage   = dice_def(3, 8 + power / 11);
1553         beam.colour   = MAGENTA;
1554         beam.flavour  = BEAM_MMISSILE;
1555         beam.hit      = 17 + power / 25;
1556         break;
1557 
1558     case SPELL_FLAMING_CLOUD:
1559         zappy(spell_to_zap(real_spell), power, true, beam);
1560         beam.aux_source   = "blast of fiery breath";
1561         beam.short_name   = "flames";
1562         break;
1563 
1564     case SPELL_THROW_BARBS:
1565         zappy(spell_to_zap(real_spell), power, true, beam);
1566         beam.hit_verb    = "skewers";
1567         break;
1568 
1569     case SPELL_DEATH_RATTLE:
1570         beam.name     = "vile air";
1571         beam.colour   = DARKGREY;
1572         beam.damage   = dice_def(2, 4);
1573         beam.hit      = AUTOMATIC_HIT;
1574         beam.flavour  = BEAM_DEATH_RATTLE;
1575         beam.foe_ratio = 30;
1576         beam.pierce   = true;
1577         break;
1578 
1579     // Special behaviour handled in _mons_upheaval
1580     // Hack so beam.cc allows us to correctly use that function
1581     case SPELL_UPHEAVAL:
1582         beam.flavour     = BEAM_RANDOM;
1583         beam.damage      = dice_def(3, 24);
1584         beam.hit         = AUTOMATIC_HIT;
1585         beam.glyph       = dchar_glyph(DCHAR_EXPLOSION);
1586         beam.ex_size     = 2;
1587         break;
1588 
1589     case SPELL_ERUPTION:
1590         beam.flavour     = BEAM_LAVA;
1591         beam.damage      = dice_def(3, 24);
1592         beam.hit         = AUTOMATIC_HIT;
1593         beam.glyph       = dchar_glyph(DCHAR_EXPLOSION);
1594         beam.ex_size     = 2;
1595         break;
1596 
1597     default:
1598         if (logic && logic->setup_beam) // already setup
1599             break;
1600 
1601         if (check_validity)
1602         {
1603             beam.flavour = NUM_BEAMS;
1604             return beam;
1605         }
1606 
1607         if (!is_valid_spell(real_spell))
1608         {
1609             die("Invalid spell #%d cast by %s", (int) real_spell,
1610                      mons->name(DESC_PLAIN, true).c_str());
1611         }
1612 
1613         die("Unknown monster spell '%s' cast by %s",
1614                  spell_title(real_spell),
1615                  mons->name(DESC_PLAIN, true).c_str());
1616     }
1617 
1618     if (beam.is_enchantment())
1619     {
1620         beam.hit = AUTOMATIC_HIT;
1621         beam.glyph = 0;
1622         beam.name = "";
1623     }
1624 
1625     return beam;
1626 }
1627 
1628 // Set up bolt structure for monster spell casting.
setup_mons_cast(const monster * mons,bolt & pbolt,spell_type spell_cast,bool evoke,bool check_validity)1629 bool setup_mons_cast(const monster* mons, bolt &pbolt, spell_type spell_cast,
1630                      bool evoke,
1631                      bool check_validity)
1632 {
1633     // always set these -- used by things other than fire_beam()
1634 
1635     pbolt.source_id = mons->mid;
1636 
1637     // Convenience for the hapless innocent who assumes that this
1638     // damn function does all possible setup. [ds]
1639     if (pbolt.target.origin())
1640         pbolt.target = mons->target;
1641 
1642     // Set bolt type and range.
1643     if (spell_is_direct_explosion(spell_cast))
1644     {
1645         pbolt.range = 0;
1646         pbolt.glyph = 0;
1647     }
1648 
1649     // The below are no-ops since they don't involve fire_tracer or beams.
1650     switch (spell_cast)
1651     {
1652     case SPELL_SUMMON_SMALL_MAMMAL:
1653     case SPELL_MAJOR_HEALING:
1654     case SPELL_WOODWEAL:
1655     case SPELL_SHADOW_CREATURES:       // summon anything appropriate for level
1656     case SPELL_FAKE_MARA_SUMMON:
1657     case SPELL_SUMMON_ILLUSION:
1658     case SPELL_SUMMON_DEMON:
1659     case SPELL_MONSTROUS_MENAGERIE:
1660 #if TAG_MAJOR_VERSION == 34
1661     case SPELL_ANIMATE_DEAD:
1662     case SPELL_TWISTED_RESURRECTION:
1663     case SPELL_SIMULACRUM:
1664 #endif
1665     case SPELL_CALL_IMP:
1666     case SPELL_SUMMON_MINOR_DEMON:
1667     case SPELL_SUMMON_UFETUBUS:
1668     case SPELL_SUMMON_HELL_BEAST:  // Geryon
1669     case SPELL_SUMMON_UNDEAD:
1670     case SPELL_SUMMON_ICE_BEAST:
1671     case SPELL_SUMMON_MUSHROOMS:
1672     case SPELL_CONJURE_BALL_LIGHTNING:
1673     case SPELL_SUMMON_DRAKES:
1674     case SPELL_SUMMON_HORRIBLE_THINGS:
1675     case SPELL_MALIGN_GATEWAY:
1676     case SPELL_SYMBOL_OF_TORMENT:
1677     case SPELL_CAUSE_FEAR:
1678     case SPELL_MESMERISE:
1679     case SPELL_SUMMON_GREATER_DEMON:
1680     case SPELL_BROTHERS_IN_ARMS:
1681     case SPELL_BERSERKER_RAGE:
1682     case SPELL_SPRINT:
1683 #if TAG_MAJOR_VERSION == 34
1684     case SPELL_SWIFTNESS:
1685 #endif
1686     case SPELL_CREATE_TENTACLES:
1687     case SPELL_BLINK:
1688     case SPELL_BLINK_RANGE:
1689     case SPELL_BLINK_AWAY:
1690     case SPELL_BLINK_CLOSE:
1691     case SPELL_TOMB_OF_DOROKLOHE:
1692     case SPELL_CHAIN_LIGHTNING:    // the only user is reckless
1693     case SPELL_CHAIN_OF_CHAOS:
1694     case SPELL_SUMMON_EYEBALLS:
1695     case SPELL_CALL_TIDE:
1696     case SPELL_INK_CLOUD:
1697     case SPELL_SILENCE:
1698     case SPELL_AWAKEN_FOREST:
1699     case SPELL_DRUIDS_CALL:
1700     case SPELL_SUMMON_HOLIES:
1701     case SPELL_CORPSE_ROT:
1702     case SPELL_SUMMON_DRAGON:
1703     case SPELL_SUMMON_HYDRA:
1704     case SPELL_FIRE_SUMMON:
1705 #if TAG_MAJOR_VERSION == 34
1706     case SPELL_DEATHS_DOOR:
1707     case SPELL_OZOCUBUS_ARMOUR:
1708 #endif
1709     case SPELL_OLGREBS_TOXIC_RADIANCE:
1710     case SPELL_SHATTER:
1711     case SPELL_BATTLESPHERE:
1712     case SPELL_WORD_OF_RECALL:
1713     case SPELL_INJURY_BOND:
1714     case SPELL_CALL_LOST_SOUL:
1715     case SPELL_BLINK_ALLIES_ENCIRCLE:
1716     case SPELL_MASS_CONFUSION:
1717     case SPELL_ENGLACIATION:
1718     case SPELL_AWAKEN_VINES:
1719     case SPELL_WALL_OF_BRAMBLES:
1720     case SPELL_WIND_BLAST:
1721     case SPELL_SUMMON_VERMIN:
1722     case SPELL_POLAR_VORTEX:
1723     case SPELL_DISCHARGE:
1724     case SPELL_IGNITE_POISON:
1725     case SPELL_BLACK_MARK:
1726     case SPELL_BLINK_ALLIES_AWAY:
1727     case SPELL_PHANTOM_MIRROR:
1728     case SPELL_SUMMON_MANA_VIPER:
1729     case SPELL_SUMMON_EMPEROR_SCORPIONS:
1730     case SPELL_BATTLECRY:
1731     case SPELL_WARNING_CRY:
1732     case SPELL_SEAL_DOORS:
1733     case SPELL_BERSERK_OTHER:
1734     case SPELL_SPELLFORGED_SERVITOR:
1735     case SPELL_THROW_ALLY:
1736     case SPELL_CORRUPTING_PULSE:
1737     case SPELL_SIREN_SONG:
1738     case SPELL_AVATAR_SONG:
1739     case SPELL_REPEL_MISSILES:
1740     case SPELL_SUMMON_SCARABS:
1741     case SPELL_CLEANSING_FLAME:
1742     case SPELL_DRAINING_GAZE:
1743     case SPELL_CONFUSION_GAZE:
1744     case SPELL_HAUNT:
1745     case SPELL_SUMMON_SPECTRAL_ORCS:
1746     case SPELL_BRAIN_FEED:
1747     case SPELL_HOLY_FLAMES:
1748     case SPELL_CALL_OF_CHAOS:
1749     case SPELL_AIRSTRIKE:
1750     case SPELL_WATERSTRIKE:
1751     case SPELL_GRAVITAS:
1752     case SPELL_ENTROPIC_WEAVE:
1753     case SPELL_SUMMON_EXECUTIONERS:
1754     case SPELL_DOOM_HOWL:
1755     case SPELL_AURA_OF_BRILLIANCE:
1756     case SPELL_GREATER_SERVANT_MAKHLEB:
1757     case SPELL_BIND_SOULS:
1758     case SPELL_DREAM_DUST:
1759     case SPELL_SPORULATE:
1760     case SPELL_ROLL:
1761     case SPELL_SUMMON_LIGHTNING_SPIRE:
1762     case SPELL_SUMMON_TZITZIMITL:
1763     case SPELL_SUMMON_HELL_SENTINEL:
1764     case SPELL_GOAD_BEASTS:
1765         pbolt.range = 0;
1766         pbolt.glyph = 0;
1767         return true;
1768     default:
1769     {
1770         const mons_spell_logic* logic = map_find(spell_to_logic, spell_cast);
1771         if (logic && logic->setup_beam == nullptr)
1772         {
1773             pbolt.range = 0;
1774             pbolt.glyph = 0;
1775             return true;
1776         }
1777 
1778         if (check_validity)
1779         {
1780             bolt beam = mons_spell_beam(mons, spell_cast, 1, true);
1781             return beam.flavour != NUM_BEAMS;
1782         }
1783         break;
1784     }
1785     }
1786 
1787     const int power = evoke ? 30 + mons->get_hit_dice()
1788                             : mons_spellpower(*mons, spell_cast);
1789 
1790     bolt theBeam = mons_spell_beam(mons, spell_cast, power);
1791 
1792     bolt_parent_init(theBeam, pbolt);
1793     if (!theBeam.target.origin())
1794         pbolt.target = theBeam.target;
1795     pbolt.source = mons->pos();
1796     pbolt.is_tracer = false;
1797     if (!pbolt.is_enchantment())
1798         pbolt.aux_source = pbolt.name;
1799     else
1800         pbolt.aux_source.clear();
1801 
1802     return true;
1803 }
1804 
1805 /// Can 'binder' bind 'bound's soul with BIND_SOUL?
_mons_can_bind_soul(monster * binder,monster * bound)1806 static bool _mons_can_bind_soul(monster* binder, monster* bound)
1807 {
1808     return bound->holiness() & MH_NATURAL
1809             && mons_can_be_zombified(*bound)
1810             && !bound->has_ench(ENCH_BOUND_SOUL)
1811             && mons_aligned(binder, bound);
1812 }
1813 
1814 // Returns true if the spell is something you wouldn't want done if
1815 // you had a friendly target... only returns a meaningful value for
1816 // non-beam spells.
_ms_direct_nasty(spell_type monspell)1817 static bool _ms_direct_nasty(spell_type monspell)
1818 {
1819     return !(get_spell_flags(monspell) & spflag::utility
1820              || spell_typematch(monspell, spschool::summoning));
1821 }
1822 
1823 // Checks if the foe *appears* to be immune to negative energy. We
1824 // can't just use foe->res_negative_energy(), because that'll mean
1825 // monsters will just "know" whether a player is fully life-protected.
1826 // XX why use this logic for rN, but not rTorment, rElec, etc
_negative_energy_spell_goodness(const actor * foe)1827 static ai_action::goodness _negative_energy_spell_goodness(const actor* foe)
1828 {
1829     ASSERT(foe);
1830     if (foe->is_player())
1831     {
1832         switch (you.undead_state())
1833         {
1834         case US_ALIVE:
1835             // Demonspawn are not demons, and statue form grants only
1836             // partial resistance.
1837             return ai_action::good();
1838         case US_SEMI_UNDEAD:
1839             // Non-bloodless vampires do not appear immune.
1840             return ai_action::good_or_bad(you.vampire_alive);
1841         default:
1842             return ai_action::bad();
1843         }
1844     }
1845 
1846     return ai_action::good_or_bad(!!(foe->holiness() & MH_NATURAL));
1847 }
1848 
_valid_blink_ally(const monster * caster,const monster * target)1849 static bool _valid_blink_ally(const monster* caster, const monster* target)
1850 {
1851     return mons_aligned(caster, target) && caster != target
1852            && !target->no_tele(true, false, true);
1853 }
1854 
_valid_encircle_ally(const monster * caster,const monster * target,const coord_def foepos)1855 static bool _valid_encircle_ally(const monster* caster, const monster* target,
1856                                  const coord_def foepos)
1857 {
1858     return _valid_blink_ally(caster, target)
1859            && target->pos().distance_from(foepos) > 1;
1860 }
1861 
_valid_blink_away_ally(const monster * caster,const monster * target,const coord_def foepos)1862 static bool _valid_blink_away_ally(const monster* caster, const monster* target,
1863                                    const coord_def foepos)
1864 {
1865     return _valid_blink_ally(caster, target)
1866            && target->pos().distance_from(foepos) < 3;
1867 }
1868 
_valid_druids_call_target(const monster * caller,const monster * callee)1869 static bool _valid_druids_call_target(const monster* caller, const monster* callee)
1870 {
1871     return mons_aligned(caller, callee) && mons_is_beast(callee->type)
1872            && callee->get_experience_level() <= 20
1873            && !callee->is_shapeshifter()
1874            && !caller->see_cell(callee->pos())
1875            && mons_habitat(*callee) != HT_WATER
1876            && mons_habitat(*callee) != HT_LAVA
1877            && !callee->is_travelling();
1878 }
1879 
_valid_goad_beasts_target(const monster * goader,const monster * beast)1880 static bool _valid_goad_beasts_target(const monster* goader, const monster* beast)
1881 {
1882     return mons_aligned(goader, beast) && mons_is_beast(beast->type)
1883            && !beast->is_shapeshifter()
1884            && beast->see_cell(goader->pos());
1885 }
1886 
_mirrorable(const monster * agent,const monster * mon)1887 static bool _mirrorable(const monster* agent, const monster* mon)
1888 {
1889     return mon != agent
1890            && mons_aligned(mon, agent)
1891            && !mon->is_stationary()
1892            && !mon->is_summoned()
1893            && !mons_is_conjured(mon->type)
1894            && !mons_is_unique(mon->type);
1895 }
1896 
_valid_aura_of_brilliance_ally(const monster * caster,const monster * target)1897 static bool _valid_aura_of_brilliance_ally(const monster* caster,
1898                                            const monster* target)
1899 {
1900     return mons_aligned(caster, target) && caster != target
1901            && target->is_actual_spellcaster();
1902 }
1903 
1904 
1905 /**
1906  * Print the message that the player sees after a battlecry goes off.
1907  *
1908  * @param chief             The monster letting out the battlecry.
1909  * @param seen_affected     The affected monsters that are visible to the
1910  *                          player.
1911  */
_print_battlecry_announcement(const monster & chief,vector<monster * > & seen_affected)1912 static void _print_battlecry_announcement(const monster& chief,
1913                                           vector<monster*> &seen_affected)
1914 {
1915     // Disabling detailed frenzy announcement because it's so spammy.
1916     const msg_channel_type channel = chief.friendly() ? MSGCH_MONSTER_ENCHANT
1917                                                       : MSGCH_FRIEND_ENCHANT;
1918 
1919     if (seen_affected.size() == 1)
1920     {
1921         mprf(channel, "%s goes into a battle-frenzy!",
1922              seen_affected[0]->name(DESC_THE).c_str());
1923         return;
1924     }
1925 
1926     // refer to the group by the most specific name possible. If they're all
1927     // one monster type; use that name; otherwise, use the genus name (since
1928     // we restrict this by genus).
1929     // Note: If we stop restricting by genus, use "foo's allies" instead.
1930     monster_type first_type = seen_affected[0]->type;
1931     const bool generic = any_of(
1932                                 begin(seen_affected), end(seen_affected),
1933                                 [=](const monster *m)
1934                                 { return m->type != first_type; });
1935     monster_type group_type = generic ? mons_genus(chief.type) : first_type;
1936 
1937     const string ally_desc
1938         = pluralise_monster(mons_type_name(group_type, DESC_PLAIN));
1939     mprf(channel, "%s %s go into a battle-frenzy!",
1940          chief.friendly() ? "Your" : "The", ally_desc.c_str());
1941 }
1942 
1943 /**
1944  * Let loose a mighty battlecry, inspiring & strengthening nearby foes!
1945  *
1946  * @param chief         The monster letting out the battlecry.
1947  * @param check_only    Whether to perform a 'dry run', only checking whether
1948  *                      any monsters are potentially affected.
1949  * @return              Whether any monsters are (or would be) affected.
1950  */
_battle_cry(const monster & chief,bool check_only=false)1951 static bool _battle_cry(const monster& chief, bool check_only = false)
1952 {
1953     const actor *foe = chief.get_foe();
1954 
1955     // Only let loose a battlecry if you have a valid target.
1956     if (!foe
1957         || foe->is_player() && chief.friendly()
1958         || !chief.see_cell_no_trans(foe->pos()))
1959     {
1960         return false;
1961     }
1962 
1963     // Don't try to make noise when silent.
1964     if (chief.is_silenced())
1965         return false;
1966 
1967     int affected = 0;
1968 
1969     vector<monster* > seen_affected;
1970     for (monster_near_iterator mi(chief.pos(), LOS_NO_TRANS); mi; ++mi)
1971     {
1972         const monster *mons = *mi;
1973         // can't buff yourself
1974         if (mons == &chief)
1975             continue;
1976 
1977         // only buff allies
1978         if (!mons_aligned(&chief, mons))
1979             continue;
1980 
1981         // no buffing confused/paralysed mons
1982         if (mons->berserk_or_insane()
1983             || mons->confused()
1984             || mons->cannot_move())
1985         {
1986             continue;
1987         }
1988 
1989         // already buffed
1990         if (mons->has_ench(ENCH_MIGHT))
1991             continue;
1992 
1993         // invalid battlecry target (wrong genus)
1994         if (mons_genus(mons->type) != mons_genus(chief.type))
1995             continue;
1996 
1997         if (check_only)
1998             return true; // just need to check
1999 
2000         const int dur = random_range(12, 20) * speed_to_duration(mi->speed);
2001 
2002         mi->add_ench(mon_enchant(ENCH_MIGHT, 1, &chief, dur));
2003 
2004         affected++;
2005         if (you.can_see(**mi))
2006             seen_affected.push_back(*mi);
2007 
2008         if (mi->asleep())
2009             behaviour_event(*mi, ME_DISTURB, 0, chief.pos());
2010     }
2011 
2012     if (affected == 0)
2013         return false;
2014 
2015     // The yell happens whether you happen to see it or not.
2016     noisy(LOS_DEFAULT_RANGE, chief.pos(), chief.mid);
2017 
2018     if (!seen_affected.empty())
2019         _print_battlecry_announcement(chief, seen_affected);
2020 
2021     return true;
2022 }
2023 
2024 /**
2025  * Call upon the powers of chaos, applying mostly positive effects to nearby
2026  * allies!
2027  *
2028  * @param mons          The monster carrying out the call of chaos.
2029  * @param check_only    Whether to perform a 'dry run', only checking whether
2030  *                      any monsters are potentially affected.
2031  * @return              Whether any monsters are (or would be) affected.
2032  */
_mons_call_of_chaos(const monster & mon,bool check_only=false)2033 static bool _mons_call_of_chaos(const monster& mon, bool check_only = false)
2034 {
2035     const actor *foe = mon.get_foe();
2036 
2037     if (!foe
2038         || foe->is_player() && mon.friendly()
2039         || !mon.see_cell_no_trans(foe->pos()))
2040     {
2041         return false;
2042     }
2043 
2044     int affected = 0;
2045 
2046     vector<monster* > seen_affected;
2047     for (monster_near_iterator mi(mon.pos(), LOS_NO_TRANS); mi; ++mi)
2048     {
2049         const monster *mons = *mi;
2050         // can't buff yourself
2051         if (mons == &mon)
2052             continue;
2053 
2054         // only buff allies
2055         if (!mons_aligned(&mon, mons))
2056             continue;
2057 
2058         if (mons_is_firewood(*mons))
2059             continue;
2060 
2061         if (check_only)
2062             return true; // just need to check
2063 
2064         if (mi->asleep())
2065             behaviour_event(*mi, ME_DISTURB, 0, mon.pos());
2066 
2067         beam_type flavour = random_choose_weighted(150, BEAM_HASTE,
2068                                                    150, BEAM_MIGHT,
2069                                                    150, BEAM_BERSERK,
2070                                                    150, BEAM_AGILITY,
2071                                                    150, BEAM_RESISTANCE,
2072                                                    150, BEAM_BLINK_CLOSE,
2073                                                     15, BEAM_BLINK,
2074                                                     15, BEAM_SLOW,
2075                                                     15, BEAM_VULNERABILITY,
2076                                                     15, BEAM_MALMUTATE,
2077                                                     15, BEAM_POLYMORPH,
2078                                                     15, BEAM_INNER_FLAME);
2079 
2080         enchant_actor_with_flavour(*mi,
2081                                    flavour == BEAM_BLINK_CLOSE
2082                                    ? foe
2083                                    : &mon,
2084                                    flavour);
2085 
2086         affected++;
2087         if (you.can_see(**mi))
2088             seen_affected.push_back(*mi);
2089     }
2090 
2091     if (affected == 0)
2092         return false;
2093 
2094     return true;
2095 }
2096 
_set_door(set<coord_def> door,dungeon_feature_type feat)2097 static void _set_door(set<coord_def> door, dungeon_feature_type feat)
2098 {
2099     for (const auto &dc : door)
2100     {
2101         env.grid(dc) = feat;
2102         set_terrain_changed(dc);
2103     }
2104 }
2105 
_tension_door_closed(set<coord_def> door,dungeon_feature_type old_feat)2106 static int _tension_door_closed(set<coord_def> door,
2107                                 dungeon_feature_type old_feat)
2108 {
2109     // this unwind is a bit heavy, but because out-of-los clouds dissipate
2110     // instantly, they can be wiped out by these door tests.
2111     unwind_var<map<coord_def, cloud_struct>> cloud_state(env.cloud);
2112     _set_door(door, DNGN_CLOSED_DOOR);
2113     const int new_tension = get_tension(GOD_NO_GOD);
2114     _set_door(door, old_feat);
2115     return new_tension;
2116 }
2117 
2118 /**
2119  * Can any actors and items be pushed out of a doorway? An actor can be pushed
2120  * for purposes of this check if there is a habitable target location and the
2121  * actor is either the player or non-hostile. Items can be moved if there is
2122  * any free space.
2123  *
2124  * @param door the door position
2125  *
2126  * @return true if any actors and items can be pushed out of the door.
2127  */
_can_force_door_shut(const coord_def & door)2128 static bool _can_force_door_shut(const coord_def& door)
2129 {
2130     if (!feat_is_open_door(env.grid(door)))
2131         return false;
2132 
2133     set<coord_def> all_door;
2134     find_connected_identical(door, all_door);
2135     auto veto_spots = vector<coord_def>(all_door.begin(), all_door.end());
2136     auto door_spots = veto_spots;
2137 
2138     for (const auto &dc : all_door)
2139     {
2140         // Only attempt to push players and non-hostile monsters out of
2141         // doorways
2142         actor* act = actor_at(dc);
2143         if (act)
2144         {
2145             if (act->is_player()
2146                 || act->is_monster()
2147                     && act->as_monster()->attitude != ATT_HOSTILE)
2148             {
2149                 vector<coord_def> targets = get_push_spaces(dc, true, &veto_spots);
2150                 if (targets.empty())
2151                     return false;
2152                 veto_spots.push_back(targets.front());
2153             }
2154             else
2155                 return false;
2156         }
2157         // If there are items in the way, see if there's room to push them
2158         // out of the way. Having push space for an actor doesn't guarantee
2159         // push space for items (e.g. with a flying actor over lava).
2160         if (env.igrid(dc) != NON_ITEM)
2161         {
2162             if (!has_push_spaces(dc, false, &door_spots))
2163                 return false;
2164         }
2165     }
2166 
2167     // Didn't find any actors or items we couldn't displace
2168     return true;
2169 }
2170 
2171 /**
2172  * Get push spaces for an actor that maximize tension. If there are any push
2173  * spaces at all, this function is guaranteed to return something.
2174  *
2175  * @param pos the position of the actor
2176  * @param excluded a set of pre-excluded spots
2177  *
2178  * @return a vector of coordinates, empty if there are no push spaces at all.
2179  */
_get_push_spaces_max_tension(const coord_def & pos,const vector<coord_def> * excluded)2180 static vector<coord_def> _get_push_spaces_max_tension(const coord_def& pos,
2181                                             const vector<coord_def>* excluded)
2182 {
2183     vector<coord_def> possible_spaces = get_push_spaces(pos, true, excluded);
2184     if (possible_spaces.empty())
2185         return possible_spaces;
2186     vector<coord_def> best;
2187     int max_tension = -1;
2188     actor *act = actor_at(pos);
2189     ASSERT(act);
2190 
2191     for (auto c : possible_spaces)
2192     {
2193         set<coord_def> all_door;
2194         find_connected_identical(pos, all_door);
2195         dungeon_feature_type old_feat = env.grid(pos);
2196 
2197         act->set_position(c);
2198         int new_tension = _tension_door_closed(all_door, old_feat);
2199         act->set_position(pos);
2200 
2201         if (new_tension == max_tension)
2202             best.push_back(c);
2203         else if (new_tension > max_tension)
2204         {
2205             max_tension = new_tension;
2206             best.clear();
2207             best.push_back(c);
2208         }
2209     }
2210     return best;
2211 }
2212 
2213 /**
2214  * Would forcing a door shut (possibly pushing the player) lower tension too
2215  * much?
2216  *
2217  * @param door the door to check
2218  *
2219  * @return true iff forcing the door shut won't lower tension by more than 1/3.
2220  */
_should_force_door_shut(const coord_def & door)2221 static bool _should_force_door_shut(const coord_def& door)
2222 {
2223     if (!feat_is_open_door(env.grid(door)))
2224         return false;
2225 
2226     dungeon_feature_type old_feat = env.grid(door);
2227 
2228     set<coord_def> all_door;
2229     find_connected_identical(door, all_door);
2230     auto veto_spots = vector<coord_def>(all_door.begin(), all_door.end());
2231 
2232     bool player_in_door = false;
2233     for (const auto &dc : all_door)
2234     {
2235         if (you.pos() == dc)
2236         {
2237             player_in_door = true;
2238             break;
2239         }
2240     }
2241 
2242     const int cur_tension = get_tension(GOD_NO_GOD);
2243     coord_def oldpos = you.pos();
2244 
2245     if (player_in_door)
2246     {
2247         coord_def newpos =
2248                 _get_push_spaces_max_tension(you.pos(), &veto_spots).front();
2249         you.set_position(newpos);
2250     }
2251 
2252     const int new_tension = _tension_door_closed(all_door, old_feat);
2253 
2254     if (player_in_door)
2255         you.set_position(oldpos);
2256 
2257     dprf("Considering sealing cur tension: %d, new tension: %d",
2258          cur_tension, new_tension);
2259 
2260     // If closing the door would reduce player tension by too much, probably
2261     // it is scarier for the player to leave it open and thus it should be left
2262     // open
2263     //
2264     // Currently won't allow tension to be lowered by more than 33%.
2265     //
2266     // Also, if there's 0 tension, we require the door closure to create
2267     // tensiion, otherwise we'll probably just lock the player away from the
2268     // warden.
2269     return 1 + cur_tension * 66 <= new_tension * 100;
2270 }
2271 
_seal_doors_and_stairs(const monster * warden,bool check_only=false)2272 static bool _seal_doors_and_stairs(const monster* warden,
2273                                    bool check_only = false)
2274 {
2275     ASSERT(warden);
2276 
2277     int num_closed = 0;
2278     int seal_duration = 80 + random2(80);
2279     bool player_pushed = false;
2280     bool had_effect = false;
2281 
2282     // Friendly wardens are already excluded by _monster_spell_goodness()
2283     if (!warden->can_see(you) || warden->foe != MHITYOU)
2284         return false;
2285 
2286     // Greedy iteration through doors/stairs that you can see.
2287     for (radius_iterator ri(you.pos(), LOS_RADIUS, C_SQUARE);
2288                  ri; ++ri)
2289     {
2290         if (feat_is_open_door(env.grid(*ri)))
2291         {
2292             if (!_can_force_door_shut(*ri))
2293                 continue;
2294 
2295             // If it's scarier to leave this door open, do so
2296             if (!_should_force_door_shut(*ri))
2297                 continue;
2298 
2299             if (check_only)
2300                 return true;
2301 
2302             set<coord_def> all_door;
2303             find_connected_identical(*ri, all_door);
2304             auto veto_spots = vector<coord_def>(all_door.begin(), all_door.end());
2305             auto door_spots = veto_spots;
2306 
2307             for (const auto &dc : all_door)
2308             {
2309                 // If there are things in the way, push them aside
2310                 // This is only reached for the player or non-hostile actors
2311                 actor* act = actor_at(dc);
2312                 if (act)
2313                 {
2314                     vector<coord_def> targets =
2315                                 _get_push_spaces_max_tension(dc, &veto_spots);
2316                     // at this point, _can_force_door_shut should have
2317                     // indicated that the door can be shut.
2318                     ASSERTM(!targets.empty(), "No push space from (%d,%d)",
2319                                                                 dc.x, dc.y);
2320                     coord_def newpos = targets.front();
2321 
2322                     actor_at(dc)->move_to_pos(newpos);
2323                     if (act->is_player())
2324                     {
2325                         stop_delay(true);
2326                         player_pushed = true;
2327                     }
2328                     veto_spots.push_back(newpos);
2329                 }
2330                 push_items_from(dc, &door_spots);
2331             }
2332 
2333             // Close the door
2334             bool seen = false;
2335             vector<coord_def> excludes;
2336             for (const auto &dc : all_door)
2337             {
2338                 dgn_close_door(dc);
2339                 set_terrain_changed(dc);
2340                 dungeon_events.fire_position_event(DET_DOOR_CLOSED, dc);
2341 
2342                 if (is_excluded(dc))
2343                     excludes.push_back(dc);
2344 
2345                 if (you.see_cell(dc))
2346                     seen = true;
2347 
2348                 had_effect = true;
2349             }
2350 
2351             if (seen)
2352             {
2353                 for (const auto &dc : all_door)
2354                 {
2355                     if (env.map_knowledge(dc).seen())
2356                     {
2357                         env.map_knowledge(dc).set_feature(DNGN_CLOSED_DOOR);
2358 #ifdef USE_TILE
2359                         tile_env.bk_bg(dc) = TILE_DNGN_CLOSED_DOOR;
2360 #endif
2361                     }
2362                 }
2363 
2364                 update_exclusion_los(excludes);
2365                 ++num_closed;
2366             }
2367         }
2368 
2369         // Try to seal the door
2370         if (feat_is_closed_door(env.grid(*ri)) && !feat_is_sealed(env.grid(*ri)))
2371         {
2372             if (check_only)
2373                 return true;
2374 
2375             set<coord_def> all_door;
2376             find_connected_identical(*ri, all_door);
2377             const dungeon_feature_type sealed_feat =
2378                 opc_default(*ri) == OPC_CLEAR ? DNGN_SEALED_CLEAR_DOOR
2379                                               : DNGN_SEALED_DOOR;
2380             for (const auto &dc : all_door)
2381             {
2382                 temp_change_terrain(dc, sealed_feat, seal_duration,
2383                                     TERRAIN_CHANGE_DOOR_SEAL, warden);
2384                 had_effect = true;
2385             }
2386         }
2387         else if (feat_is_travelable_stair(env.grid(*ri)))
2388         {
2389             if (check_only)
2390                 return true;
2391 
2392             dungeon_feature_type stype;
2393             if (feat_stair_direction(env.grid(*ri)) == CMD_GO_UPSTAIRS)
2394                 stype = DNGN_SEALED_STAIRS_UP;
2395             else
2396                 stype = DNGN_SEALED_STAIRS_DOWN;
2397 
2398             temp_change_terrain(*ri, stype, seal_duration,
2399                                 TERRAIN_CHANGE_DOOR_SEAL, warden);
2400             had_effect = true;
2401         }
2402     }
2403 
2404     if (had_effect)
2405     {
2406         ASSERT(!check_only);
2407         mprf(MSGCH_MONSTER_SPELL, "%s activates a sealing rune.",
2408                 (warden->visible_to(&you) ? warden->name(DESC_THE, true).c_str()
2409                                           : "Someone"));
2410         if (num_closed > 1)
2411             mpr("The doors slam shut!");
2412         else if (num_closed == 1)
2413             mpr("A door slams shut!");
2414 
2415         if (player_pushed)
2416             mpr("You are pushed out of the doorway!");
2417 
2418         return true;
2419     }
2420 
2421     return false;
2422 }
2423 
2424 /// Can the caster see the given target's cell and a wall next to them?
_near_visible_wall(const monster & caster,const actor & target)2425 static bool _near_visible_wall(const monster &caster, const actor &target)
2426 {
2427     if (!caster.see_cell_no_trans(target.pos()))
2428         return false;
2429     for (adjacent_iterator ai(target.pos()); ai; ++ai)
2430         if (cell_is_solid(*ai) && caster.see_cell_no_trans(*ai))
2431             return true;
2432     return false;
2433 }
2434 
2435 /// Does the given monster have a foe that's 3+ distance away?
_foe_not_nearby(const monster & caster)2436 static ai_action::goodness _foe_not_nearby(const monster &caster)
2437 {
2438     const actor* foe = caster.get_foe();
2439     if (!foe
2440         || grid_distance(caster.pos(), foe->pos()) < 3
2441         || !caster.see_cell_no_trans(foe->pos()))
2442     {
2443         return ai_action::impossible();
2444     }
2445     return ai_action::good();
2446 }
2447 
2448 /// Cast the spell Call Down Lightning, blasting the target with a smitey lightning bolt. (It can miss.)
_cast_call_down_lightning(monster & caster,mon_spell_slot,bolt & beam)2449 static void _cast_call_down_lightning(monster &caster, mon_spell_slot, bolt &beam)
2450 {
2451     actor *foe = caster.get_foe();
2452     if (!foe)
2453         return;
2454     beam.source = foe->pos();
2455     beam.target = foe->pos();
2456     beam.fire();
2457 }
2458 
2459 /// Does the given monster have a foe that's adjacent to a wall, and can the caster see
2460 /// that wall?
_foe_near_wall(const monster & caster)2461 static ai_action::goodness _foe_near_wall(const monster &caster)
2462 {
2463     const actor* foe = caster.get_foe();
2464     if (!foe)
2465         return ai_action::bad();
2466 
2467     if (_near_visible_wall(caster, *foe))
2468         return ai_action::good();
2469     return ai_action::bad();
2470 }
2471 
_setup_creeping_frost(bolt & beam,const monster &,int pow)2472 static void _setup_creeping_frost(bolt &beam, const monster &, int pow)
2473 {
2474     zappy(spell_to_zap(SPELL_CREEPING_FROST), pow, true, beam);
2475     beam.hit = AUTOMATIC_HIT;
2476     beam.name = "frost";
2477 }
2478 
_creeping_frost_freeze(coord_def p,bolt & beam)2479 static bool _creeping_frost_freeze(coord_def p, bolt &beam)
2480 {
2481     beam.hit_verb = "grips"; // We can't do this in _setup_creeping_frost,
2482                              // since hit_verb isn't copied. XXX: think about
2483                              // the consequences of copying it in bolt_parent_init
2484     beam.source = p;
2485     beam.target = p;
2486     beam.aux_source = "creeping frost";
2487     beam.fire();
2488     return beam.explosion_draw_cell(p);
2489 }
2490 
2491 /// Cast the spell Creeping Frost, freezing any of the caster's foes that are adjacent to walls.
_cast_creeping_frost(monster & caster,mon_spell_slot,bolt & beam)2492 static void _cast_creeping_frost(monster &caster, mon_spell_slot, bolt &beam)
2493 {
2494     bool visible_effect = false;
2495     // Freeze the player.
2496     if (!caster.wont_attack() && _near_visible_wall(caster, you))
2497         visible_effect |= _creeping_frost_freeze(you.pos(), beam);
2498 
2499     // Freeze the player's friends.
2500     for (vision_iterator vi(caster); vi; ++vi)
2501     {
2502         actor* target = actor_at(*vi);
2503         if (!target)
2504             continue;
2505 
2506         monster *mon = target->as_monster();
2507         if (!mon || mons_aligned(&caster, mon))
2508             continue;
2509         if (_near_visible_wall(caster, *mon))
2510             visible_effect |= _creeping_frost_freeze(mon->pos(), beam);
2511     }
2512     if (visible_effect)
2513     {
2514         viewwindow(false);
2515         update_screen();
2516         scaled_delay(25);
2517     }
2518 }
2519 
2520 /// Can the caster see the given target's cell and lava next to (or under) them?
_near_visible_lava(const monster & caster,const actor & target)2521 static bool _near_visible_lava(const monster &caster, const actor &target)
2522 {
2523     if (!caster.see_cell_no_trans(target.pos()))
2524         return false;
2525     for (adjacent_iterator ai(target.pos(), false); ai; ++ai)
2526         if (feat_is_lava(env.grid(*ai)) && caster.see_cell_no_trans(*ai))
2527             return true;
2528     return false;
2529 }
2530 
_foe_near_lava(const monster & caster)2531 static ai_action::goodness _foe_near_lava(const monster &caster)
2532 {
2533     const actor* foe = caster.get_foe();
2534     if (!foe)
2535         return ai_action::bad();
2536 
2537     if (_near_visible_lava(caster, *foe))
2538         return ai_action::good();
2539     return ai_action::bad();
2540 }
2541 
_setup_pyroclastic_surge(bolt & beam,const monster &,int pow)2542 static void _setup_pyroclastic_surge(bolt &beam, const monster &, int pow)
2543 {
2544     zappy(spell_to_zap(SPELL_PYROCLASTIC_SURGE), pow, true, beam);
2545     beam.hit = AUTOMATIC_HIT;
2546     beam.name = "flame surge";
2547 }
2548 
_pyroclastic_surge(coord_def p,bolt & beam)2549 static bool _pyroclastic_surge(coord_def p, bolt &beam)
2550 {
2551     beam.source = p;
2552     beam.target = p;
2553     beam.fire();
2554     return beam.explosion_draw_cell(p);
2555 }
2556 
_cast_pyroclastic_surge(monster & caster,mon_spell_slot,bolt & beam)2557 static void _cast_pyroclastic_surge(monster &caster, mon_spell_slot, bolt &beam)
2558 {
2559     bool visible_effect = false;
2560     // Burn the player.
2561     if (!caster.wont_attack() && _near_visible_lava(caster, you))
2562         visible_effect |= _pyroclastic_surge(you.pos(), beam);
2563 
2564     // Burn the player's friends.
2565     for (vision_iterator vi(caster); vi; ++vi)
2566     {
2567         actor* target = actor_at(*vi);
2568         if (!target)
2569             continue;
2570 
2571         monster *mon = target->as_monster();
2572         if (!mon || mons_aligned(&caster, mon))
2573             continue;
2574         if (_near_visible_lava(caster, *mon))
2575             visible_effect |= _pyroclastic_surge(mon->pos(), beam);
2576     }
2577     if (visible_effect)
2578     {
2579         viewwindow(false);
2580         update_screen();
2581         scaled_delay(25);
2582     }
2583 }
2584 
2585 /// Should the given monster cast Still Winds?
_still_winds_goodness(const monster & caster)2586 static ai_action::goodness _still_winds_goodness(const monster &caster)
2587 {
2588     // if it's already running, don't start it again.
2589     if (env.level_state & LSTATE_STILL_WINDS)
2590         return ai_action::impossible();
2591 
2592     // just gonna annoy the player most of the time. don't try to be clever
2593     if (caster.wont_attack())
2594         return ai_action::bad();
2595 
2596     for (radius_iterator ri(caster.pos(), LOS_NO_TRANS); ri; ++ri)
2597     {
2598         const cloud_struct *cloud = cloud_at(*ri);
2599         if (!cloud)
2600             continue;
2601 
2602         // clouds the player might hide in are worrying.
2603         if (grid_distance(*ri, you.pos()) <= 3 // decent margin
2604             && is_opaque_cloud(cloud->type)
2605             && actor_cloud_immune(you, *cloud))
2606         {
2607             return ai_action::good();
2608         }
2609 
2610         // so are hazardous clouds on allies.
2611         const monster* mon = monster_at(*ri);
2612         if (mon && !actor_cloud_immune(*mon, *cloud))
2613             return ai_action::good();
2614     }
2615 
2616     // let's give a pass otherwise.
2617     return ai_action::bad();
2618 }
2619 
2620 /// Cast the spell Still Winds, disabling clouds across the level temporarily.
_cast_still_winds(monster & caster,mon_spell_slot,bolt &)2621 static void _cast_still_winds(monster &caster, mon_spell_slot, bolt&)
2622 {
2623     ASSERT(!(env.level_state & LSTATE_STILL_WINDS));
2624     caster.add_ench(ENCH_STILL_WINDS);
2625 }
2626 
_make_monster_angry(const monster * mon,monster * targ,bool actual)2627 static bool _make_monster_angry(const monster* mon, monster* targ, bool actual)
2628 {
2629     ASSERT(mon); // XXX: change to const monster &mon
2630     ASSERT(targ); // XXX: change to monster &targ
2631     if (mon->friendly() != targ->friendly())
2632         return false;
2633 
2634     // targ is guaranteed to have a foe (needs_berserk checks this).
2635     // Now targ needs to be closer to *its* foe than mon is (otherwise
2636     // mon might be in the way).
2637 
2638     coord_def victim;
2639     if (targ->foe == MHITYOU)
2640         victim = you.pos();
2641     else if (targ->foe != MHITNOT)
2642     {
2643         const monster* vmons = &env.mons[targ->foe];
2644         if (!vmons->alive())
2645             return false;
2646         victim = vmons->pos();
2647     }
2648     else
2649     {
2650         // Should be impossible. needs_berserk should find this case.
2651         die("angered by no foe");
2652     }
2653 
2654     // If mon may be blocking targ from its victim, don't try.
2655     if (victim.distance_from(targ->pos()) > victim.distance_from(mon->pos()))
2656         return false;
2657 
2658     if (!actual)
2659         return true;
2660 
2661     if (you.can_see(*mon))
2662     {
2663         if (mon->type == MONS_QUEEN_BEE && (targ->type == MONS_KILLER_BEE ||
2664                                             targ->type == MONS_MELIAI))
2665         {
2666             mprf("%s calls on %s to defend %s!",
2667                 mon->name(DESC_THE).c_str(),
2668                 targ->name(DESC_THE).c_str(),
2669                 mon->pronoun(PRONOUN_OBJECTIVE).c_str());
2670         }
2671         else
2672             mprf("%s goads %s on!", mon->name(DESC_THE).c_str(),
2673                  targ->name(DESC_THE).c_str());
2674     }
2675 
2676     targ->go_berserk(false);
2677 
2678     return true;
2679 }
2680 
_incite_monsters(const monster * mon,bool actual)2681 static bool _incite_monsters(const monster* mon, bool actual)
2682 {
2683     if (is_sanctuary(you.pos()) || is_sanctuary(mon->pos()))
2684         return false;
2685 
2686     // Only things both in LOS of the inciter and within radius 3.
2687     const int radius = 3;
2688     int goaded = 0;
2689     for (monster_near_iterator mi(mon->pos(), LOS_NO_TRANS); mi; ++mi)
2690     {
2691         // XXX: Ugly hack to skip the spellcaster rules for meliai.
2692         if (*mi == mon || !mi->needs_berserk(mon->type != MONS_QUEEN_BEE))
2693             continue;
2694 
2695         if (is_sanctuary(mi->pos()))
2696             continue;
2697 
2698         // Cannot goad other moths of wrath!
2699         if (mon->type == MONS_MOTH_OF_WRATH
2700             && mi->type == MONS_MOTH_OF_WRATH
2701         // Queen bees can only incite bees.
2702             || mon->type == MONS_QUEEN_BEE
2703                && mi->type != MONS_KILLER_BEE &&
2704                   mi->type != MONS_MELIAI)
2705         {
2706             continue;
2707         }
2708 
2709         if (grid_distance(mon->pos(), mi->pos()) > radius)
2710             continue;
2711 
2712         const bool worked = _make_monster_angry(mon, *mi, actual);
2713         if (worked && (!actual || !one_chance_in(3 * ++goaded)))
2714             return true;
2715     }
2716 
2717     return goaded > 0;
2718 }
2719 
2720 // Spells for a quick get-away.
2721 // Currently only used to get out of a net.
_ms_quick_get_away(spell_type monspell)2722 static bool _ms_quick_get_away(spell_type monspell)
2723 {
2724     switch (monspell)
2725     {
2726     case SPELL_TELEPORT_SELF:
2727     case SPELL_BLINK:
2728         return true;
2729     default:
2730         return false;
2731     }
2732 }
2733 
2734 // Is it worth bothering to invoke recall? (Currently defined by there being at
2735 // least 3 things we could actually recall, and then with a probability inversely
2736 // proportional to how many HD of allies are current nearby)
_should_recall(monster * caller)2737 static bool _should_recall(monster* caller)
2738 {
2739     ASSERT(caller); // XXX: change to monster &caller
2740     // It's a long recitation - if we're winded, we can't use it.
2741     if (caller->has_ench(ENCH_BREATH_WEAPON))
2742         return false;
2743 
2744     int num = 0;
2745     for (monster_iterator mi; mi; ++mi)
2746     {
2747         if (mons_is_recallable(caller, **mi)
2748             && !caller->see_cell_no_trans((*mi)->pos()))
2749         {
2750             ++num;
2751         }
2752     }
2753 
2754     // Since there are reinforcements we could recall, do we think we need them?
2755     if (num > 2)
2756     {
2757         int ally_hd = 0;
2758         for (monster_near_iterator mi(caller->pos(), LOS_NO_TRANS); mi; ++mi)
2759         {
2760             if (*mi != caller && caller->can_see(**mi)
2761                 && mons_aligned(caller, *mi)
2762                 && !mons_is_firewood(**mi))
2763             {
2764                 ally_hd += mi->get_experience_level();
2765             }
2766         }
2767         return 25 + roll_dice(2, 22) > ally_hd;
2768     }
2769     else
2770         return false;
2771 }
2772 
2773 /**
2774  * Recall a bunch of monsters!
2775  *
2776  * @param mons[in] the monster doing the recall
2777  * @param recall_target the max number of monsters to recall.
2778  * @returns whether anything was recalled.
2779  */
mons_word_of_recall(monster * mons,int recall_target)2780 bool mons_word_of_recall(monster* mons, int recall_target)
2781 {
2782     unsigned short num_recalled = 0;
2783     vector<monster* > mon_list;
2784 
2785     // Build the list of recallable monsters and randomize
2786     for (monster_iterator mi; mi; ++mi)
2787     {
2788         // Don't recall ourselves
2789         if (*mi == mons)
2790             continue;
2791 
2792         if (!mons_is_recallable(mons, **mi))
2793             continue;
2794 
2795         // Don't recall things that are already close to us
2796         if ((mons && mons->see_cell_no_trans((*mi)->pos()))
2797             || (!mons && you.see_cell_no_trans((*mi)->pos())))
2798         {
2799             continue;
2800         }
2801 
2802         mon_list.push_back(*mi);
2803     }
2804     shuffle_array(mon_list);
2805 
2806     const coord_def target   = (mons) ? mons->pos() : you.pos();
2807     const unsigned short foe = (mons) ? mons->foe   : short{MHITYOU};
2808 
2809     // Now actually recall things
2810     for (monster *mon : mon_list)
2811     {
2812         coord_def empty;
2813         if (find_habitable_spot_near(target, mons_base_type(*mon),
2814                                      3, false, empty)
2815             && mon->move_to_pos(empty))
2816         {
2817             mon->behaviour = BEH_SEEK;
2818             mon->foe = foe;
2819             ++num_recalled;
2820             simple_monster_message(*mon, " is recalled.");
2821         }
2822         // Can only recall a couple things at once
2823         if (num_recalled == recall_target)
2824             break;
2825     }
2826     return num_recalled;
2827 }
2828 
_valid_vine_spot(coord_def p)2829 static bool _valid_vine_spot(coord_def p)
2830 {
2831     if (actor_at(p) || !monster_habitable_grid(MONS_PLANT, env.grid(p)))
2832         return false;
2833 
2834     int num_trees = 0;
2835     bool valid_trees = false;
2836     for (adjacent_iterator ai(p); ai; ++ai)
2837     {
2838         if (feat_is_tree(env.grid(*ai)))
2839         {
2840             // Make sure this spot is not on a diagonal to its only adjacent
2841             // tree (so that the vines can pull back against the tree properly)
2842             if (num_trees || !((*ai-p).sgn().x != 0 && (*ai-p).sgn().y != 0))
2843             {
2844                 valid_trees = true;
2845                 break;
2846             }
2847             else
2848                 ++num_trees;
2849         }
2850     }
2851 
2852     if (!valid_trees)
2853         return false;
2854 
2855     // Now the connectivity check
2856     return !plant_forbidden_at(p, true);
2857 }
2858 
_awaken_vines(monster * mon,bool test_only=false)2859 static bool _awaken_vines(monster* mon, bool test_only = false)
2860 {
2861     if (_is_wiz_cast())
2862     {
2863         mprf("Sorry, this spell isn't supported for dummies!"); //mons dummy
2864         return false;
2865     }
2866 
2867     vector<coord_def> spots;
2868     for (radius_iterator ri(mon->pos(), LOS_NO_TRANS); ri; ++ri)
2869     {
2870         if (_valid_vine_spot(*ri))
2871             spots.push_back(*ri);
2872     }
2873 
2874     shuffle_array(spots);
2875 
2876     actor* foe = mon->get_foe();
2877     ASSERT(foe);
2878 
2879     int num_vines = 1 + random2(3);
2880     if (mon->props.exists("vines_awakened"))
2881         num_vines = min(num_vines, 3 - mon->props["vines_awakened"].get_int());
2882     bool seen = false;
2883 
2884     for (coord_def spot : spots)
2885     {
2886         // Don't place vines where they can't see our target
2887         if (!cell_see_cell(spot, foe->pos(), LOS_NO_TRANS))
2888             continue;
2889 
2890         // Don't place a vine too near to another existing one
2891         bool too_close = false;
2892         for (distance_iterator di(spot, false, true, 3); di; ++di)
2893         {
2894             monster* m = monster_at(*di);
2895             if (m && m->type == MONS_SNAPLASHER_VINE)
2896             {
2897                 too_close = true;
2898                 break;
2899             }
2900         }
2901         if (too_close)
2902             continue;
2903 
2904         // We've found at least one valid spot, so the spell should be castable
2905         if (test_only)
2906             return true;
2907 
2908         // Actually place the vine and update properties
2909         if (monster* vine = create_monster(
2910             mgen_data(MONS_SNAPLASHER_VINE, SAME_ATTITUDE(mon), spot, mon->foe,
2911                         MG_FORCE_PLACE)
2912             .set_summoned(mon, 0, SPELL_AWAKEN_VINES, mon->god)))
2913         {
2914             vine->props["vine_awakener"].get_int() = mon->mid;
2915             mon->props["vines_awakened"].get_int()++;
2916             mon->add_ench(mon_enchant(ENCH_AWAKEN_VINES, 1, nullptr, 200));
2917             --num_vines;
2918             if (you.can_see(*vine))
2919                 seen = true;
2920         }
2921 
2922         // We've finished placing all our vines
2923         if (num_vines == 0)
2924             break;
2925     }
2926 
2927     if (test_only)
2928         return false;
2929     else
2930     {
2931         if (seen)
2932             mpr("Vines fly forth from the trees!");
2933         return true;
2934     }
2935 }
2936 
_place_druids_call_beast(const monster * druid,monster * beast,const actor * target)2937 static bool _place_druids_call_beast(const monster* druid, monster* beast,
2938                                      const actor* target)
2939 {
2940     for (int t = 0; t < 20; ++t)
2941     {
2942         // Attempt to find some random spot out of the target's los to place
2943         // the beast (but not too far away).
2944         coord_def area_rnd;
2945         area_rnd.x = random_range(-11, 11);
2946         area_rnd.y = random_range(-11, 11);
2947         coord_def area = clamp_in_bounds(target->pos() + area_rnd);
2948         if (cell_see_cell(target->pos(), area, LOS_DEFAULT))
2949             continue;
2950 
2951         coord_def base_spot;
2952         int tries = 0;
2953         while (tries < 10 && base_spot.origin())
2954         {
2955             find_habitable_spot_near(area, mons_base_type(*beast), 3, false, base_spot);
2956             if (cell_see_cell(target->pos(), base_spot, LOS_DEFAULT))
2957                 base_spot.reset();
2958             ++tries;
2959         }
2960 
2961         if (base_spot.origin())
2962             continue;
2963 
2964         beast->move_to_pos(base_spot);
2965 
2966         // Wake the beast up and calculate a path to the druid's target.
2967         // (Note that both BEH_WANDER and MTRAV_PATROL are necessary for it
2968         // to follow the given path and also not randomly wander off instead)
2969         beast->behaviour = BEH_WANDER;
2970         beast->foe = druid->foe;
2971 
2972         monster_pathfind mp;
2973         if (mp.init_pathfind(beast, target->pos()))
2974         {
2975             beast->travel_path = mp.calc_waypoints();
2976             if (!beast->travel_path.empty())
2977             {
2978                 beast->target = beast->travel_path[0];
2979                 beast->travel_target = MTRAV_PATROL;
2980             }
2981         }
2982 
2983         // Assign blame (for statistical purposes, mostly)
2984         mons_add_blame(beast, "called by " + druid->name(DESC_A, true));
2985 
2986         return true;
2987     }
2988 
2989     return false;
2990 }
2991 
_cast_druids_call(const monster * mon)2992 static void _cast_druids_call(const monster* mon)
2993 {
2994     vector<monster*> mon_list;
2995     for (monster_iterator mi; mi; ++mi)
2996     {
2997         if (_valid_druids_call_target(mon, *mi))
2998             mon_list.push_back(*mi);
2999     }
3000 
3001     shuffle_array(mon_list);
3002 
3003     const actor* target = mon->get_foe();
3004     const int num = min((int)mon_list.size(),
3005                         mon->get_experience_level() > 10 ? random_range(2, 3)
3006                                                       : random_range(1, 2));
3007 
3008     for (int i = 0; i < num; ++i)
3009         _place_druids_call_beast(mon, mon_list[i], target);
3010 }
3011 
_cast_goad_beasts(const monster * mon)3012 static void _cast_goad_beasts(const monster* mon)
3013 {
3014     // Gain moves from the goad.
3015     for (monster_near_iterator mi(mon, LOS_NO_TRANS); mi; ++mi)
3016         if (_valid_goad_beasts_target(mon, *mi))
3017             mi->gain_energy(EUT_MOVE);
3018 }
3019 
_angle_between(coord_def origin,coord_def p1,coord_def p2)3020 static double _angle_between(coord_def origin, coord_def p1, coord_def p2)
3021 {
3022     double ang0 = atan2(p1.x - origin.x, p1.y - origin.y);
3023     double ang  = atan2(p2.x - origin.x, p2.y - origin.y);
3024     return min(fabs(ang - ang0), fabs(ang - ang0 + 2 * PI));
3025 }
3026 
3027 // Does there already appear to be a bramble wall in this direction?
3028 // We approximate this by seeing if there are at least two briar patches in
3029 // a ray between us and our target, which turns out to be a pretty decent
3030 // metric in practice.
_already_bramble_wall(const monster * mons,coord_def targ)3031 static bool _already_bramble_wall(const monster* mons, coord_def targ)
3032 {
3033     bolt tracer;
3034     tracer.source    = mons->pos();
3035     tracer.target    = targ;
3036     tracer.range     = 12;
3037     tracer.is_tracer = true;
3038     tracer.pierce    = true;
3039     tracer.fire();
3040 
3041     int briar_count = 0;
3042     bool targ_reached = false;
3043     for (coord_def p : tracer.path_taken)
3044     {
3045         if (!targ_reached && p == targ)
3046             targ_reached = true;
3047         else if (!targ_reached)
3048             continue;
3049 
3050         if (monster_at(p) && monster_at(p)->type == MONS_BRIAR_PATCH)
3051             ++briar_count;
3052     }
3053 
3054     return briar_count > 1;
3055 }
3056 
_wall_of_brambles(monster * mons)3057 static bool _wall_of_brambles(monster* mons)
3058 {
3059     mgen_data briar_mg = mgen_data(MONS_BRIAR_PATCH, SAME_ATTITUDE(mons),
3060                                    coord_def(-1, -1), MHITNOT, MG_FORCE_PLACE);
3061     briar_mg.set_summoned(mons, 0, 0);
3062 
3063     // We want to raise a defensive wall if we think our foe is moving to attack
3064     // us, and otherwise raise a wall further away to block off their escape.
3065     // (Each wall type uses different parameters)
3066     bool defensive = mons->props["foe_approaching"].get_bool();
3067 
3068     coord_def aim_pos = you.pos();
3069     coord_def targ_pos = mons->pos();
3070 
3071     // A defensive wall cannot provide any cover if our target is already
3072     // adjacent, so don't bother creating one.
3073     if (defensive && mons->pos().distance_from(aim_pos) == 1)
3074         return false;
3075 
3076     // Don't raise a non-defensive wall if it looks like there's an existing one
3077     // in the same direction already (this looks rather silly to see walls
3078     // springing up in the distance behind already-closed paths, and probably
3079     // is more likely to aid the player than the monster)
3080     if (!defensive)
3081     {
3082         if (_already_bramble_wall(mons, aim_pos))
3083             return false;
3084     }
3085 
3086     // Select a random radius for the circle used draw an arc from (affects
3087     // both shape and distance of the resulting wall)
3088     int rad = (defensive ? random_range(3, 5)
3089                          : min(11, mons->pos().distance_from(you.pos()) + 6));
3090 
3091     // Adjust the center of the circle used to draw the arc of the wall if
3092     // we're raising one defensively, based on both its radius and foe distance.
3093     // (The idea is the ensure that our foe will end up on the other side of it
3094     // without always raising the wall in exactly the same shape and position)
3095     if (defensive)
3096     {
3097         coord_def adjust = (targ_pos - aim_pos).sgn();
3098 
3099         targ_pos += adjust;
3100         if (rad == 5)
3101             targ_pos += adjust;
3102         if (mons->pos().distance_from(aim_pos) == 2)
3103             targ_pos += adjust;
3104     }
3105 
3106     // XXX: There is almost certainly a better way to calculate the points
3107     //      along the desired arcs, though this code produces the proper look.
3108     vector<coord_def> points;
3109     for (distance_iterator di(targ_pos, false, false, rad); di; ++di)
3110     {
3111         if (di.radius() == rad || di.radius() == rad - 1)
3112         {
3113             if (!actor_at(*di) && !cell_is_solid(*di))
3114             {
3115                 if (defensive && _angle_between(targ_pos, aim_pos, *di) <= PI/4.0
3116                     || (!defensive
3117                         && _angle_between(targ_pos, aim_pos, *di) <= PI/(4.2 + rad/6.0)))
3118                 {
3119                     points.push_back(*di);
3120                 }
3121             }
3122         }
3123     }
3124 
3125     bool seen = false;
3126     for (coord_def point : points)
3127     {
3128         briar_mg.pos = point;
3129         monster* briar = create_monster(briar_mg, false);
3130         if (briar)
3131         {
3132             briar->add_ench(mon_enchant(ENCH_SHORT_LIVED, 1, nullptr, 80 + random2(100)));
3133             if (you.can_see(*briar))
3134                 seen = true;
3135         }
3136     }
3137 
3138     if (seen)
3139         mpr("Thorny briars emerge from the ground!");
3140 
3141     return true;
3142 }
3143 
3144 /**
3145  * Make the given monster cast the spell "Corrupting Pulse", corrupting
3146  * (temporarily malmutating) all creatures in LOS.
3147  *
3148  * @param mons  The monster in question.
3149  */
_corrupting_pulse(monster * mons)3150 static void _corrupting_pulse(monster *mons)
3151 {
3152     if (cell_see_cell(you.pos(), mons->pos(), LOS_DEFAULT))
3153     {
3154         targeter_radius hitfunc(mons, LOS_SOLID);
3155         flash_view_delay(UA_MONSTER, MAGENTA, 300, &hitfunc);
3156 
3157         if (!is_sanctuary(you.pos())
3158             && cell_see_cell(you.pos(), mons->pos(), LOS_SOLID))
3159         {
3160             int num_mutations = one_chance_in(4) ? 2 : 1;
3161             for (int i = 0; i < num_mutations; ++i)
3162                 temp_mutate(RANDOM_CORRUPT_MUTATION, "wretched star");
3163         }
3164     }
3165 
3166     for (radius_iterator ri(mons->pos(), LOS_RADIUS, C_SQUARE); ri; ++ri)
3167     {
3168         monster *m = monster_at(*ri);
3169         if (m && cell_see_cell(mons->pos(), *ri, LOS_SOLID_SEE)
3170             && !mons_aligned(mons, m))
3171         {
3172             m->corrupt();
3173         }
3174     }
3175 }
3176 
3177 // Returns the clone just created (null otherwise)
cast_phantom_mirror(monster * mons,monster * targ,int hp_perc,int summ_type)3178 monster* cast_phantom_mirror(monster* mons, monster* targ, int hp_perc, int summ_type)
3179 {
3180     // Create clone.
3181     monster *mirror = clone_mons(targ, true);
3182 
3183     // Abort if we failed to place the monster for some reason.
3184     if (!mirror)
3185         return nullptr;
3186 
3187     // Unentangle the real monster.
3188     if (mons->is_constricted())
3189         mons->stop_being_constricted();
3190 
3191     mons_clear_trapping_net(mons);
3192 
3193     // Don't leak the real one with the targeting interface.
3194     if (you.prev_targ == mons->mindex())
3195     {
3196         you.prev_targ = MHITNOT;
3197         crawl_state.cancel_cmd_repeat();
3198     }
3199     mons->reset_client_id();
3200 
3201     mirror->mark_summoned(5, true, summ_type);
3202     mirror->add_ench(ENCH_PHANTOM_MIRROR);
3203     mirror->summoner = mons->mid;
3204     mirror->hit_points = max(mirror->hit_points * hp_perc / 100, 1);
3205     mirror->max_hit_points = max(mirror->max_hit_points * hp_perc / 100, 1);
3206 
3207     // Sometimes swap the two monsters, so as to disguise the original and the
3208     // copy.
3209     if (coinflip())
3210         targ->swap_with(mirror);
3211 
3212     return mirror;
3213 }
3214 
_trace_los(monster * agent,bool (* vulnerable)(const actor *))3215 static bool _trace_los(monster* agent, bool (*vulnerable)(const actor*))
3216 {
3217     bolt tracer;
3218     tracer.foe_ratio = 0;
3219     for (actor_near_iterator ai(agent, LOS_NO_TRANS); ai; ++ai)
3220     {
3221         if (agent == *ai || !vulnerable(*ai))
3222             continue;
3223 
3224         if (mons_aligned(agent, *ai))
3225         {
3226             tracer.friend_info.count++;
3227             tracer.friend_info.power +=
3228                     ai->is_player() ? you.experience_level
3229                                     : ai->as_monster()->get_experience_level();
3230         }
3231         else
3232         {
3233             tracer.foe_info.count++;
3234             tracer.foe_info.power +=
3235                     ai->is_player() ? you.experience_level
3236                                     : ai->as_monster()->get_experience_level();
3237         }
3238     }
3239     return mons_should_fire(tracer);
3240 }
3241 
_vortex_vulnerable(const actor * victim)3242 static bool _vortex_vulnerable(const actor* victim)
3243 {
3244     if (!victim)
3245         return false;
3246     return !victim->res_polar_vortex();
3247 }
3248 
_torment_vulnerable(const actor * victim)3249 static bool _torment_vulnerable(const actor* victim)
3250 {
3251     if (!victim)
3252         return false;
3253     return !victim->res_torment();
3254 }
3255 
_mutation_vulnerable(const actor * victim)3256 static bool _mutation_vulnerable(const actor* victim)
3257 {
3258     if (!victim)
3259         return false;
3260     return victim->can_mutate();
3261 }
3262 
_cast_black_mark(monster * agent)3263 static void _cast_black_mark(monster* agent)
3264 {
3265     for (actor_near_iterator ai(agent, LOS_NO_TRANS); ai; ++ai)
3266     {
3267         if (ai->is_player() || !mons_aligned(*ai, agent))
3268             continue;
3269         monster* mon = ai->as_monster();
3270 
3271         if (!mon->has_ench(ENCH_BLACK_MARK)
3272             && mons_has_attacks(*mon))
3273         {
3274             mon->add_ench(ENCH_BLACK_MARK);
3275             simple_monster_message(*mon, " begins absorbing vital energies!");
3276         }
3277     }
3278 }
3279 
aura_of_brilliance(monster * agent)3280 void aura_of_brilliance(monster* agent)
3281 {
3282     bool did_something = false;
3283     for (actor_near_iterator ai(agent, LOS_NO_TRANS); ai; ++ai)
3284     {
3285         if (ai->is_player() || !mons_aligned(*ai, agent))
3286             continue;
3287         monster* mon = ai->as_monster();
3288         if (_valid_aura_of_brilliance_ally(agent, mon))
3289         {
3290             if (!mon->has_ench(ENCH_EMPOWERED_SPELLS) && you.can_see(*mon))
3291             {
3292                mprf("%s is empowered by %s aura!",
3293                     mon->name(DESC_THE).c_str(),
3294                     apostrophise(agent->name(DESC_THE)).c_str());
3295             }
3296 
3297             mon_enchant ench = mon->get_ench(ENCH_EMPOWERED_SPELLS);
3298             if (ench.ench != ENCH_NONE)
3299                 mon->update_ench(ench);
3300             else
3301                 mon->add_ench(mon_enchant(ENCH_EMPOWERED_SPELLS, 1, agent));
3302 
3303             did_something = true;
3304         }
3305     }
3306 
3307     if (!did_something)
3308         agent->del_ench(ENCH_BRILLIANCE_AURA);
3309 }
3310 
_glaciate_tracer(monster * caster,int pow,coord_def aim)3311 static bool _glaciate_tracer(monster *caster, int pow, coord_def aim)
3312 {
3313     targeter_cone hitfunc(caster, spell_range(SPELL_GLACIATE, pow));
3314     hitfunc.set_aim(aim);
3315 
3316     mon_attitude_type castatt = caster->temp_attitude();
3317     int friendly = 0, enemy = 0;
3318 
3319     for (const auto &entry : hitfunc.zapped)
3320     {
3321         if (entry.second <= 0)
3322             continue;
3323 
3324         const actor *victim = actor_at(entry.first);
3325         if (!victim)
3326             continue;
3327 
3328         if (mons_atts_aligned(castatt, victim->temp_attitude()))
3329         {
3330             if (victim->is_player() && !(caster->holiness() & MH_DEMONIC))
3331                 return false; // never glaciate the player! except demons
3332             friendly += victim->get_experience_level();
3333         }
3334         else
3335             enemy += victim->get_experience_level();
3336     }
3337 
3338     return enemy > friendly;
3339 }
3340 
3341 /**
3342  * Is this a feature that we can Awaken?
3343  *
3344  * @param   feat The feature type.
3345  * @returns If the feature is a valid feature that we can Awaken Earth on.
3346  */
_feat_is_awakenable(dungeon_feature_type feat)3347 static bool _feat_is_awakenable(dungeon_feature_type feat)
3348 {
3349     return feat == DNGN_ROCK_WALL || feat == DNGN_CLEAR_ROCK_WALL;
3350 }
3351 
3352 /**
3353  * Pick a target for Awaken Earth.
3354  *
3355  *  @param  mon       The monster casting
3356  *  @return The target square - out of bounds if no target was found.
3357  */
_mons_awaken_earth_target(const monster & mon)3358 static coord_def _mons_awaken_earth_target(const monster &mon)
3359 {
3360     coord_def pos = mon.target;
3361 
3362     // First up, see if we can see our target, and if they're in a good spot
3363     // to pick on them. If so, do that.
3364     if (in_bounds(pos) && mon.see_cell(pos)
3365         && count_neighbours_with_func(pos, &_feat_is_awakenable) > 0)
3366     {
3367         return pos;
3368     }
3369 
3370     // Either we can't see our target, or they're not adjacent to walls.
3371     // Step back towards the caster from the target, and see if we can find
3372     // a better wall for this.
3373     const coord_def start_pos = mon.pos();
3374 
3375     ray_def ray;
3376     fallback_ray(pos, start_pos, ray); // straight line from them to mon
3377 
3378     unordered_set<coord_def> candidates;
3379 
3380     // Candidates: everything on or adjacent to a straight line to the target.
3381     // Strongly prefer cells where we can get lots of elementals.
3382     while (in_bounds(pos) && pos != start_pos)
3383     {
3384         for (adjacent_iterator ai(pos, false); ai; ++ai)
3385             if (mon.see_cell(pos))
3386                 candidates.insert(*ai);
3387 
3388         ray.advance();
3389         pos = ray.pos();
3390     }
3391 
3392     vector<coord_weight> targets;
3393     for (coord_def candidate : candidates)
3394     {
3395         int neighbours = count_neighbours_with_func(candidate,
3396                                                     &_feat_is_awakenable);
3397 
3398         // We can target solid cells, which themselves will awaken, so count
3399         // those as well.
3400         if (_feat_is_awakenable(env.grid(candidate)))
3401             neighbours++;
3402 
3403         if (neighbours > 0)
3404             targets.emplace_back(candidate, neighbours * neighbours);
3405     }
3406 
3407     coord_def* choice = random_choose_weighted(targets);
3408     return choice ? *choice : coord_def(GXM+1, GYM+1);
3409 }
3410 
3411 /**
3412  * Get the fraction of damage done by the given beam that's to enemies,
3413  * multiplied by the given scale.
3414  */
_get_dam_fraction(const bolt & tracer,int scale)3415 static int _get_dam_fraction(const bolt &tracer, int scale)
3416 {
3417     if (!tracer.foe_info.power)
3418         return 0;
3419     return tracer.foe_info.power * scale
3420             / (tracer.foe_info.power + tracer.friend_info.power);
3421 }
3422 
3423 /**
3424  * Pick a target for Ghostly Sacrifice.
3425  *
3426  *  @param  caster       The monster casting the spell.
3427  *                      TODO: constify (requires mon_spell_beam param const
3428  *  @return The target square, or an out of bounds coord if none was found.
3429  */
_mons_ghostly_sacrifice_target(const monster & caster,bolt tracer)3430 static coord_def _mons_ghostly_sacrifice_target(const monster &caster,
3431                                                 bolt tracer)
3432 {
3433     const int dam_scale = 1000;
3434     int best_dam_fraction = dam_scale / 2;
3435     coord_def best_target = coord_def(GXM+1, GYM+1); // initially out of bounds
3436     tracer.ex_size = 1;
3437 
3438     for (monster_near_iterator mi(&caster, LOS_NO_TRANS); mi; ++mi)
3439     {
3440         if (*mi == &caster)
3441             continue; // don't blow yourself up!
3442 
3443         if (!mons_aligned(&caster, *mi))
3444             continue; // can only blow up allies ;)
3445 
3446         tracer.target = mi->pos();
3447         fire_tracer(&caster, tracer, true, true);
3448         if (mons_is_threatening(**mi)) // only care about sacrificing real mons
3449             tracer.friend_info.power += mi->get_experience_level() * 2;
3450 
3451         const int dam_fraction = _get_dam_fraction(tracer, dam_scale);
3452         dprf("if sacrificing %s (at %d,%d): ratio %d/%d",
3453              mi->name(DESC_A, true).c_str(),
3454              best_target.x, best_target.y, dam_fraction, dam_scale);
3455         if (dam_fraction > best_dam_fraction)
3456         {
3457             best_target = mi->pos();
3458             best_dam_fraction = dam_fraction;
3459             dprf("setting best target");
3460         }
3461     }
3462 
3463     return best_target;
3464 }
3465 
3466 /// Everything short of the actual explosion. Returns whether to explode.
_prepare_ghostly_sacrifice(monster & caster,bolt & beam)3467 static bool _prepare_ghostly_sacrifice(monster &caster, bolt &beam)
3468 {
3469     if (!in_bounds(beam.target))
3470         return false; // assert?
3471 
3472     monster* victim = monster_at(beam.target);
3473     if (!victim)
3474         return false; // assert?
3475 
3476     if (you.see_cell(victim->pos()))
3477     {
3478         mprf("%s animating energy erupts into ghostly fire!",
3479              apostrophise(victim->name(DESC_THE)).c_str());
3480     }
3481     monster_die(*victim, &caster, true);
3482     return true;
3483 }
3484 
3485 /// Setup a negative energy explosion.
_setup_ghostly_beam(bolt & beam,int power,int dice)3486 static void _setup_ghostly_beam(bolt &beam, int power, int dice)
3487 {
3488     beam.colour   = CYAN;
3489     beam.name     = "ghostly fireball";
3490     beam.damage   = dice_def(dice, 6 + power / 13);
3491     beam.hit      = 40;
3492     beam.flavour  = BEAM_NEG;
3493     beam.is_explosion = true;
3494 }
3495 
3496 /// Setup and target a ghostly sacrifice explosion.
_setup_ghostly_sacrifice_beam(bolt & beam,const monster & caster,int power)3497 static void _setup_ghostly_sacrifice_beam(bolt& beam, const monster& caster,
3498                                           int power)
3499 {
3500     _setup_ghostly_beam(beam, power, 5);
3501     // Future-proofing: your shadow keeps your targetting.
3502     if (mons_is_player_shadow(caster))
3503         return;
3504 
3505     beam.target = _mons_ghostly_sacrifice_target(caster, beam);
3506     beam.aimed_at_spot = true;  // to get noise to work properly
3507 }
3508 
_setup_hex_check(spell_type spell)3509 static function<ai_action::goodness(const monster&)> _setup_hex_check(spell_type spell)
3510 {
3511     return [spell](const monster& caster) {
3512         return _hexing_goodness(caster, spell);
3513     };
3514 }
3515 
3516 /**
3517  * Does the given monster think it's worth casting the given hex at its current
3518  * target?
3519  *
3520  * XXX: very strongly consider removing this logic!
3521  *
3522  * @param caster    The monster casting the hex.
3523  * @param spell     The spell to cast; e.g. SPELL_DIMENSIONAL_ANCHOR.
3524  * @return          Whether the monster thinks it's worth trying to beat the
3525  *                  defender's willpower.
3526  */
_hexing_goodness(const monster & caster,spell_type spell)3527 static ai_action::goodness _hexing_goodness(const monster &caster, spell_type spell)
3528 {
3529     const actor* foe = caster.get_foe();
3530     ASSERT(foe);
3531 
3532     // Occasionally we don't estimate... just fire and see.
3533     if (one_chance_in(5))
3534         return ai_action::good();
3535 
3536     // Only intelligent monsters estimate.
3537     if (mons_intel(caster) < I_HUMAN)
3538         return ai_action::good();
3539 
3540     // Simulate Strip Willpower's 1/3 chance of ignoring WL
3541     if (spell == SPELL_STRIP_WILLPOWER && one_chance_in(3))
3542         return ai_action::good();
3543 
3544     // We'll estimate the target's resistance to magic, by first getting
3545     // the actual value and then randomising it.
3546     const int est_magic_resist = foe->willpower() + random2(60) - 30; // +-30
3547     const int power = ench_power_stepdown(mons_spellpower(caster, spell));
3548 
3549     // Determine the amount of chance allowed by the benefit from
3550     // the spell. The estimated difficulty is the probability
3551     // of rolling over 100 + diff on 2d100. -- bwr
3552     int diff = (spell == SPELL_PAIN
3553                 || spell == SPELL_SLOW
3554                 || spell == SPELL_CONFUSE) ? 0 : 50;
3555 
3556     return ai_action::good_or_bad(est_magic_resist - power <= diff);
3557 }
3558 
3559 /** Chooses a matching spell from this spell list, based on frequency.
3560  *
3561  *  @param[in]  spells     the monster spell list to search
3562  *  @param[in]  flag       what spflag the spell should match
3563  *  @return The spell chosen, or a slot containing SPELL_NO_SPELL and
3564  *          MON_SPELL_NO_FLAGS if no spell was chosen.
3565  */
_pick_spell_from_list(const monster_spells & spells,spflag flag)3566 static mon_spell_slot _pick_spell_from_list(const monster_spells &spells,
3567                                             spflag flag)
3568 {
3569     spell_type spell_cast = SPELL_NO_SPELL;
3570     mon_spell_slot_flags slot_flags = MON_SPELL_NO_FLAGS;
3571     int weight = 0;
3572     for (const mon_spell_slot &slot : spells)
3573     {
3574         spell_flags flags = get_spell_flags(slot.spell);
3575         if (!(flags & flag))
3576             continue;
3577 
3578         weight += slot.freq;
3579         if (x_chance_in_y(slot.freq, weight))
3580         {
3581             spell_cast = slot.spell;
3582             slot_flags = slot.flags;
3583         }
3584     }
3585 
3586     return { spell_cast, 0, slot_flags };
3587 }
3588 
3589 /**
3590  * Are we a short distance from our target?
3591  *
3592  * @param  mons The monster checking distance from its target.
3593  * @return true if we have a target and are within LOS_DEFAULT_RANGE / 2 of that
3594  *         target, or false otherwise.
3595  */
_short_target_range(const monster * mons)3596 static bool _short_target_range(const monster *mons)
3597 {
3598     return mons->get_foe()
3599            && mons->pos().distance_from(mons->get_foe()->pos())
3600               < LOS_DEFAULT_RANGE / 2;
3601 }
3602 
3603 /**
3604  * Are we a long distance from our target?
3605  *
3606  * @param  mons The monster checking distance from its target.
3607  * @return true if we have a target and are outside LOS_DEFAULT_RANGE / 2 of
3608  *          that target, or false otherwise.
3609  */
_long_target_range(const monster * mons)3610 static bool _long_target_range(const monster *mons)
3611 {
3612     return mons->get_foe()
3613            && mons->pos().distance_from(mons->get_foe()->pos())
3614               > LOS_DEFAULT_RANGE / 2;
3615 }
3616 
3617 /// Does the given monster think it's in an emergency situation?
_mons_in_emergency(const monster & mons)3618 static bool _mons_in_emergency(const monster &mons)
3619 {
3620     return mons.hit_points < mons.max_hit_points / 3;
3621 }
3622 
3623 /**
3624  * Choose a spell for the given monster to consider casting.
3625  *
3626  * @param mons              The monster considering casting a spell/
3627  * @param hspell_pass       The set of spells to choose from.
3628  * @param prefer_selfench   Whether to prefer self-enchantment spells, which
3629  *                          are more likely to be castable.
3630  * @return                  A spell to cast, or { SPELL_NO_SPELL }.
3631  */
_find_spell_prospect(const monster & mons,const monster_spells & hspell_pass,bool prefer_selfench)3632 static mon_spell_slot _find_spell_prospect(const monster &mons,
3633                                            const monster_spells &hspell_pass,
3634                                            bool prefer_selfench)
3635 {
3636 
3637     // Setup spell.
3638     // If we didn't find a spell on the first pass, try a
3639     // self-enchantment.
3640     if (prefer_selfench)
3641         return _pick_spell_from_list(hspell_pass, spflag::selfench);
3642 
3643     // Monsters that are fleeing or pacified and leaving the
3644     // level will always try to choose an escape spell.
3645     if (mons_is_fleeing(mons) || mons.pacified())
3646         return _pick_spell_from_list(hspell_pass, spflag::escape);
3647 
3648     unsigned what = random2(200);
3649     unsigned int i = 0;
3650     for (; i < hspell_pass.size(); i++)
3651     {
3652         if ((hspell_pass[i].flags & MON_SPELL_EMERGENCY
3653              && !_mons_in_emergency(mons))
3654             || (hspell_pass[i].flags & MON_SPELL_SHORT_RANGE
3655                 && !_short_target_range(&mons))
3656             || (hspell_pass[i].flags & MON_SPELL_LONG_RANGE
3657                 && !_long_target_range(&mons)))
3658         {
3659             continue;
3660         }
3661 
3662         if (hspell_pass[i].freq >= what)
3663             break;
3664         what -= hspell_pass[i].freq;
3665     }
3666 
3667     // If we roll above the weight of the spell list,
3668     // don't cast a spell at all.
3669     if (i == hspell_pass.size())
3670         return { SPELL_NO_SPELL, 0, MON_SPELL_NO_FLAGS };
3671 
3672     return hspell_pass[i];
3673 }
3674 
3675 /**
3676  * Would it be a good idea for the given monster to cast the given spell?
3677  *
3678  * @param mons      The monster casting the spell.
3679  * @param spell     The spell in question; e.g. SPELL_FIREBALL.
3680  * @param beem      A beam with the spell loaded into it; used as a tracer.
3681  * @param ignore_good_idea      Whether to be almost completely indiscriminate
3682  *                              with beam spells. XXX: refactor this out?
3683  */
_should_cast_spell(const monster & mons,spell_type spell,bolt & beem,bool ignore_good_idea)3684 static bool _should_cast_spell(const monster &mons, spell_type spell,
3685                                bolt &beem, bool ignore_good_idea)
3686 {
3687     // beam-type spells requiring tracers
3688     if (get_spell_flags(spell) & spflag::needs_tracer)
3689     {
3690         const bool explode = spell_is_direct_explosion(spell);
3691         fire_tracer(&mons, beem, explode);
3692         // Good idea?
3693         return mons_should_fire(beem, ignore_good_idea);
3694     }
3695 
3696     // All direct-effect/summoning/self-enchantments/etc.
3697     const actor *foe = mons.get_foe();
3698     if (_ms_direct_nasty(spell)
3699         && mons_aligned(&mons, (mons.foe == MHITYOU) ?
3700                         &you : foe)) // foe=get_foe() is nullptr for friendlies
3701     {                                // targeting you, which is bad here.
3702         return false;
3703     }
3704 
3705     // Don't use blinking spells in sight of a trap the player can see if we're
3706     // allied with the player; this might do more harm than good to the player
3707     // restrict to the ones the player can see to avoid an information leak
3708     if (mons_aligned(&mons, &you)
3709         && (spell == SPELL_BLINK || spell == SPELL_BLINK_OTHER
3710             || spell == SPELL_BLINK_OTHER_CLOSE || spell == SPELL_BLINK_CLOSE
3711             || spell == SPELL_BLINK_RANGE || spell == SPELL_BLINK_AWAY
3712             || spell == SPELL_BLINK_ALLIES_ENCIRCLE || spell == SPELL_BLINKBOLT
3713             || spell == SPELL_BLINK_ALLIES_AWAY))
3714     {
3715         for (auto ri = radius_iterator(mons.pos(), LOS_NO_TRANS); ri; ++ri)
3716             if (feat_is_trap(env.grid(*ri)) && you.see_cell(*ri))
3717                 return false;
3718     }
3719 
3720 
3721     if (mons.foe == MHITYOU || mons.foe == MHITNOT)
3722     {
3723         // XXX: Note the crude hack so that monsters can
3724         // use ME_ALERT to target (we should really have
3725         // a measure of time instead of peeking to see
3726         // if the player is still there). -- bwr
3727         return you.visible_to(&mons)
3728                || mons.target == you.pos() && coinflip();
3729     }
3730 
3731     ASSERT(foe);
3732     if (!mons.can_see(*foe))
3733         return false;
3734 
3735     return true;
3736 }
3737 
3738 /// How does Ru describe stopping the given monster casting a spell?
_ru_spell_stop_desc(monster & mons)3739 static string _ru_spell_stop_desc(monster &mons)
3740 {
3741     if (mons.is_actual_spellcaster())
3742         return "cast a spell";
3743     if (mons.is_priest())
3744         return "pray";
3745     return "attack";
3746 }
3747 
3748 /// What spells can the given monster currently use?
_find_usable_spells(monster & mons)3749 static monster_spells _find_usable_spells(monster &mons)
3750 {
3751     // TODO: make mons param const (requires waste_of_time param to be const)
3752 
3753     monster_spells hspell_pass(mons.spells);
3754 
3755     if (mons.is_silenced() || mons.is_shapeshifter())
3756     {
3757         erase_if(hspell_pass, [](const mon_spell_slot &t) {
3758             return t.flags & MON_SPELL_SILENCE_MASK;
3759         });
3760     }
3761 
3762     // Remove currently useless spells.
3763     erase_if(hspell_pass, [&](const mon_spell_slot &t) {
3764         return !ai_action::is_viable(_monster_spell_goodness(&mons, t))
3765         // Should monster not have selected dig by now,
3766         // it never will.
3767         || t.spell == SPELL_DIG;
3768     });
3769 
3770     return hspell_pass;
3771 }
3772 
3773 /**
3774  * For the given spell and monster, try to find a target for the spell, and
3775  * and then see if it's a good idea to actually cast the spell at that target.
3776  * Return whether we succeeded in both.
3777  *
3778  * @param mons            The monster casting the spell. XXX: should be const
3779  * @param beem[in,out]    A targeting beam. Has a very few params already set.
3780  *                        (from setup_targetting_beam())
3781  * @param spell           The spell to be targetted and cast.
3782  * @param ignore_good_idea  Whether to ignore most targeting constraints (ru)
3783  */
_target_and_justify_spell(monster & mons,bolt & beem,spell_type spell,bool ignore_good_idea)3784 static bool _target_and_justify_spell(monster &mons,
3785                                       bolt &beem,
3786                                       spell_type spell,
3787                                       bool ignore_good_idea)
3788 {
3789     // Setup the spell.
3790     setup_mons_cast(&mons, beem, spell);
3791 
3792     switch (spell)
3793     {
3794         case SPELL_CHARMING:
3795             // Try to find an ally of the player to hex if we are
3796             // hexing the player.
3797             if (mons.foe == MHITYOU && !_set_hex_target(&mons, beem))
3798                 return false;
3799             break;
3800         default:
3801             break;
3802     }
3803 
3804     // special beam targeting sets the beam's target to an out-of-bounds coord
3805     // if no valid target was found.
3806     const mons_spell_logic* logic = map_find(spell_to_logic, spell);
3807     if (logic && logic->setup_beam && !in_bounds(beem.target))
3808         return false;
3809 
3810     // Don't knockback something we're trying to constrict.
3811     const actor *victim = actor_at(beem.target);
3812     if (victim &&
3813         beem.can_knockback(*victim)
3814         && mons.is_constricting()
3815         && mons.constricting->count(victim->mid))
3816     {
3817         return false;
3818     }
3819 
3820     return _should_cast_spell(mons, spell, beem, ignore_good_idea);
3821 }
3822 
3823 /**
3824  * Let a monster choose a spell to cast; may be SPELL_NO_SPELL.
3825  *
3826  * @param mons          The monster doing the casting, potentially.
3827  *                      TODO: should be const (requires _ms_low_hitpoint_cast
3828                         param to be const)
3829  * @param orig_beem[in,out]     A beam. Has a very few params already set.
3830  *                              (from setup_targetting_beam())
3831  *                              TODO: split out targeting into another func
3832  * @param hspell_pass   A list of valid spells to consider casting.
3833  * @param ignore_good_idea      Whether to be almost completely indiscriminate
3834  *                              with beam spells. XXX: refactor this out?
3835  * @return              A spell to cast, or SPELL_NO_SPELL.
3836  */
_choose_spell_to_cast(monster & mons,bolt & beem,const monster_spells & hspell_pass,bool ignore_good_idea)3837 static mon_spell_slot _choose_spell_to_cast(monster &mons,
3838                                             bolt &beem,
3839                                             const monster_spells &hspell_pass,
3840                                             bool ignore_good_idea)
3841 {
3842     // Monsters caught in a net try to get away.
3843     // This is only urgent if enemies are around.
3844     // TODO this seems kind of pointless with a 1/15 chance?
3845     if (mon_enemies_around(&mons) && mons.caught() && one_chance_in(15))
3846         for (const mon_spell_slot &slot : hspell_pass)
3847             if (_ms_quick_get_away(slot.spell))
3848                 return slot;
3849 
3850     bolt orig_beem = beem;
3851 
3852     // Promote the casting of useful spells for low-HP monsters.
3853     // (kraken should always cast their escape spell of inky).
3854     if (_mons_in_emergency(mons)
3855         && one_chance_in(mons.type == MONS_KRAKEN ? 4 : 8))
3856     {
3857         // Note: There should always be at least some chance we don't
3858         // get here... even if the monster is on its last HP. That
3859         // way we don't have to worry about monsters infinitely casting
3860         // Healing on themselves (e.g. orc high priests).
3861         int found_spell = 0;
3862         mon_spell_slot chosen_slot = { SPELL_NO_SPELL, 0, MON_SPELL_NO_FLAGS };
3863         for (const mon_spell_slot &slot : hspell_pass)
3864         {
3865             bolt targ_beam = orig_beem;
3866             if (_target_and_justify_spell(mons, targ_beam, slot.spell,
3867                                           ignore_good_idea)
3868                 && one_chance_in(++found_spell))
3869             {
3870                 chosen_slot = slot;
3871                 beem = targ_beam;
3872             }
3873         }
3874 
3875         if (chosen_slot.spell != SPELL_NO_SPELL)
3876             return chosen_slot;
3877     }
3878 
3879     // If nothing found by now, safe friendlies and good
3880     // neutrals will rarely cast.
3881     if (mons.wont_attack() && !mon_enemies_around(&mons) && !one_chance_in(10))
3882         return { SPELL_NO_SPELL, 0, MON_SPELL_NO_FLAGS };
3883 
3884     bool reroll = mons.has_ench(ENCH_EMPOWERED_SPELLS);
3885     for (int attempt = 0; attempt < 2; attempt++)
3886     {
3887         const bool prefer_selfench = attempt > 0 && coinflip();
3888         mon_spell_slot chosen_slot
3889             = _find_spell_prospect(mons, hspell_pass, prefer_selfench);
3890 
3891         // aura of brilliance gives monsters a bonus cast chance.
3892         if (chosen_slot.spell == SPELL_NO_SPELL && reroll)
3893         {
3894             chosen_slot = _find_spell_prospect(mons, hspell_pass,
3895                                                prefer_selfench);
3896             reroll = false;
3897         }
3898 
3899         // if we didn't roll a spell, don't make another attempt; bail.
3900         // (only give multiple attempts for targetting issues.)
3901         if (chosen_slot.spell == SPELL_NO_SPELL)
3902             return chosen_slot;
3903 
3904         // reset the beam
3905         beem = orig_beem;
3906 
3907         if (_target_and_justify_spell(mons, beem, chosen_slot.spell,
3908                                        ignore_good_idea))
3909         {
3910             ASSERT(chosen_slot.spell != SPELL_NO_SPELL);
3911             return chosen_slot;
3912         }
3913     }
3914 
3915     return { SPELL_NO_SPELL, 0, MON_SPELL_NO_FLAGS };
3916 }
3917 
3918 /**
3919  * Give a monster a chance to cast a spell.
3920  *
3921  * @param mons the monster that might cast.
3922  * @param return whether a spell was cast.
3923  */
handle_mon_spell(monster * mons)3924 bool handle_mon_spell(monster* mons)
3925 {
3926     ASSERT(mons);
3927 
3928     if (is_sanctuary(mons->pos()) && !mons->wont_attack())
3929         return false;
3930 
3931     // Yes, there is a logic to this ordering {dlb}:
3932     // .. berserk check is necessary for out-of-sequence actions like emergency
3933     // slot spells {blue}
3934     if (mons->asleep()
3935         || mons->submerged()
3936         || mons->berserk_or_insane()
3937         || mons_is_confused(*mons, false)
3938         || !mons->has_spells())
3939     {
3940         return false;
3941     }
3942 
3943     const monster_spells hspell_pass = _find_usable_spells(*mons);
3944 
3945     // If no useful spells... cast no spell.
3946     if (!hspell_pass.size())
3947         return false;
3948 
3949     bolt beem = setup_targetting_beam(*mons);
3950 
3951     bool ignore_good_idea = false;
3952     if (does_ru_wanna_redirect(mons))
3953     {
3954         ru_interference interference = get_ru_attack_interference_level();
3955         if (interference == DO_BLOCK_ATTACK)
3956         {
3957             const string message
3958                 = make_stringf(" begins to %s, but is stunned by your conviction!",
3959                                _ru_spell_stop_desc(*mons).c_str());
3960             simple_monster_message(*mons, message.c_str(), MSGCH_GOD);
3961             mons->lose_energy(EUT_SPELL);
3962             return true;
3963         }
3964         if (interference == DO_REDIRECT_ATTACK)
3965         {
3966             int pfound = 0;
3967             for (radius_iterator ri(you.pos(),
3968                                     LOS_DEFAULT); ri; ++ri)
3969             {
3970                 monster* new_target = monster_at(*ri);
3971 
3972                 if (new_target == nullptr
3973                     || mons_is_projectile(new_target->type)
3974                     || mons_is_firewood(*new_target)
3975                     || new_target->friendly())
3976                 {
3977                     continue;
3978                 }
3979 
3980                 ASSERT(new_target);
3981 
3982                 if (one_chance_in(++pfound))
3983                 {
3984                     mons->target = new_target->pos();
3985                     mons->foe = new_target->mindex();
3986                     beem.target = mons->target;
3987                     ignore_good_idea = true;
3988                 }
3989             }
3990 
3991             if (ignore_good_idea)
3992             {
3993                 mprf(MSGCH_GOD, "You redirect %s's attack!",
3994                      mons->name(DESC_THE).c_str());
3995             }
3996         }
3997     }
3998 
3999     const mon_spell_slot spell_slot
4000         = _choose_spell_to_cast(*mons, beem, hspell_pass, ignore_good_idea);
4001     const spell_type spell_cast = spell_slot.spell;
4002     const mon_spell_slot_flags flags = spell_slot.flags;
4003 
4004     // Should the monster *still* not have a spell, well, too bad {dlb}:
4005     if (spell_cast == SPELL_NO_SPELL)
4006         return false;
4007 
4008     // Check for antimagic if casting a spell spell.
4009     if (mons->has_ench(ENCH_ANTIMAGIC) && flags & MON_SPELL_ANTIMAGIC_MASK
4010         && !x_chance_in_y(4 * BASELINE_DELAY,
4011                           4 * BASELINE_DELAY
4012                           + mons->get_ench(ENCH_ANTIMAGIC).duration))
4013     {
4014         // This may be a bad idea -- if we decide monsters shouldn't
4015         // lose a turn like players do not, please make this just return.
4016         simple_monster_message(*mons, " falters for a moment.");
4017         mons->lose_energy(EUT_SPELL);
4018         return true;
4019     }
4020 
4021     // Dragons now have a time-out on their breath weapons, draconians too!
4022     if (flags & MON_SPELL_BREATH)
4023         setup_breath_timeout(mons);
4024 
4025     // FINALLY! determine primary spell effects {dlb}:
4026     if (spell_cast == SPELL_BLINK)
4027     {
4028         // Why only cast blink if nearby? {dlb}
4029         if (mons->can_see(you))
4030         {
4031             mons_cast_noise(mons, beem, spell_cast, flags);
4032             monster_blink(mons);
4033         }
4034         else
4035             return false;
4036     }
4037     else if (spell_cast == SPELL_BLINK_RANGE)
4038         blink_range(mons);
4039     else if (spell_cast == SPELL_BLINK_AWAY)
4040         blink_away(mons, true);
4041     else if (spell_cast == SPELL_BLINK_CLOSE)
4042         blink_close(mons);
4043     else
4044     {
4045         const bool battlesphere = mons->props.exists("battlesphere");
4046         if (!(get_spell_flags(spell_cast) & spflag::utility))
4047             make_mons_stop_fleeing(mons);
4048 
4049         if (battlesphere)
4050             aim_battlesphere(mons, spell_cast);
4051         mons_cast(mons, beem, spell_cast, flags);
4052         if (battlesphere)
4053             trigger_battlesphere(mons);
4054         if (flags & MON_SPELL_WIZARD && mons->has_ench(ENCH_SAP_MAGIC))
4055         {
4056             mons->add_ench(mon_enchant(ENCH_ANTIMAGIC, 0,
4057                                        mons->get_ench(ENCH_SAP_MAGIC).agent(),
4058                                        6 * BASELINE_DELAY));
4059         }
4060     }
4061 
4062     // Reflection, fireballs, etc.
4063     if (!mons->alive())
4064         return true;
4065 
4066     if (!(flags & MON_SPELL_INSTANT))
4067     {
4068         mons->lose_energy(EUT_SPELL);
4069         return true;
4070     }
4071 
4072     return false; // to let them do something else
4073 }
4074 
_monster_abjure_target(monster * target,int pow,bool actual)4075 static int _monster_abjure_target(monster* target, int pow, bool actual)
4076 {
4077     int duration;
4078 
4079     if (!target->is_summoned(&duration))
4080         return 0;
4081 
4082     pow = max(20, fuzz_value(pow, 40, 25));
4083 
4084     if (!actual)
4085         return pow > 40 || pow >= duration;
4086 
4087     // TSO and Trog's abjuration protection.
4088     bool shielded = false;
4089     if (have_passive(passive_t::abjuration_protection_hd))
4090     {
4091         pow = pow * (30 - target->get_hit_dice()) / 30;
4092         if (pow < duration)
4093         {
4094             simple_god_message(" protects your fellow warrior from evil "
4095                                "magic!");
4096             shielded = true;
4097         }
4098     }
4099     else if (have_passive(passive_t::abjuration_protection))
4100     {
4101         pow = pow / 2;
4102         if (pow < duration)
4103         {
4104             simple_god_message(" shields your ally from puny magic!");
4105             shielded = true;
4106         }
4107     }
4108     else if (is_sanctuary(target->pos()))
4109     {
4110         pow = 0;
4111         mprf(MSGCH_GOD, "Zin's power protects your fellow warrior from evil magic!");
4112         shielded = true;
4113     }
4114 
4115     dprf("Abj: dur: %d, pow: %d, ndur: %d", duration, pow, duration - pow);
4116 
4117     mon_enchant abj = target->get_ench(ENCH_ABJ);
4118     if (!target->lose_ench_duration(abj, pow))
4119     {
4120         if (!shielded)
4121             simple_monster_message(*target, " shudders.");
4122         return 1;
4123     }
4124 
4125     return 0;
4126 }
4127 
_monster_abjuration(const monster & caster,bool actual)4128 static int _monster_abjuration(const monster& caster, bool actual)
4129 {
4130     int maffected = 0;
4131 
4132     if (actual)
4133         mpr("Send 'em back where they came from!");
4134 
4135     const int pow = mons_spellpower(caster, SPELL_ABJURATION);
4136 
4137     for (monster_near_iterator mi(caster.pos(), LOS_NO_TRANS); mi; ++mi)
4138     {
4139         if (!mons_aligned(&caster, *mi))
4140             maffected += _monster_abjure_target(*mi, pow, actual);
4141     }
4142 
4143     return maffected;
4144 }
4145 
_mons_will_abjure(const monster & mons)4146 static ai_action::goodness _mons_will_abjure(const monster& mons)
4147 {
4148     return ai_action::good_or_bad(_monster_abjuration(mons, false) > 0);
4149 }
4150 
_haunt_fixup(monster * summon,coord_def pos)4151 static void _haunt_fixup(monster* summon, coord_def pos)
4152 {
4153     actor* victim = actor_at(pos);
4154     if (victim && victim != summon)
4155     {
4156         summon->add_ench(mon_enchant(ENCH_HAUNTING, 1, victim,
4157                                      INFINITE_DURATION));
4158         summon->foe = victim->mindex();
4159     }
4160 }
4161 
_pick_horrible_thing()4162 static monster_type _pick_horrible_thing()
4163 {
4164     return one_chance_in(4) ? MONS_TENTACLED_MONSTROSITY
4165                             : MONS_ABOMINATION_LARGE;
4166 }
4167 
_pick_undead_summon()4168 static monster_type _pick_undead_summon()
4169 {
4170     static monster_type undead[] =
4171     {
4172         MONS_NECROPHAGE, MONS_JIANGSHI, MONS_FLAYED_GHOST, MONS_ZOMBIE,
4173         MONS_SKELETON, MONS_SIMULACRUM, MONS_SPECTRAL_THING, MONS_FLYING_SKULL,
4174         MONS_MUMMY, MONS_VAMPIRE, MONS_WIGHT, MONS_WRAITH, MONS_SHADOW_WRAITH,
4175         MONS_FREEZING_WRAITH, MONS_PHANTASMAL_WARRIOR, MONS_SHADOW
4176     };
4177 
4178     return RANDOM_ELEMENT(undead);
4179 }
4180 
_pick_vermin()4181 static monster_type _pick_vermin()
4182 {
4183     return random_choose_weighted(8, MONS_HELL_RAT,
4184                                   5, MONS_REDBACK,
4185                                   2, MONS_TARANTELLA,
4186                                   2, MONS_JUMPING_SPIDER,
4187                                   3, MONS_DEMONIC_CRAWLER);
4188 }
4189 
_pick_drake()4190 static monster_type _pick_drake()
4191 {
4192     return random_choose_weighted(5, MONS_SWAMP_DRAKE,
4193                                   5, MONS_KOMODO_DRAGON,
4194                                   5, MONS_WIND_DRAKE,
4195                                   6, MONS_RIME_DRAKE,
4196                                   6, MONS_DEATH_DRAKE,
4197                                   3, MONS_LINDWURM);
4198 }
4199 
_do_high_level_summon(monster * mons,spell_type spell_cast,monster_type (* mpicker)(),int nsummons,god_type god,const coord_def * target=nullptr,void (* post_hook)(monster *,coord_def)=nullptr)4200 static void _do_high_level_summon(monster* mons, spell_type spell_cast,
4201                                   monster_type (*mpicker)(), int nsummons,
4202                                   god_type god, const coord_def *target = nullptr,
4203                                   void (*post_hook)(monster*, coord_def)
4204                                       = nullptr)
4205 {
4206     const int duration = min(2 + mons->spell_hd(spell_cast) / 5, 6);
4207 
4208     for (int i = 0; i < nsummons; ++i)
4209     {
4210         monster_type which_mons = mpicker();
4211 
4212         if (which_mons == MONS_NO_MONSTER)
4213             continue;
4214 
4215         monster* summon = create_monster(
4216             mgen_data(which_mons, SAME_ATTITUDE(mons),
4217                       target ? *target : mons->pos(), mons->foe)
4218             .set_summoned(mons, duration, spell_cast, god));
4219         if (summon && post_hook)
4220             post_hook(summon, target ? *target : mons->pos());
4221     }
4222 }
4223 
4224 
_mons_summon_elemental(monster & mons,mon_spell_slot slot,bolt &)4225 static void _mons_summon_elemental(monster &mons, mon_spell_slot slot, bolt&)
4226 {
4227     static const map<spell_type, monster_type> elemental_types = {
4228         { SPELL_WATER_ELEMENTALS, MONS_WATER_ELEMENTAL },
4229         { SPELL_FIRE_ELEMENTALS, MONS_FIRE_ELEMENTAL },
4230         { SPELL_EARTH_ELEMENTALS, MONS_EARTH_ELEMENTAL },
4231         { SPELL_AIR_ELEMENTALS, MONS_AIR_ELEMENTAL },
4232     };
4233 
4234     const monster_type* mtyp = map_find(elemental_types, slot.spell);
4235     ASSERT(mtyp);
4236 
4237     const int spell_hd = mons.spell_hd(slot.spell);
4238     const int count = 1 + (spell_hd > 15) + random2(spell_hd / 7 + 1);
4239 
4240     for (int i = 0; i < count; i++)
4241         _summon(mons, *mtyp, 3, slot);
4242 }
4243 
_mons_cast_haunt(monster * mons)4244 static void _mons_cast_haunt(monster* mons)
4245 {
4246     ASSERT(mons->get_foe());
4247     const coord_def fpos = mons->get_foe()->pos();
4248 
4249     _do_high_level_summon(mons, SPELL_HAUNT, pick_random_wraith,
4250                           random_range(2, 3), GOD_NO_GOD, &fpos, _haunt_fixup);
4251 }
4252 
_mons_cast_summon_illusion(monster * mons,spell_type spell)4253 static void _mons_cast_summon_illusion(monster* mons, spell_type spell)
4254 {
4255     actor *foe = mons->get_foe();
4256     if (!foe || !actor_is_illusion_cloneable(foe))
4257         return;
4258 
4259     mons_summon_illusion_from(mons, foe, spell);
4260 }
4261 
_mons_cast_spectral_orcs(monster * mons)4262 static void _mons_cast_spectral_orcs(monster* mons)
4263 {
4264     ASSERT(mons->get_foe());
4265     const coord_def fpos = mons->get_foe()->pos();
4266 
4267     const int abj = 3;
4268 
4269     for (int i = random2(3) + 1; i > 0; --i)
4270     {
4271         monster_type mon = MONS_ORC;
4272         if (coinflip())
4273             mon = MONS_ORC_WARRIOR;
4274         else if (one_chance_in(3))
4275             mon = MONS_ORC_KNIGHT;
4276         else if (one_chance_in(10))
4277             mon = MONS_ORC_WARLORD;
4278 
4279         // Use the original monster type as the zombified type here, to
4280         // get the proper stats from it.
4281         if (monster *orc = create_monster(
4282                 mgen_data(MONS_SPECTRAL_THING, SAME_ATTITUDE(mons), fpos,
4283                           mons->foe)
4284                 .set_summoned(mons, abj, SPELL_SUMMON_SPECTRAL_ORCS, mons->god)
4285                 .set_base(mon)))
4286         {
4287             // set which base type this orc is pretending to be for gear
4288             // purposes
4289             if (mon != MONS_ORC)
4290             {
4291                 orc->mname = mons_type_name(mon, DESC_PLAIN);
4292                 orc->flags |= MF_NAME_REPLACE | MF_NAME_DESCRIPTOR;
4293             }
4294 
4295             // give gear using the base type
4296             const int lvl = env.absdepth0;
4297             give_specific_item(orc, make_mons_weapon(orc->base_monster, lvl));
4298             give_specific_item(orc, make_mons_armour(orc->base_monster, lvl));
4299             // XXX: and a shield, for warlords...? (wasn't included before)
4300 
4301             // set gear as summoned
4302             orc->mark_summoned(abj, true, SPELL_SUMMON_SPECTRAL_ORCS);
4303         }
4304     }
4305 }
4306 
_mons_cast_freeze(monster * mons)4307 static bool _mons_cast_freeze(monster* mons)
4308 {
4309     actor *target = mons->get_foe();
4310     if (!target)
4311         return false;
4312     if (grid_distance(mons->pos(), target->pos()) > 1)
4313         return false;
4314 
4315     const int pow = mons_spellpower(*mons, SPELL_FREEZE);
4316 
4317     const int base_damage = freeze_damage(pow).roll();
4318     const int damage = resist_adjust_damage(target, BEAM_COLD, base_damage);
4319 
4320     if (you.can_see(*target))
4321     {
4322         mprf("%s %s frozen%s", target->name(DESC_THE).c_str(),
4323                               target->conj_verb("are").c_str(),
4324                               attack_strength_punctuation(damage).c_str());
4325     }
4326 
4327     // Resist messaging, needs to happen after so we get the correct message
4328     // order; resist_adjust_damage is used to compute the punctuation.
4329     if (target->is_player())
4330         check_your_resists(base_damage, BEAM_COLD, "");
4331     else
4332     {
4333         bolt beam;
4334         beam.flavour = BEAM_COLD;
4335         mons_adjust_flavoured(target->as_monster(), beam, base_damage);
4336     }
4337 
4338     target->hurt(mons, damage, BEAM_COLD, KILLED_BY_FREEZING);
4339 
4340     if (target->alive())
4341         target->expose_to_element(BEAM_COLD, damage);
4342 
4343     return true;
4344 }
4345 
setup_breath_timeout(monster * mons)4346 void setup_breath_timeout(monster* mons)
4347 {
4348     if (mons->has_ench(ENCH_BREATH_WEAPON))
4349         return;
4350 
4351     const int timeout = roll_dice(1, 5);
4352 
4353     dprf("breath timeout: %d", timeout);
4354 
4355     mon_enchant breath_timeout = mon_enchant(ENCH_BREATH_WEAPON, 1, mons,
4356                                              timeout * BASELINE_DELAY);
4357     mons->add_ench(breath_timeout);
4358 }
4359 
4360 /**
4361  * Maybe mesmerise the player.
4362  *
4363  * This function decides whether or not it is possible for the player to become
4364  * mesmerised by mons. It will return a variety of values depending on whether
4365  * or not this can succeed or has succeeded; finally, it will add mons to the
4366  * player's list of beholders.
4367  *
4368  * @param mons      The monster doing the mesmerisation.
4369  * @param actual    Whether or not we are actually casting the spell. If false,
4370  *                  no messages are emitted.
4371  * @return          0 if the player could be mesmerised but wasn't, 1 if the
4372  *                  player was mesmerised, -1 if the player couldn't be
4373  *                  mesmerised.
4374 **/
_mons_mesmerise(monster * mons,bool actual)4375 static int _mons_mesmerise(monster* mons, bool actual)
4376 {
4377     ASSERT(mons); // XXX: change to monster &mons
4378     bool already_mesmerised = you.beheld_by(*mons);
4379 
4380     if (!you.visible_to(mons)             // Don't mesmerise while invisible.
4381         || (!you.can_see(*mons)           // Or if we are, and you're aren't
4382             && !already_mesmerised)       // already mesmerised by us.
4383         || !player_can_hear(mons->pos())  // Or if you're silenced, or we are.
4384         || you.berserk()                  // Or if you're berserk.
4385         || mons->has_ench(ENCH_CONFUSION) // Or we're confused,
4386         || mons_is_fleeing(*mons)          // fleeing,
4387         || mons->pacified()               // pacified,
4388         || mons->friendly())              // or friendly!
4389     {
4390         return -1;
4391     }
4392 
4393     if (actual)
4394     {
4395         if (!already_mesmerised)
4396         {
4397             simple_monster_message(*mons, " attempts to bespell you!");
4398             flash_view(UA_MONSTER, LIGHTMAGENTA);
4399         }
4400         else
4401         {
4402             mprf("%s draws you further into %s thrall.",
4403                     mons->name(DESC_THE).c_str(),
4404                     mons->pronoun(PRONOUN_POSSESSIVE).c_str());
4405         }
4406     }
4407 
4408     const int pow = _ench_power(SPELL_MESMERISE, *mons);
4409     const int will_check = you.check_willpower(pow);
4410 
4411     // Don't mesmerise if you pass an WL check or have clarity.
4412     // If you're already mesmerised, you cannot resist further.
4413     if ((will_check > 0 || you.clarity()
4414          || you.duration[DUR_MESMERISE_IMMUNE]) && !already_mesmerised)
4415     {
4416         if (actual)
4417         {
4418             if (you.clarity())
4419                 canned_msg(MSG_YOU_UNAFFECTED);
4420             else if (you.duration[DUR_MESMERISE_IMMUNE] && !already_mesmerised)
4421                 canned_msg(MSG_YOU_RESIST);
4422             else
4423                 mprf("You%s", you.resist_margin_phrase(will_check).c_str());
4424         }
4425 
4426         return 0;
4427     }
4428 
4429     you.add_beholder(*mons);
4430 
4431     return 1;
4432 }
4433 
4434 // Check whether targets might be scared.
4435 // Returns 0, if targets can be scared but the attempt failed or wasn't made.
4436 // Returns 1, if targets are scared.
4437 // Returns -1, if targets can never be scared.
_mons_cause_fear(monster * mons,bool actual)4438 static int _mons_cause_fear(monster* mons, bool actual)
4439 {
4440     if (actual)
4441     {
4442         if (you.can_see(*mons))
4443             simple_monster_message(*mons, " radiates an aura of fear!");
4444         else if (you.see_cell(mons->pos()))
4445             mpr("An aura of fear fills the air!");
4446     }
4447 
4448     int retval = -1;
4449 
4450     const int pow = _ench_power(SPELL_CAUSE_FEAR, *mons);
4451 
4452     if (mons->see_cell_no_trans(you.pos())
4453         && mons->can_see(you)
4454         && !mons->wont_attack()
4455         && !you.afraid_of(mons))
4456     {
4457         if (!you.can_feel_fear(false))
4458         {
4459             if (actual)
4460                 canned_msg(MSG_YOU_UNAFFECTED);
4461         }
4462         else if (!actual)
4463             retval = 0;
4464         else
4465         {
4466             const int res_margin = you.check_willpower(pow);
4467             if (!you.can_feel_fear(true))
4468                 canned_msg(MSG_YOU_UNAFFECTED);
4469             else if (res_margin > 0)
4470                 mprf("You%s", you.resist_margin_phrase(res_margin).c_str());
4471             else if (you.add_fearmonger(mons))
4472             {
4473                 retval = 1;
4474                 you.increase_duration(DUR_AFRAID, 10 + random2avg(pow / 10, 4));
4475             }
4476         }
4477     }
4478 
4479     for (monster_near_iterator mi(mons->pos(), LOS_NO_TRANS); mi; ++mi)
4480     {
4481         if (*mi == mons)
4482             continue;
4483 
4484         // Invulnerable-willed, unnatural and "firewood" monsters are
4485         // immune to being scared. Same-aligned monsters are
4486         // never affected, even though they aren't immune.
4487         // Will not further scare a monster that is already afraid.
4488         if (mons_invuln_will(**mi)
4489             || !(mi->holiness() & MH_NATURAL)
4490             || mons_is_firewood(**mi)
4491             || mons_atts_aligned(mi->attitude, mons->attitude)
4492             || mi->has_ench(ENCH_FEAR))
4493         {
4494             continue;
4495         }
4496 
4497         retval = max(retval, 0);
4498 
4499         if (!actual)
4500             continue;
4501 
4502         // It's possible to scare this monster. If its magic
4503         // resistance fails, do so.
4504         int res_margin = mi->check_willpower(pow);
4505         if (res_margin > 0)
4506         {
4507             simple_monster_message(**mi,
4508                 mi->resist_margin_phrase(res_margin).c_str());
4509             continue;
4510         }
4511 
4512         if (mi->add_ench(mon_enchant(ENCH_FEAR, 0, mons)))
4513         {
4514             retval = 1;
4515 
4516             if (you.can_see(**mi))
4517                 simple_monster_message(**mi, " looks frightened!");
4518 
4519             behaviour_event(*mi, ME_SCARE, mons);
4520         }
4521     }
4522 
4523     if (actual && retval == 1 && you.see_cell(mons->pos()))
4524         flash_view_delay(UA_MONSTER, DARKGREY, 300);
4525 
4526     return retval;
4527 }
4528 
_mons_mass_confuse(monster * mons,bool actual)4529 static int _mons_mass_confuse(monster* mons, bool actual)
4530 {
4531     int retval = -1;
4532 
4533     const int pow = _ench_power(SPELL_MASS_CONFUSION, *mons);
4534 
4535     if (mons->see_cell_no_trans(you.pos())
4536         && mons->can_see(you)
4537         && !mons->wont_attack())
4538     {
4539         retval = 0;
4540 
4541         if (actual)
4542         {
4543             const int willpower = you.check_willpower(pow);
4544             if (willpower > 0)
4545                 mprf("You%s", you.resist_margin_phrase(willpower).c_str());
4546             else
4547             {
4548                 you.confuse(mons, 5 + random2(3));
4549                 retval = 1;
4550             }
4551         }
4552     }
4553 
4554     for (monster_near_iterator mi(mons->pos(), LOS_NO_TRANS); mi; ++mi)
4555     {
4556         if (*mi == mons)
4557             continue;
4558 
4559         if (mons_invuln_will(**mi)
4560             || mons_is_firewood(**mi)
4561             || mons_atts_aligned(mi->attitude, mons->attitude)
4562             || mons->has_ench(ENCH_HEXED))
4563         {
4564             continue;
4565         }
4566 
4567         retval = max(retval, 0);
4568 
4569         int res_margin = mi->check_willpower(pow);
4570         if (res_margin > 0)
4571         {
4572             if (actual)
4573             {
4574                 simple_monster_message(**mi,
4575                     mi->resist_margin_phrase(res_margin).c_str());
4576             }
4577             continue;
4578         }
4579         if (actual)
4580         {
4581             retval = 1;
4582             mi->confuse(mons, 5 + random2(3));
4583         }
4584     }
4585 
4586     return retval;
4587 }
4588 
_mons_fragment_target(const monster & mon)4589 static coord_def _mons_fragment_target(const monster &mon)
4590 {
4591     coord_def target(GXM+1, GYM+1);
4592     const monster *mons = &mon; // TODO: rewriteme
4593     const int pow = mons_spellpower(*mons, SPELL_LRD);
4594 
4595     // Shadow casting should try to affect the same tile as the player.
4596     if (mons_is_player_shadow(*mons))
4597     {
4598         bool temp;
4599         bolt beam;
4600         if (!setup_fragmentation_beam(beam, pow, mons, mons->target, true,
4601                                       nullptr, temp))
4602         {
4603             return target;
4604         }
4605         return mons->target;
4606     }
4607 
4608     const int range = _mons_spell_range(*mons, SPELL_LRD);
4609     int maxpower = 0;
4610     for (distance_iterator di(mons->pos(), true, true, range); di; ++di)
4611     {
4612         bool temp;
4613 
4614         if (!cell_see_cell(mons->pos(), *di, LOS_SOLID))
4615             continue;
4616 
4617         bolt beam;
4618         if (!setup_fragmentation_beam(beam, pow, mons, *di, true, nullptr,
4619                                       temp))
4620         {
4621             continue;
4622         }
4623 
4624         beam.range = range;
4625         fire_tracer(mons, beam, true);
4626         if (!mons_should_fire(beam))
4627             continue;
4628 
4629         if (beam.foe_info.count > 0
4630             && beam.foe_info.power > maxpower)
4631         {
4632             maxpower = beam.foe_info.power;
4633             target = *di;
4634         }
4635     }
4636 
4637     return target;
4638 }
4639 
_blink_allies_encircle(const monster * mon)4640 static void _blink_allies_encircle(const monster* mon)
4641 {
4642     vector<monster*> allies;
4643     const coord_def foepos = mon->get_foe()->pos();
4644 
4645     for (monster_near_iterator mi(mon, LOS_NO_TRANS); mi; ++mi)
4646     {
4647         if (_valid_encircle_ally(mon, *mi, foepos))
4648             allies.push_back(*mi);
4649     }
4650     shuffle_array(allies);
4651 
4652     int count = max(1, mon->spell_hd(SPELL_BLINK_ALLIES_ENCIRCLE) / 8
4653                        + random2(mon->spell_hd(SPELL_BLINK_ALLIES_ENCIRCLE) / 4));
4654 
4655     for (monster *ally : allies)
4656     {
4657         coord_def empty;
4658         if (find_habitable_spot_near(foepos, mons_base_type(*ally), 1, false, empty))
4659         {
4660             if (ally->blink_to(empty))
4661             {
4662                 // XXX: This seems an awkward way to give a message for something
4663                 // blinking from out of sight into sight. Probably could use a
4664                 // more general solution.
4665                 if (!(ally->flags & MF_WAS_IN_VIEW)
4666                     && ally->flags & MF_SEEN)
4667                 {
4668                     simple_monster_message(*ally, " blinks into view!");
4669                 }
4670                 ally->behaviour = BEH_SEEK;
4671                 ally->foe = mon->foe;
4672                 count--;
4673             }
4674         }
4675     }
4676 }
4677 
_blink_allies_away(const monster * mon)4678 static void _blink_allies_away(const monster* mon)
4679 {
4680     vector<monster*> allies;
4681     const coord_def foepos = mon->get_foe()->pos();
4682 
4683     for (monster_near_iterator mi(mon, LOS_NO_TRANS); mi; ++mi)
4684     {
4685         if (_valid_blink_away_ally(mon, *mi, foepos))
4686             allies.push_back(*mi);
4687     }
4688     shuffle_array(allies);
4689 
4690     int count = max(1, mon->spell_hd(SPELL_BLINK_ALLIES_AWAY) / 8
4691                        + random2(mon->spell_hd(SPELL_BLINK_ALLIES_AWAY) / 4));
4692 
4693     for (unsigned int i = 0; i < allies.size() && count; ++i)
4694     {
4695         if (blink_away(allies[i], &you, false))
4696             count--;
4697     }
4698 }
4699 
4700 struct branch_summon_pair
4701 {
4702     branch_type     origin;
4703     const vector<pop_entry> pop;
4704 };
4705 
4706 static branch_summon_pair _invitation_summons[] =
4707 {
4708   { BRANCH_LAIR,
4709     { // Lair enemies
4710       {  1,   1,   60, FLAT, MONS_BLINK_FROG },
4711       {  1,   1,   40, FLAT, MONS_DREAM_SHEEP },
4712       {  1,   1,   20, FLAT, MONS_CANE_TOAD },
4713     }},
4714   { BRANCH_SNAKE,
4715     { // Snake enemies
4716       {  1,   1,   80, FLAT, MONS_NAGA },
4717       {  1,   1,   40, FLAT, MONS_BLACK_MAMBA },
4718       {  1,   1,   20, FLAT, MONS_MANA_VIPER },
4719     }},
4720   { BRANCH_SPIDER,
4721     { // Spider enemies
4722       {  1,   1,   60, FLAT, MONS_TARANTELLA },
4723       {  1,   1,   80, FLAT, MONS_JUMPING_SPIDER },
4724       {  1,   1,   20, FLAT, MONS_ORB_SPIDER },
4725     }},
4726   { BRANCH_SWAMP,
4727     { // Swamp enemies
4728       {  1,   1,   80, FLAT, MONS_VAMPIRE_MOSQUITO },
4729       {  1,   1,   60, FLAT, MONS_BOG_BODY },
4730       {  1,   1,   40, FLAT, MONS_SWAMP_DRAKE },
4731     }},
4732   { BRANCH_SHOALS,
4733     { // Shoals enemies
4734       {  1,   1,   60, FLAT, MONS_MERFOLK_SIREN },
4735       {  1,   1,   40, FLAT, MONS_MANTICORE },
4736       {  1,   1,   20, FLAT, MONS_WIND_DRAKE },
4737     }},
4738   { BRANCH_ORC,
4739     { // Orc enemies
4740       {  1,   1,   80, FLAT, MONS_ORC_PRIEST },
4741       {  1,   1,   40, FLAT, MONS_WARG },
4742       {  1,   1,   20, FLAT, MONS_TROLL },
4743     }},
4744   { BRANCH_ELF,
4745     { // Elf enemies
4746       {  1,   1,   50, FLAT, MONS_DEEP_ELF_AIR_MAGE },
4747       {  1,   1,   50, FLAT, MONS_DEEP_ELF_FIRE_MAGE },
4748       {  1,   1,   40, FLAT, MONS_DEEP_ELF_KNIGHT },
4749       {  1,   1,   40, FLAT, MONS_DEEP_ELF_ARCHER },
4750     }},
4751   { BRANCH_VAULTS,
4752     { // Vaults enemies
4753       {  1,   1,   60, FLAT, MONS_YAKTAUR },
4754       {  1,   1,   40, FLAT, MONS_IRONBOUND_PRESERVER },
4755       {  1,   1,   20, FLAT, MONS_VAULT_SENTINEL },
4756     }},
4757   { BRANCH_CRYPT,
4758     { // Crypt enemies
4759       {  1,   1,   80, FLAT, MONS_WRAITH },
4760       {  1,   1,   60, FLAT, MONS_SHADOW },
4761       {  1,   1,   20, FLAT, MONS_NECROMANCER },
4762     }},
4763 };
4764 
4765 static branch_summon_pair _planerend_summons[] =
4766 {
4767   { BRANCH_SNAKE,
4768     { // Snake enemies
4769       {  1,   1,   40, FLAT, MONS_ANACONDA },
4770       {  1,   1,  100, FLAT, MONS_GUARDIAN_SERPENT },
4771       {  1,   1,  100, FLAT, MONS_NAGARAJA },
4772     }},
4773   { BRANCH_SPIDER,
4774     { // Spider enemies
4775       {  1,   1,  100, FLAT, MONS_EMPEROR_SCORPION },
4776       {  1,   1,   80, FLAT, MONS_TORPOR_SNAIL },
4777       {  1,   1,  100, FLAT, MONS_GHOST_MOTH },
4778     }},
4779   { BRANCH_SWAMP,
4780     { // Swamp enemies
4781       {  1,   1,  100, FLAT, MONS_SWAMP_DRAGON },
4782       {  1,   1,   80, FLAT, MONS_SHAMBLING_MANGROVE },
4783       {  1,   1,   40, FLAT, MONS_THORN_HUNTER },
4784     }},
4785   { BRANCH_SHOALS,
4786     { // Shoals enemies
4787       {  1,   1,   80, FLAT, MONS_ALLIGATOR_SNAPPING_TURTLE },
4788       {  1,   1,   40, FLAT, MONS_WATER_NYMPH },
4789       {  1,   1,  100, FLAT, MONS_MERFOLK_JAVELINEER },
4790     }},
4791   { BRANCH_SLIME,
4792     { // Slime enemies
4793       {  1,   1,   80, FLAT, MONS_SLIME_CREATURE }, // changed to titanic below
4794       {  1,   1,  100, FLAT, MONS_AZURE_JELLY },
4795       {  1,   1,  100, FLAT, MONS_ACID_BLOB },
4796     }},
4797   { BRANCH_ELF,
4798     { // Elf enemies
4799       {  1,   1,  100, FLAT, MONS_DEEP_ELF_SORCERER },
4800       {  1,   1,  100, FLAT, MONS_DEEP_ELF_HIGH_PRIEST },
4801       {  1,   1,   60, FLAT, MONS_DEEP_ELF_BLADEMASTER },
4802     }},
4803   { BRANCH_VAULTS,
4804     { // Vaults enemies
4805       {  1,   1,   80, FLAT, MONS_VAULT_SENTINEL },
4806       {  1,   1,   40, FLAT, MONS_IRONBOUND_CONVOKER },
4807       {  1,   1,  100, FLAT, MONS_WAR_GARGOYLE },
4808     }},
4809   { BRANCH_CRYPT,
4810     { // Crypt enemies
4811       {  1,   1,  100, FLAT, MONS_VAMPIRE_KNIGHT },
4812       {  1,   1,  100, FLAT, MONS_FLAYED_GHOST },
4813       {  1,   1,   80, FLAT, MONS_REVENANT },
4814     }},
4815   { BRANCH_TOMB,
4816     { // Tomb enemies
4817       {  1,   1,   60, FLAT, MONS_ANCIENT_CHAMPION },
4818       {  1,   1,  100, FLAT, MONS_SPHINX },
4819       {  1,   1,  100, FLAT, MONS_MUMMY_PRIEST },
4820     }},
4821   { BRANCH_ABYSS,
4822     { // Abyss enemies
4823       {  1,   1,   80, FLAT, MONS_APOCALYPSE_CRAB },
4824       {  1,   1,  100, FLAT, MONS_STARCURSED_MASS },
4825       {  1,   1,   40, FLAT, MONS_WRETCHED_STAR },
4826     }},
4827   { BRANCH_ZOT,
4828     { // Zot enemies
4829       {  1,   1,   40, FLAT, MONS_DRACONIAN_STORMCALLER },
4830       {  1,   1,  100, FLAT, MONS_GOLDEN_DRAGON },
4831       {  1,   1,   80, FLAT, MONS_MOTH_OF_WRATH },
4832     }},
4833 };
4834 
_branch_summon(monster & mons,mon_spell_slot slot,bolt &)4835 static void _branch_summon(monster &mons, mon_spell_slot slot, bolt&)
4836 {
4837     _branch_summon_helper(&mons, slot.spell);
4838 }
4839 
_branch_summon_helper(monster * mons,spell_type spell_cast)4840 static void _branch_summon_helper(monster* mons, spell_type spell_cast)
4841 {
4842     // TODO: rewrite me! (should use maps, vectors, const monster&...)
4843     branch_summon_pair *summon_list;
4844     size_t list_size;
4845     int which_branch;
4846     static const string INVITATION_KEY = "invitation_branch";
4847 
4848     switch (spell_cast)
4849     {
4850         case SPELL_FORCEFUL_INVITATION:
4851             summon_list = _invitation_summons;
4852             list_size = ARRAYSZ(_invitation_summons);
4853             if (!mons->props.exists(INVITATION_KEY))
4854                 mons->props[INVITATION_KEY].get_byte() = random2(list_size);
4855             which_branch = mons->props[INVITATION_KEY].get_byte();
4856             break;
4857         case SPELL_PLANEREND:
4858             summon_list = _planerend_summons;
4859             list_size = ARRAYSZ(_planerend_summons);
4860             which_branch = random2(list_size);
4861             break;
4862         default:
4863             die("Unsupported branch summon spell %s!",
4864                  spell_title(spell_cast));
4865     }
4866     const int num_summons = random_range(1, 3);
4867 
4868     if (you.see_cell(mons->pos()))
4869     {
4870         string msg = getSpeakString("branch summon cast prefix");
4871         if (!msg.empty())
4872         {
4873             msg  = replace_all(msg, "@The_monster@", mons->name(DESC_THE));
4874             msg += " ";
4875             msg += branches[summon_list[which_branch].origin].longname;
4876             msg += "!";
4877             mprf(mons->wont_attack() ? MSGCH_FRIEND_ENCHANT
4878                                      : MSGCH_MONSTER_ENCHANT,
4879                  "%s", msg.c_str());
4880         }
4881     }
4882 
4883     for (int i = 0; i < num_summons; i++)
4884     {
4885         monster_type type = pick_monster_from(summon_list[which_branch].pop, 1);
4886         if (type == MONS_NO_MONSTER)
4887             continue;
4888 
4889         mgen_data mg(type, SAME_ATTITUDE(mons), mons->pos(), mons->foe);
4890         mg.set_summoned(mons, 1, spell_cast);
4891         if (type == MONS_SLIME_CREATURE)
4892             mg.props[MGEN_BLOB_SIZE] = 5;
4893         create_monster(mg);
4894     }
4895 }
4896 
_cast_marshlight(monster & mons,mon_spell_slot,bolt &)4897 static void _cast_marshlight(monster &mons, mon_spell_slot, bolt&)
4898 {
4899     const int pow = mons_spellpower(mons, SPELL_MARSHLIGHT);
4900     cast_foxfire(mons, pow, GOD_NO_GOD, false);
4901 }
4902 
_cast_flay(monster & caster,mon_spell_slot,bolt &)4903 static void _cast_flay(monster &caster, mon_spell_slot, bolt&)
4904 {
4905     actor* defender = caster.get_foe();
4906     ASSERT(defender);
4907 
4908     int damage_taken = 0;
4909     if (defender->is_player())
4910         damage_taken = max(0, you.hp * 25 / 100 - 1);
4911     else
4912     {
4913         monster* mon = defender->as_monster();
4914         damage_taken = max(0, mon->hit_points * 25 / 100 - 1);
4915     }
4916 
4917     _flay(caster, *defender, damage_taken);
4918 }
4919 
4920 /**
4921  * Attempt to flay the given target, dealing 'temporary' damage that heals when
4922  * a flayed ghost nearby dies.
4923  *
4924  * @param caster    The flayed ghost doing the flaying. (Mostly irrelevant.)
4925  * @param defender  The thing being flayed.
4926  * @param damage    How much flaying damage to do.
4927  */
_flay(const monster & caster,actor & defender,int damage)4928 static void _flay(const monster &caster, actor &defender, int damage)
4929 {
4930     if (damage <= 0)
4931         return;
4932 
4933     bool was_flayed = false;
4934 
4935     if (defender.is_player())
4936     {
4937         if (you.duration[DUR_FLAYED])
4938             was_flayed = true;
4939 
4940         you.duration[DUR_FLAYED] = max(you.duration[DUR_FLAYED],
4941                                        55 + random2(66));
4942     }
4943     else
4944     {
4945         monster* mon = defender.as_monster();
4946         const int added_dur = 30 + random2(50);
4947 
4948         if (mon->has_ench(ENCH_FLAYED))
4949         {
4950             was_flayed = true;
4951             mon_enchant flayed = mon->get_ench(ENCH_FLAYED);
4952             flayed.duration = min(flayed.duration + added_dur, 150);
4953             mon->update_ench(flayed);
4954         }
4955         else
4956         {
4957             mon_enchant flayed(ENCH_FLAYED, 1, &caster, added_dur);
4958             mon->add_ench(flayed);
4959         }
4960     }
4961 
4962     if (you.can_see(defender))
4963     {
4964         if (was_flayed)
4965         {
4966             mprf("Terrible wounds spread across more of %s body!",
4967                  defender.name(DESC_ITS).c_str());
4968         }
4969         else
4970         {
4971             mprf("Terrible wounds open up all over %s body!",
4972                  defender.name(DESC_ITS).c_str());
4973         }
4974     }
4975 
4976     // Due to Deep Dwarf damage shaving, the player may take less than the intended
4977     // amount of damage. Keep track of the actual amount of damage done by comparing
4978     // hp before and after the player is hurt; use this as the actual value for
4979     // flay damage to prevent the player from regaining extra hp when it wears off
4980 
4981     const int orig_hp = defender.stat_hp();
4982 
4983     defender.hurt(&caster, damage, BEAM_NONE,
4984                   KILLED_BY_MONSTER, "", "flay_damage", true);
4985     defender.props["flay_damage"].get_int() += orig_hp - defender.stat_hp();
4986 
4987     vector<coord_def> old_blood;
4988     CrawlVector &new_blood = defender.props["flay_blood"].get_vector();
4989 
4990     // Find current blood spatters
4991     for (radius_iterator ri(defender.pos(), LOS_SOLID); ri; ++ri)
4992     {
4993         if (env.pgrid(*ri) & FPROP_BLOODY)
4994             old_blood.push_back(*ri);
4995     }
4996 
4997     blood_spray(defender.pos(), defender.type, 20);
4998 
4999     // Compute and store new blood spatters
5000     unsigned int i = 0;
5001     for (radius_iterator ri(defender.pos(), LOS_SOLID); ri; ++ri)
5002     {
5003         if (env.pgrid(*ri) & FPROP_BLOODY)
5004         {
5005             if (i < old_blood.size() && old_blood[i] == *ri)
5006                 ++i;
5007             else
5008                 new_blood.push_back(*ri);
5009         }
5010     }
5011 }
5012 
5013 /// What nonliving creatures are adjacent to the given location?
_find_nearby_constructs(const monster & caster,coord_def pos)5014 static vector<const actor*> _find_nearby_constructs(const monster &caster,
5015                                                     coord_def pos)
5016 {
5017     vector<const actor*> nearby_constructs;
5018     for (adjacent_iterator ai(pos); ai; ++ai)
5019     {
5020         const actor* act = actor_at(*ai);
5021         if (act && act->holiness() & MH_NONLIVING && mons_aligned(&caster, act))
5022             nearby_constructs.push_back(act);
5023     }
5024     return nearby_constructs;
5025 }
5026 
5027 /// How many nonliving creatures are adjacent to the given location?
_count_nearby_constructs(const monster & caster,coord_def pos)5028 static int _count_nearby_constructs(const monster &caster, coord_def pos)
5029 {
5030     return _find_nearby_constructs(caster, pos).size();
5031 }
5032 
5033 /// What's a good description of nonliving creatures adjacent to the given point?
_describe_nearby_constructs(const monster & caster,coord_def pos)5034 static string _describe_nearby_constructs(const monster &caster, coord_def pos)
5035 {
5036     const vector<const actor*> nearby_constructs
5037         = _find_nearby_constructs(caster, pos);
5038     if (!nearby_constructs.size())
5039         return "";
5040 
5041     const string name = nearby_constructs.back()->name(DESC_THE);
5042     if (nearby_constructs.size() == 1)
5043         return make_stringf(" and %s", name.c_str());
5044 
5045     for (auto act : nearby_constructs)
5046         if (act->name(DESC_THE) != name)
5047             return " and the adjacent constructs";
5048     return make_stringf(" and %s", pluralise_monster(name).c_str());
5049 }
5050 
5051 /// Cast Resonance Strike, blasting the caster's target with smitey damage.
_cast_resonance_strike(monster & caster,mon_spell_slot,bolt &)5052 static void _cast_resonance_strike(monster &caster, mon_spell_slot, bolt&)
5053 {
5054     actor* target = caster.get_foe();
5055     if (!target)
5056         return;
5057 
5058     const int constructs = _count_nearby_constructs(caster, target->pos());
5059     // base damage 3d(spell hd) (probably 3d12)
5060     // + 1 die for every 2 adjacent constructs (so at 4 constructs, 5dhd)
5061     dice_def dice = resonance_strike_base_damage(caster);
5062     dice.num += div_rand_round(constructs, 2);
5063     const int dam = target->apply_ac(dice.roll());
5064     const string constructs_desc
5065         = _describe_nearby_constructs(caster, target->pos());
5066 
5067     if (you.see_cell(target->pos()))
5068     {
5069         mprf("A blast of power from the earth%s strikes %s!",
5070              constructs_desc.c_str(),
5071              target->name(DESC_THE).c_str());
5072     }
5073     target->hurt(&caster, dam, BEAM_MISSILE, KILLED_BY_BEAM,
5074                  "", "by a resonance strike");
5075 }
5076 
_spell_charged(monster * mons)5077 static bool _spell_charged(monster *mons)
5078 {
5079     mon_enchant ench = mons->get_ench(ENCH_SPELL_CHARGED);
5080     if (ench.ench == ENCH_NONE || ench.degree < max_mons_charge(mons->type))
5081     {
5082         if (ench.ench == ENCH_NONE)
5083         {
5084             mons->add_ench(mon_enchant(ENCH_SPELL_CHARGED, 1, mons,
5085                                        INFINITE_DURATION));
5086         }
5087         else
5088         {
5089             ench.degree++;
5090             mons->update_ench(ench);
5091         }
5092 
5093         if (!you.can_see(*mons))
5094             return false;
5095         string msg =
5096             getSpeakString(make_stringf("%s charge",
5097                                         mons->name(DESC_PLAIN, true).c_str())
5098                            .c_str());
5099         if (!msg.empty())
5100         {
5101             msg = do_mon_str_replacements(msg, *mons);
5102             mprf(mons->wont_attack() ? MSGCH_FRIEND_ENCHANT
5103                  : MSGCH_MONSTER_ENCHANT, "%s", msg.c_str());
5104         }
5105         return false;
5106     }
5107     mons->del_ench(ENCH_SPELL_CHARGED);
5108     return true;
5109 }
5110 
5111 /// How much damage does the given monster do when casting Waterstrike?
waterstrike_damage(int spell_hd)5112 dice_def waterstrike_damage(int spell_hd)
5113 {
5114     return dice_def(3, 7 + spell_hd);
5115 }
5116 
5117 /**
5118  * How much damage does the given monster do when casting Resonance Strike,
5119  * assuming no allied constructs are boosting damage?
5120  */
resonance_strike_base_damage(const monster & mons)5121 dice_def resonance_strike_base_damage(const monster &mons)
5122 {
5123     return dice_def(3, mons.spell_hd(SPELL_RESONANCE_STRIKE));
5124 }
5125 
5126 static const int MIN_DREAM_SUCCESS_POWER = 25;
5127 
_sheep_message(int num_sheep,int sleep_pow,actor & foe)5128 static void _sheep_message(int num_sheep, int sleep_pow, actor& foe)
5129 {
5130     string message;
5131 
5132     // Determine messaging based on sleep strength.
5133     if (sleep_pow >= 125)
5134         message = "You are overwhelmed by glittering dream dust!";
5135     else if (sleep_pow >= 75)
5136         message = "The dream sheep are wreathed in dream dust.";
5137     else if (sleep_pow >= MIN_DREAM_SUCCESS_POWER)
5138     {
5139         message = make_stringf("The dream sheep shake%s wool and sparkle%s.",
5140                                num_sheep == 1 ? "s its" : " their",
5141                                num_sheep == 1 ? "s": "");
5142     }
5143     else // if sleep fails
5144     {
5145         message = make_stringf("The dream sheep ruffle%s wool and motes of "
5146                                "dream dust sparkle, to no effect.",
5147                                num_sheep == 1 ? "s its" : " their");
5148     }
5149 
5150     // Messaging for non-player targets
5151     if (!foe.is_player() && you.see_cell(foe.pos()))
5152     {
5153         const char* pluralize = num_sheep == 1 ? "s": "";
5154         const string foe_name = foe.name(DESC_THE);
5155         if (sleep_pow)
5156         {
5157             mprf(foe.as_monster()->friendly() ? MSGCH_FRIEND_SPELL
5158                                               : MSGCH_MONSTER_SPELL,
5159                  "As the sheep sparkle%s and sway%s, %s falls asleep.",
5160                  pluralize,
5161                  pluralize,
5162                  foe_name.c_str());
5163         }
5164         else // if dust strength failure for non-player
5165         {
5166             mprf(foe.as_monster()->friendly() ? MSGCH_FRIEND_SPELL
5167                                               : MSGCH_MONSTER_SPELL,
5168                  "The dream sheep attempt%s to lull %s to sleep.",
5169                  pluralize,
5170                  foe_name.c_str());
5171             mprf("%s is unaffected.", foe_name.c_str());
5172         }
5173     }
5174     else if (foe.is_player())
5175     {
5176         mprf(MSGCH_MONSTER_SPELL, "%s%s", message.c_str(),
5177              sleep_pow ? " You feel drowsy..." : "");
5178     }
5179 }
5180 
_dream_sheep_sleep(monster & mons,actor & foe)5181 static void _dream_sheep_sleep(monster& mons, actor& foe)
5182 {
5183     // Shepherd the dream sheep.
5184     int num_sheep = 0;
5185     for (monster_near_iterator mi(foe.pos(), LOS_NO_TRANS); mi; ++mi)
5186         if (mi->type == MONS_DREAM_SHEEP)
5187             num_sheep++;
5188 
5189     // The correlation between amount of sheep and duration of
5190     // sleep is randomised, but bounds are 5 to 20 turns of sleep.
5191     // More dream sheep are both more likely to succeed and to have a
5192     // stronger effect. Too-weak attempts get blanked.
5193     // Special note: a single sheep has a 1 in 25 chance to succeed.
5194     int sleep_pow = min(150, random2(num_sheep * 25) + 1);
5195     if (sleep_pow < MIN_DREAM_SUCCESS_POWER)
5196         sleep_pow = 0;
5197 
5198     // Communicate with the player.
5199     _sheep_message(num_sheep, sleep_pow, foe);
5200 
5201     // Put the player to sleep.
5202     if (sleep_pow)
5203         foe.put_to_sleep(&mons, sleep_pow, false);
5204 }
5205 
5206 // Draconian stormcaller upheaval. Simplified compared to the player version.
5207 // Noisy! Causes terrain changes. Destroys doors/walls.
5208 // Also used for Salamander Tyrants
5209 // TODO: Could use further simplification.
_mons_upheaval(monster & mons,actor &,bool randomize)5210 static void _mons_upheaval(monster& mons, actor& /*foe*/, bool randomize)
5211 {
5212     bolt beam;
5213     beam.source_id   = mons.mid;
5214     beam.source_name = mons.name(DESC_THE).c_str();
5215     beam.thrower     = KILL_MON_MISSILE;
5216     beam.range       = LOS_RADIUS;
5217     beam.damage      = dice_def(3, 24);
5218     beam.foe_ratio   = random_range(20, 30);
5219     beam.hit         = AUTOMATIC_HIT;
5220     beam.glyph       = dchar_glyph(DCHAR_EXPLOSION);
5221     beam.loudness    = 10;
5222 #ifdef USE_TILE
5223     beam.tile_beam   = -1;
5224 #endif
5225     beam.draw_delay  = 0;
5226     beam.target = mons.target;
5227     string message = "";
5228 
5229     switch (randomize ? random2(4) : 0)
5230     {
5231         case 0:
5232             beam.name     = "blast of magma";
5233             beam.flavour  = BEAM_LAVA;
5234             beam.colour   = RED;
5235             beam.hit_verb = "engulfs";
5236             message       = "Magma suddenly erupts from the ground!";
5237             break;
5238         case 1:
5239             beam.name    = "blast of ice";
5240             beam.flavour = BEAM_ICE;
5241             beam.colour  = WHITE;
5242             message      = "A blizzard blasts the area with ice!";
5243             break;
5244         case 2:
5245             beam.name    = "cutting wind";
5246             beam.flavour = BEAM_AIR;
5247             beam.colour  = LIGHTGRAY;
5248             message      = "A storm cloud blasts the area with cutting wind!";
5249             break;
5250         case 3:
5251             beam.name    = "blast of rubble";
5252             beam.flavour = BEAM_FRAG;
5253             beam.colour  = BROWN;
5254             message      = "The ground shakes violently, spewing rubble!";
5255             break;
5256         default:
5257             break;
5258     }
5259 
5260     vector<coord_def> affected;
5261     affected.push_back(beam.target);
5262 
5263     const int radius = 2;
5264     for (radius_iterator ri(beam.target, radius, C_SQUARE, LOS_SOLID, true);
5265          ri; ++ri)
5266     {
5267         if (!in_bounds(*ri) || cell_is_solid(*ri))
5268             continue;
5269 
5270         bool splash = true;
5271         bool adj = adjacent(beam.target, *ri);
5272         if (!adj)
5273             splash = false;
5274         if (adj || splash)
5275         {
5276             if (beam.flavour == BEAM_FRAG || !cell_is_solid(*ri))
5277                 affected.push_back(*ri);
5278         }
5279     }
5280 
5281     if (Options.use_animations & UA_MONSTER)
5282     {
5283         for (coord_def pos : affected)
5284         {
5285             beam.draw(pos);
5286             scaled_delay(25);
5287         }
5288     }
5289 
5290     for (coord_def pos : affected)
5291     {
5292         beam.source = pos;
5293         beam.target = pos;
5294         beam.fire();
5295 
5296         switch (beam.flavour)
5297         {
5298             case BEAM_LAVA:
5299                 if (env.grid(pos) == DNGN_FLOOR && !actor_at(pos) && coinflip())
5300                 {
5301                     temp_change_terrain(
5302                         pos, DNGN_LAVA,
5303                         random2(14) * BASELINE_DELAY,
5304                         TERRAIN_CHANGE_FLOOD);
5305                 }
5306                 break;
5307             case BEAM_AIR:
5308                 if (!cell_is_solid(pos) && !cloud_at(pos) && coinflip())
5309                     place_cloud(CLOUD_STORM, pos, random2(7), &mons);
5310                 break;
5311             case BEAM_FRAG:
5312                 if (((env.grid(pos) == DNGN_ROCK_WALL
5313                      || env.grid(pos) == DNGN_CLEAR_ROCK_WALL
5314                      || env.grid(pos) == DNGN_SLIMY_WALL)
5315                      && x_chance_in_y(1, 4)
5316                      || feat_is_door(env.grid(pos))
5317                      || env.grid(pos) == DNGN_GRATE))
5318                 {
5319                     noisy(30, pos);
5320                     destroy_wall(pos);
5321                 }
5322                 break;
5323             default:
5324                 break;
5325         }
5326     }
5327 }
5328 
_mons_vortex(monster * mons)5329 static void _mons_vortex(monster *mons)
5330 {
5331     if (you.can_see(*mons))
5332     {
5333         bool flying = mons->airborne();
5334         mprf("A freezing vortex appears %s%s%s!",
5335              flying ? "around " : "and lifts ",
5336              mons->name(DESC_THE).c_str(),
5337              flying ? "" : " up!");
5338     }
5339     else if (you.see_cell(mons->pos()))
5340         mpr("A freezing vortex appears out of thin air!");
5341 
5342     const int ench_dur = 60;
5343 
5344     mons->props["polar_vortex_since"].get_int() = you.elapsed_time;
5345     mon_enchant me(ENCH_POLAR_VORTEX, 0, mons, ench_dur);
5346     mons->add_ench(me);
5347 
5348     if (mons->has_ench(ENCH_FLIGHT))
5349     {
5350         mon_enchant me2 = mons->get_ench(ENCH_FLIGHT);
5351         me2.duration = me.duration;
5352         mons->update_ench(me2);
5353     }
5354     else
5355         mons->add_ench(mon_enchant(ENCH_FLIGHT, 0, mons, ench_dur));
5356 }
5357 
5358 /**
5359  *  Make this monster cast a spell
5360  *
5361  *  @param mons       The monster casting
5362  *  @param pbolt      The beam, possibly containing pre-done setup, to use
5363  *                    for the spell. Not a reference because this function
5364                       shouldn't affect the original copy.
5365  *  @param spell_cast The spell to be cast.
5366  *  @param slot_flags The spell slot flags in mons->spells (is it an
5367  *                    invocation, natural, shouty, etc.?)
5368  *  @param do_noise   Whether to make noise (including casting messages).
5369  */
mons_cast(monster * mons,bolt pbolt,spell_type spell_cast,mon_spell_slot_flags slot_flags,bool do_noise)5370 void mons_cast(monster* mons, bolt pbolt, spell_type spell_cast,
5371                mon_spell_slot_flags slot_flags, bool do_noise)
5372 {
5373     // check sputtercast state for e.g. orb spiders. assumption: all
5374     // sputtercasting monsters have one charge status and use it for all of
5375     // their spells.
5376     if (max_mons_charge(mons->type) > 0 && !_spell_charged(mons))
5377         return;
5378 
5379     if (spell_is_soh_breath(spell_cast))
5380     {
5381         const vector<spell_type> *breaths = soh_breath_spells(spell_cast);
5382         ASSERT(breaths);
5383         ASSERT(mons->heads() == (int)breaths->size());
5384 
5385         for (spell_type head_spell : *breaths)
5386         {
5387             if (!mons->get_foe())
5388                 return;
5389             setup_mons_cast(mons, pbolt, head_spell);
5390             mons_cast(mons, pbolt, head_spell, slot_flags, do_noise);
5391         }
5392 
5393         return;
5394     }
5395 
5396     if (spell_cast == SPELL_LEGENDARY_DESTRUCTION)
5397     {
5398         if (do_noise)
5399         {
5400             mons_cast_noise(mons, pbolt, SPELL_LEGENDARY_DESTRUCTION,
5401                             slot_flags);
5402         }
5403 
5404         setup_mons_cast(mons, pbolt, SPELL_LEGENDARY_DESTRUCTION);
5405         mons_cast(mons, pbolt, _legendary_destruction_spell(), slot_flags,
5406                   false);
5407         if (!mons->get_foe())
5408             return;
5409         setup_mons_cast(mons, pbolt, SPELL_LEGENDARY_DESTRUCTION);
5410         mons_cast(mons, pbolt, _legendary_destruction_spell(), slot_flags,
5411                   false);
5412         return;
5413     }
5414 
5415     // Maybe cast abjuration instead of certain summoning spells.
5416     if (mons->can_see(you) &&
5417         get_spell_flags(spell_cast) & spflag::mons_abjure && one_chance_in(3)
5418         && ai_action::is_viable(_mons_will_abjure(*mons)))
5419     {
5420         mons_cast(mons, pbolt, SPELL_ABJURATION, slot_flags, do_noise);
5421         return;
5422     }
5423 
5424     bool evoke {slot_flags & MON_SPELL_EVOKE};
5425     // Always do setup. It might be done already, but it doesn't hurt
5426     // to do it again (cheap).
5427     setup_mons_cast(mons, pbolt, spell_cast, evoke);
5428 
5429     // single calculation permissible {dlb}
5430     const spell_flags flags = get_spell_flags(spell_cast);
5431     actor* const foe = mons->get_foe();
5432     const mons_spell_logic* logic = map_find(spell_to_logic, spell_cast);
5433     const mon_spell_slot slot = {spell_cast, 0, slot_flags};
5434 
5435     int sumcount = 0;
5436     int sumcount2;
5437     int duration = 0;
5438 
5439     dprf("Mon #%d casts %s (#%d)",
5440          mons->mindex(), spell_title(spell_cast), spell_cast);
5441     ASSERT(!(flags & spflag::testing));
5442     // Targeted spells need a valid target.
5443     // Wizard-mode cast monster spells may target the boundary (shift-dir).
5444     ASSERT(map_bounds(pbolt.target) || !(flags & spflag::targeting_mask));
5445 
5446     if (spell_cast == SPELL_PORTAL_PROJECTILE
5447         || logic && (logic->flags & MSPELL_NO_AUTO_NOISE))
5448     {
5449         do_noise = false;       // Spell itself does the messaging.
5450     }
5451 
5452     if (do_noise)
5453         mons_cast_noise(mons, pbolt, spell_cast, slot_flags);
5454 
5455     if (logic && logic->cast)
5456     {
5457         logic->cast(*mons, slot, pbolt);
5458         return;
5459     }
5460 
5461     const god_type god = _find_god(*mons, slot_flags);
5462     const int splpow = evoke ? 30 + mons->get_hit_dice()
5463                              : mons_spellpower(*mons, spell_cast);
5464 
5465     switch (spell_cast)
5466     {
5467     default:
5468         break;
5469 
5470     case SPELL_WATERSTRIKE:
5471     {
5472         pbolt.flavour    = BEAM_WATER;
5473 
5474         ASSERT(foe);
5475         int damage_taken = waterstrike_damage(mons->spell_hd(spell_cast)).roll();
5476         damage_taken = foe->beam_resists(pbolt, damage_taken, false);
5477         damage_taken = foe->apply_ac(damage_taken);
5478 
5479         if (you.can_see(*foe))
5480         {
5481                 mprf("The water %s and strikes %s%s",
5482                         foe->airborne() ? "rises up" : "swirls",
5483                         foe->name(DESC_THE).c_str(),
5484                         attack_strength_punctuation(damage_taken).c_str());
5485         }
5486 
5487         foe->hurt(mons, damage_taken, BEAM_MISSILE, KILLED_BY_BEAM,
5488                       "", "by the raging water");
5489         return;
5490     }
5491 
5492     case SPELL_AIRSTRIKE:
5493     {
5494         pbolt.flavour = BEAM_AIR;
5495 
5496         int empty_space = 0;
5497         ASSERT(foe);
5498         for (adjacent_iterator ai(foe->pos()); ai; ++ai)
5499             if (!monster_at(*ai) && !cell_is_solid(*ai))
5500                 empty_space++;
5501 
5502         empty_space = max(3, empty_space);
5503 
5504         int damage_taken = 5 + empty_space
5505                          + random2avg(2 + div_rand_round(splpow, 7),
5506                                       empty_space);
5507         damage_taken = foe->beam_resists(pbolt, damage_taken, false);
5508 
5509         damage_taken = foe->apply_ac(damage_taken);
5510 
5511         if (you.can_see(*foe))
5512         {
5513                 mprf("The air twists around and strikes %s%s",
5514                      foe->name(DESC_THE).c_str(),
5515                      attack_strength_punctuation(damage_taken).c_str());
5516         }
5517 
5518         foe->hurt(mons, damage_taken, BEAM_MISSILE, KILLED_BY_BEAM,
5519                   "", "by the air");
5520         return;
5521     }
5522 
5523     case SPELL_HOLY_FLAMES:
5524         holy_flames(mons, foe);
5525         return;
5526     case SPELL_BRAIN_FEED:
5527         if (one_chance_in(3)
5528             && lose_stat(STAT_INT, 1 + random2(3)))
5529         {
5530             mpr("Something feeds on your intellect!");
5531             xom_is_stimulated(50);
5532         }
5533         else
5534             mpr("Something tries to feed on your intellect!");
5535         return;
5536 
5537     case SPELL_SUMMON_SPECTRAL_ORCS:
5538         // Wizard mode creates a dummy friendly monster, with no foe.
5539         if (!foe)
5540             return;
5541         if (foe->is_player())
5542             mpr("Orcish apparitions take form around you.");
5543         else
5544             simple_monster_message(*foe->as_monster(), " is surrounded by Orcish apparitions.");
5545         _mons_cast_spectral_orcs(mons);
5546         return;
5547 
5548     case SPELL_HAUNT:
5549         ASSERT(foe);
5550         if (foe->is_player())
5551             mpr("You feel haunted.");
5552         else
5553             mpr("You sense an evil presence.");
5554         _mons_cast_haunt(mons);
5555         return;
5556 
5557     // SPELL_SLEEP_GAZE ;)
5558     case SPELL_DREAM_DUST:
5559         _dream_sheep_sleep(*mons, *foe);
5560         return;
5561 
5562     case SPELL_CONFUSION_GAZE:
5563     {
5564         ASSERT(foe);
5565         const int res_margin = foe->check_willpower(splpow / ENCH_POW_FACTOR);
5566         if (res_margin > 0)
5567         {
5568             if (you.can_see(*foe))
5569             {
5570                 mprf("%s%s",
5571                      foe->name(DESC_THE).c_str(),
5572                      foe->resist_margin_phrase(res_margin).c_str());
5573             }
5574             return;
5575         }
5576 
5577         foe->confuse(mons, 5 + random2(3));
5578         return;
5579     }
5580 
5581     case SPELL_WOODWEAL:
5582         if (mons->heal(35 + random2(mons->spell_hd(spell_cast) * 3)))
5583             simple_monster_message(*mons, " is healed.");
5584         break;
5585 
5586     case SPELL_MAJOR_HEALING:
5587         if (mons->heal(50 + random2avg(mons->spell_hd(spell_cast) * 10, 2)))
5588             simple_monster_message(*mons, " is healed.");
5589         return;
5590 
5591     case SPELL_BERSERKER_RAGE:
5592         mons->props.erase("brothers_count");
5593         mons->go_berserk(true);
5594         return;
5595 
5596 #if TAG_MAJOR_VERSION == 34
5597     // Replaced with monster-specific version.
5598     case SPELL_SWIFTNESS:
5599 #endif
5600     case SPELL_SPRINT:
5601         mons->add_ench(ENCH_SWIFT);
5602         simple_monster_message(*mons, " puts on a burst of speed!");
5603         return;
5604 
5605     case SPELL_SILENCE:
5606         mons->add_ench(ENCH_SILENCE);
5607         invalidate_agrid(true);
5608         simple_monster_message(*mons, "'s surroundings become eerily quiet.");
5609         return;
5610 
5611     case SPELL_CALL_TIDE:
5612         if (player_in_branch(BRANCH_SHOALS))
5613         {
5614             const int tide_duration = BASELINE_DELAY
5615                 * random_range(80, 200, 2);
5616             mons->add_ench(mon_enchant(ENCH_TIDE, 0, mons,
5617                                        tide_duration));
5618             mons->props[TIDE_CALL_TURN].get_int() = you.num_turns;
5619             if (simple_monster_message(*
5620                     mons,
5621                     " sings a water chant to call the tide!"))
5622             {
5623                 flash_view_delay(UA_MONSTER, ETC_WATER, 300);
5624             }
5625         }
5626         return;
5627 
5628     case SPELL_INK_CLOUD:
5629         if (!feat_is_watery(env.grid(mons->pos())))
5630             return;
5631 
5632         big_cloud(CLOUD_INK, mons, mons->pos(), 30, 30);
5633 
5634         simple_monster_message(*
5635             mons,
5636             " squirts a massive cloud of ink into the water!");
5637         return;
5638 
5639     case SPELL_SUMMON_SMALL_MAMMAL:
5640         sumcount2 = 1 + random2(3);
5641 
5642         for (sumcount = 0; sumcount < sumcount2; ++sumcount)
5643         {
5644             monster_type rats[] = { MONS_QUOKKA, MONS_RIVER_RAT, MONS_RAT };
5645 
5646             const monster_type mon = (one_chance_in(3) ? MONS_BAT
5647                                                        : RANDOM_ELEMENT(rats));
5648             create_monster(
5649                 mgen_data(mon, SAME_ATTITUDE(mons), mons->pos(), mons->foe)
5650                 .set_summoned(mons, 5, spell_cast, god));
5651         }
5652         return;
5653 
5654     case SPELL_SHADOW_CREATURES:       // summon anything appropriate for level
5655     {
5656         level_id place = level_id::current();
5657 
5658         sumcount2 = 1 + random2(mons->spell_hd(spell_cast) / 5 + 1);
5659 
5660         for (sumcount = 0; sumcount < sumcount2; ++sumcount)
5661         {
5662             create_monster(
5663                 mgen_data(RANDOM_MOBILE_MONSTER, SAME_ATTITUDE(mons),
5664                           mons->pos(), mons->foe)
5665                           .set_summoned(mons, 5, spell_cast, god)
5666                           .set_place(place));
5667         }
5668         return;
5669     }
5670 
5671     case SPELL_SUMMON_ILLUSION:
5672         _mons_cast_summon_illusion(mons, spell_cast);
5673         return;
5674 
5675     case SPELL_CREATE_TENTACLES:
5676         mons_create_tentacles(mons);
5677         return;
5678 
5679     case SPELL_FAKE_MARA_SUMMON:
5680         // We only want there to be two fakes, which, plus Mara, means
5681         // a total of three Maras; if we already have two, give up, otherwise
5682         // we want to summon either one more or two more.
5683         sumcount2 = 2 - count_summons(mons, SPELL_FAKE_MARA_SUMMON);
5684         if (sumcount2 <= 0)
5685             return;
5686 
5687         for (sumcount = 0; sumcount < sumcount2; sumcount++)
5688             cast_phantom_mirror(mons, mons, 50, SPELL_FAKE_MARA_SUMMON);
5689 
5690         if (you.can_see(*mons))
5691         {
5692             mprf("%s shimmers and seems to become %s!", mons->name(DESC_THE).c_str(),
5693                                                         sumcount2 == 1 ? "two"
5694                                                                        : "three");
5695         }
5696 
5697         return;
5698 
5699     case SPELL_SUMMON_DEMON: // class 3-4 demons
5700         // if you change this, please update art-func.h:_DEMON_AXE_melee_effects
5701         sumcount2 = 1 + random2(mons->spell_hd(spell_cast) / 10 + 1);
5702 
5703         duration  = min(2 + mons->spell_hd(spell_cast) / 10, 6);
5704         for (sumcount = 0; sumcount < sumcount2; sumcount++)
5705         {
5706             create_monster(
5707                 mgen_data(summon_any_demon(RANDOM_DEMON_COMMON, true),
5708                           SAME_ATTITUDE(mons), mons->pos(), mons->foe)
5709                 .set_summoned(mons, duration, spell_cast, god));
5710         }
5711         return;
5712 
5713     case SPELL_MONSTROUS_MENAGERIE:
5714         cast_monstrous_menagerie(mons, splpow, mons->god);
5715         return;
5716 
5717     case SPELL_CALL_IMP:
5718         duration  = min(2 + mons->spell_hd(spell_cast) / 5, 6);
5719         create_monster(
5720             mgen_data(random_choose_weighted(
5721                         1, MONS_IRON_IMP,
5722                         2, MONS_SHADOW_IMP,
5723                         2, MONS_WHITE_IMP,
5724                         4, MONS_CRIMSON_IMP),
5725                       SAME_ATTITUDE(mons), mons->pos(), mons->foe)
5726             .set_summoned(mons, duration, spell_cast, god));
5727         return;
5728 
5729     case SPELL_SUMMON_MINOR_DEMON: // class 5 demons
5730         sumcount2 = 1 + random2(3);
5731 
5732         duration  = min(2 + mons->spell_hd(spell_cast) / 5, 6);
5733         for (sumcount = 0; sumcount < sumcount2; ++sumcount)
5734         {
5735             create_monster(
5736                 mgen_data(summon_any_demon(RANDOM_DEMON_LESSER, true),
5737                           SAME_ATTITUDE(mons), mons->pos(), mons->foe)
5738                 .set_summoned(mons, duration, spell_cast, god));
5739         }
5740         return;
5741 
5742     case SPELL_SUMMON_UFETUBUS:
5743         sumcount2 = 2 + random2(2);
5744 
5745         duration  = min(2 + mons->spell_hd(spell_cast) / 5, 6);
5746 
5747         for (sumcount = 0; sumcount < sumcount2; ++sumcount)
5748         {
5749             create_monster(
5750                 mgen_data(MONS_UFETUBUS, SAME_ATTITUDE(mons), mons->pos(),
5751                           mons->foe)
5752                 .set_summoned(mons, duration, spell_cast, god));
5753         }
5754         return;
5755 
5756     case SPELL_SUMMON_HELL_BEAST:  // Geryon
5757         create_monster(
5758             mgen_data(MONS_HELL_BEAST, SAME_ATTITUDE(mons), mons->pos(),
5759                       mons->foe).set_summoned(mons, 4, spell_cast, god));
5760         return;
5761 
5762     case SPELL_SUMMON_ICE_BEAST:
5763         _summon(*mons, MONS_ICE_BEAST, 5, slot);
5764         return;
5765 
5766     case SPELL_SUMMON_MUSHROOMS:   // Summon a ring of icky crawling fungi.
5767         // Wizard mode creates a dummy friendly monster, with no foe.
5768         if (!foe)
5769             return;
5770         sumcount2 = 2 + random2(mons->spell_hd(spell_cast) / 4 + 1);
5771         duration  = min(2 + mons->spell_hd(spell_cast) / 5, 6);
5772         for (int i = 0; i < sumcount2; ++i)
5773         {
5774             // Attempt to place adjacent to target first, and only at a wider
5775             // radius if no adjacent spots can be found
5776             coord_def empty;
5777             find_habitable_spot_near(foe->pos(),
5778                                      MONS_WANDERING_MUSHROOM, 1, false, empty);
5779             if (empty.origin())
5780             {
5781                 find_habitable_spot_near(foe->pos(),
5782                                          MONS_WANDERING_MUSHROOM, 2, false, empty);
5783             }
5784 
5785             // Can't find any room, so stop trying
5786             if (empty.origin())
5787                 return;
5788 
5789             create_monster(
5790                 mgen_data(one_chance_in(3) ? MONS_DEATHCAP
5791                                            : MONS_WANDERING_MUSHROOM,
5792                           SAME_ATTITUDE(mons), empty, mons->foe, MG_FORCE_PLACE)
5793                 .set_summoned(mons, duration, spell_cast, god));
5794         }
5795         return;
5796 
5797     case SPELL_SUMMON_HORRIBLE_THINGS:
5798         _do_high_level_summon(mons, spell_cast, _pick_horrible_thing,
5799                               random_range(3, 5), god);
5800         return;
5801 
5802     case SPELL_MALIGN_GATEWAY:
5803         if (!can_cast_malign_gateway())
5804         {
5805             dprf("ERROR: %s can't cast malign gateway, but is casting anyway! "
5806                  "Counted %d gateways.", mons->name(DESC_THE).c_str(),
5807                  count_malign_gateways());
5808         }
5809         cast_malign_gateway(mons, 200);
5810         return;
5811 
5812     case SPELL_CONJURE_BALL_LIGHTNING:
5813     {
5814         const int hd = mons->spell_hd(spell_cast);
5815         const int pow = mons_power_for_hd(spell_cast, hd);
5816         const int n = 3;
5817         for (int i = 0; i < n; ++i)
5818         {
5819             mgen_data mg = mgen_data(MONS_BALL_LIGHTNING, SAME_ATTITUDE(mons),
5820                                      mons->pos(), mons->foe)
5821                             .set_summoned(mons, 0, spell_cast, god);
5822             mg.hd = mons_ball_lightning_hd(pow);
5823             if (monster *ball = create_monster(mg))
5824                 ball->add_ench(ENCH_SHORT_LIVED);
5825         }
5826         return;
5827     }
5828 
5829     case SPELL_SUMMON_UNDEAD:
5830         _do_high_level_summon(mons, spell_cast, _pick_undead_summon,
5831                               2 + random2(mons->spell_hd(spell_cast) / 5 + 1),
5832                               god);
5833         return;
5834 
5835     case SPELL_BROTHERS_IN_ARMS:
5836     {
5837         // Invocation; don't use spell_hd
5838         int power = (mons->get_hit_dice() * 20)
5839                           + random2(mons->get_hit_dice() * 5);
5840         power -= random2(mons->get_hit_dice() * 5); // force a sequence point
5841         monster_type to_summon;
5842 
5843         if (mons->type == MONS_SPRIGGAN_BERSERKER)
5844         {
5845             monster_type berserkers[] = { MONS_POLAR_BEAR, MONS_ELEPHANT,
5846                                           MONS_DEATH_YAK };
5847             to_summon = RANDOM_ELEMENT(berserkers);
5848         }
5849         else
5850         {
5851             monster_type berserkers[] = { MONS_BLACK_BEAR, MONS_OGRE, MONS_TROLL,
5852                                            MONS_TWO_HEADED_OGRE, MONS_DEEP_TROLL };
5853             to_summon = RANDOM_ELEMENT(berserkers);
5854         }
5855 
5856         summon_berserker(power, mons, to_summon);
5857         mons->props["brothers_count"].get_int()++;
5858         return;
5859     }
5860 
5861     case SPELL_SYMBOL_OF_TORMENT:
5862         torment(mons, TORMENT_SPELL, mons->pos());
5863         return;
5864 
5865     case SPELL_MESMERISE:
5866         _mons_mesmerise(mons);
5867         return;
5868 
5869     case SPELL_CAUSE_FEAR:
5870         _mons_cause_fear(mons);
5871         return;
5872 
5873     case SPELL_OLGREBS_TOXIC_RADIANCE:
5874         cast_toxic_radiance(mons, splpow);
5875         return;
5876 
5877     case SPELL_SHATTER:
5878         mons_shatter(mons);
5879         return;
5880 
5881     case SPELL_CORPSE_ROT:
5882         corpse_rot(mons);
5883         return;
5884 
5885     case SPELL_SUMMON_GREATER_DEMON:
5886         duration  = min(2 + mons->spell_hd(spell_cast) / 10, 6);
5887 
5888         create_monster(
5889             mgen_data(summon_any_demon(RANDOM_DEMON_GREATER, true),
5890                       SAME_ATTITUDE(mons), mons->pos(), mons->foe)
5891             .set_summoned(mons, duration, spell_cast, god));
5892         return;
5893 
5894     // Journey -- Added in Summon Lizards
5895     case SPELL_SUMMON_DRAKES:
5896         sumcount2 = 1 + random2(mons->spell_hd(spell_cast) / 5 + 1);
5897 
5898         duration  = min(2 + mons->spell_hd(spell_cast) / 10, 6);
5899 
5900         {
5901             vector<monster_type> monsters;
5902 
5903             for (sumcount = 0; sumcount < sumcount2; ++sumcount)
5904             {
5905                 monster_type mon = _pick_drake();
5906                 monsters.push_back(mon);
5907             }
5908 
5909             for (monster_type type : monsters)
5910             {
5911                 create_monster(
5912                     mgen_data(type, SAME_ATTITUDE(mons), mons->pos(),
5913                               mons->foe)
5914                     .set_summoned(mons, duration, spell_cast, god));
5915             }
5916         }
5917         return;
5918 
5919     case SPELL_DRUIDS_CALL:
5920         _cast_druids_call(mons);
5921         return;
5922 
5923     case SPELL_BATTLESPHERE:
5924         cast_battlesphere(mons, min(splpow, 200), mons->god, false);
5925         return;
5926 
5927     case SPELL_POLAR_VORTEX:
5928     {
5929         _mons_vortex(mons);
5930         return;
5931     }
5932 
5933     case SPELL_SUMMON_HOLIES: // Holy monsters.
5934         sumcount2 = 1 + random2(2); // sequence point
5935         sumcount2 += random2(mons->spell_hd(spell_cast) / 4 + 1);
5936 
5937         duration  = min(2 + mons->spell_hd(spell_cast) / 5, 6);
5938         for (int i = 0; i < sumcount2; ++i)
5939         {
5940             create_monster(
5941                 mgen_data(random_choose_weighted(
5942                             100, MONS_ANGEL,     80,  MONS_CHERUB,
5943                             50,  MONS_DAEVA,      1,  MONS_OPHAN),
5944                           SAME_ATTITUDE(mons), mons->pos(), mons->foe)
5945                 .set_summoned(mons, duration, spell_cast, god));
5946         }
5947         return;
5948 
5949     case SPELL_BLINK_OTHER:
5950     {
5951         // Allow the caster to comment on moving the foe.
5952         string msg = getSpeakString(mons->name(DESC_PLAIN) + " blink_other");
5953         if (!msg.empty() && msg != "__NONE")
5954         {
5955             mons_speaks_msg(mons, msg, MSGCH_TALK,
5956                             silenced(you.pos()) || silenced(mons->pos()));
5957         }
5958         break;
5959     }
5960 
5961     case SPELL_BLINK_OTHER_CLOSE:
5962     {
5963         // Allow the caster to comment on moving the foe.
5964         string msg = getSpeakString(mons->name(DESC_PLAIN)
5965                                     + " blink_other_close");
5966         if (!msg.empty() && msg != "__NONE")
5967         {
5968             mons_speaks_msg(mons, msg, MSGCH_TALK,
5969                             silenced(you.pos()) || silenced(mons->pos()));
5970         }
5971         break;
5972     }
5973 
5974     case SPELL_TOMB_OF_DOROKLOHE:
5975     {
5976         sumcount = 0;
5977 
5978         const int hp_lost = mons->max_hit_points - mons->hit_points;
5979 
5980         if (!hp_lost)
5981             sumcount++;
5982 
5983         static const set<dungeon_feature_type> safe_tiles =
5984         {
5985             DNGN_SHALLOW_WATER, DNGN_FLOOR, DNGN_OPEN_DOOR,
5986             DNGN_OPEN_CLEAR_DOOR
5987         };
5988 
5989         for (adjacent_iterator ai(mons->pos()); ai; ++ai)
5990         {
5991             const actor* act = actor_at(*ai);
5992 
5993             // We can blink away the crowd, but only our allies.
5994             if (act
5995                 && (act->is_player()
5996                     || (act->is_monster()
5997                         && act->as_monster()->attitude != mons->attitude)))
5998             {
5999                 sumcount++;
6000             }
6001 
6002             // Make sure we have a legitimate tile.
6003             if (!safe_tiles.count(env.grid(*ai)) && !feat_is_trap(env.grid(*ai))
6004                 && feat_is_reachable_past(env.grid(*ai)))
6005             {
6006                 sumcount++;
6007             }
6008         }
6009 
6010         if (sumcount)
6011         {
6012             mons->blink();
6013             return;
6014         }
6015 
6016         sumcount = 0;
6017         for (adjacent_iterator ai(mons->pos()); ai; ++ai)
6018         {
6019             if (monster_at(*ai))
6020             {
6021                 monster_at(*ai)->blink();
6022                 if (monster_at(*ai))
6023                 {
6024                     monster_at(*ai)->teleport(true);
6025                     if (monster_at(*ai))
6026                         continue;
6027                 }
6028             }
6029 
6030             // Make sure we have a legitimate tile.
6031             if (safe_tiles.count(env.grid(*ai)) || feat_is_trap(env.grid(*ai)))
6032             {
6033                 // All items are moved inside.
6034                 if (env.igrid(*ai) != NON_ITEM)
6035                     move_items(*ai, mons->pos());
6036 
6037                 // All clouds are destroyed.
6038                 delete_cloud(*ai);
6039 
6040                 // All traps are destroyed.
6041                 if (trap_def *ptrap = trap_at(*ai))
6042                     ptrap->destroy();
6043 
6044                 // Actually place the wall.
6045                 temp_change_terrain(*ai, DNGN_ROCK_WALL, INFINITE_DURATION,
6046                                     TERRAIN_CHANGE_TOMB, mons);
6047                 sumcount++;
6048             }
6049         }
6050 
6051         if (sumcount)
6052         {
6053             mpr("Walls emerge from the floor!");
6054 
6055             // XXX: Assume that the entombed monster can regenerate.
6056             // Also, base the regeneration rate on HD to avoid
6057             // randomness.
6058             const int tomb_duration = BASELINE_DELAY
6059                 * hp_lost * max(1, mons->spell_hd(spell_cast) / 3);
6060             int mon_index = mons->mindex();
6061             env.markers.add(new map_tomb_marker(mons->pos(),
6062                                                 tomb_duration,
6063                                                 mon_index,
6064                                                 mon_index));
6065             env.markers.clear_need_activate(); // doesn't need activation
6066         }
6067         return;
6068     }
6069 
6070     case SPELL_CHAIN_LIGHTNING:
6071         cast_chain_lightning(splpow, *mons, false);
6072         return;
6073 
6074     case SPELL_CHAIN_OF_CHAOS:
6075         cast_chain_spell(spell_cast, splpow, mons);
6076         return;
6077 
6078     case SPELL_SUMMON_EYEBALLS:
6079         sumcount2 = 1 + random2(mons->spell_hd(spell_cast) / 7 + 1);
6080 
6081         duration = min(2 + mons->spell_hd(spell_cast) / 10, 6);
6082 
6083         for (sumcount = 0; sumcount < sumcount2; sumcount++)
6084         {
6085             const monster_type mon = random_choose_weighted(
6086                                        100, MONS_FLOATING_EYE,
6087                                         60, MONS_GOLDEN_EYE,
6088                                         40, MONS_SHINING_EYE,
6089                                         20, MONS_GREAT_ORB_OF_EYES,
6090                                         10, MONS_EYE_OF_DEVASTATION);
6091 
6092             create_monster(
6093                 mgen_data(mon, SAME_ATTITUDE(mons), mons->pos(), mons->foe)
6094                 .set_summoned(mons, duration, spell_cast, god));
6095         }
6096         return;
6097 
6098     case SPELL_IOOD:
6099         cast_iood(mons, splpow, &pbolt);
6100         return;
6101 
6102     case SPELL_AWAKEN_FOREST:
6103         if (!mons->friendly() && have_passive(passive_t::friendly_plants))
6104         {
6105             if (you.can_see(*mons))
6106             {
6107                 mprf("%s commands the forest to attack, but nothing happens.",
6108                      mons->name(DESC_THE).c_str());
6109             }
6110             return;
6111         }
6112 
6113         duration = 50 + random2(mons->spell_hd(spell_cast) * 20);
6114 
6115         mons->add_ench(mon_enchant(ENCH_AWAKEN_FOREST, 0, mons, duration));
6116         // Actually, it's a boolean marker... save for a sanity check.
6117         env.forest_awoken_until = you.elapsed_time + duration;
6118 
6119         // You may be unable to see the monster, but notice an affected tree.
6120         forest_message(mons->pos(), "The forest starts to sway and rumble!");
6121         return;
6122 
6123     case SPELL_SUMMON_DRAGON:
6124         cast_summon_dragon(mons, splpow, god);
6125         return;
6126 
6127     case SPELL_SUMMON_HYDRA:
6128         cast_summon_hydra(mons, splpow, god);
6129         return;
6130 
6131     case SPELL_SUMMON_LIGHTNING_SPIRE:
6132     {
6133         monster* spire = _summon(*mons, MONS_LIGHTNING_SPIRE, 2, slot);
6134         if (spire && !silenced(spire->pos()))
6135             mpr("An electric hum fills the air.");
6136         return;
6137     }
6138 
6139     case SPELL_FIRE_SUMMON:
6140         sumcount2 = 1 + random2(mons->spell_hd(spell_cast) / 5 + 1);
6141 
6142         duration = min(2 + mons->spell_hd(spell_cast) / 10, 6);
6143 
6144         for (sumcount = 0; sumcount < sumcount2; sumcount++)
6145         {
6146             const monster_type mon = random_choose_weighted(
6147                                        3, MONS_BALRUG,
6148                                        2, MONS_HELLION,
6149                                        1, MONS_BRIMSTONE_FIEND);
6150 
6151             create_monster(
6152                 mgen_data(mon, SAME_ATTITUDE(mons), mons->pos(), mons->foe)
6153                 .set_summoned(mons, duration, spell_cast, god));
6154         }
6155         return;
6156 
6157     case SPELL_SUMMON_TZITZIMITL:
6158         _summon(*mons, MONS_TZITZIMITL, 2, slot);
6159         return;
6160 
6161     case SPELL_SUMMON_HELL_SENTINEL:
6162         _summon(*mons, MONS_HELL_SENTINEL, 2, slot);
6163         return;
6164 
6165     case SPELL_WORD_OF_RECALL:
6166     {
6167         mon_enchant chant_timer = mon_enchant(ENCH_WORD_OF_RECALL, 1, mons, 30);
6168         mons->add_ench(chant_timer);
6169         return;
6170     }
6171 
6172     case SPELL_INJURY_BOND:
6173     {
6174         simple_monster_message(*mons,
6175             make_stringf(" begins to accept %s allies' injuries.",
6176                          mons->pronoun(PRONOUN_POSSESSIVE).c_str()).c_str());
6177         // FIXME: allies preservers vs the player
6178         for (monster_near_iterator mi(mons, LOS_NO_TRANS); mi; ++mi)
6179         {
6180             if (mons_aligned(mons, *mi) && !mi->has_ench(ENCH_CHARM)
6181                 && !mi->has_ench(ENCH_HEXED) && *mi != mons)
6182             {
6183                 mon_enchant bond = mon_enchant(ENCH_INJURY_BOND, 1, mons,
6184                                                40 + random2(80));
6185                 mi->add_ench(bond);
6186             }
6187         }
6188 
6189         return;
6190     }
6191 
6192     case SPELL_CALL_LOST_SOUL:
6193         create_monster(mgen_data(MONS_LOST_SOUL, SAME_ATTITUDE(mons),
6194                                  mons->pos(), mons->foe)
6195                        .set_summoned(mons, 2, spell_cast, god));
6196         return;
6197 
6198     case SPELL_BLINK_ALLIES_ENCIRCLE:
6199         _blink_allies_encircle(mons);
6200         return;
6201 
6202     case SPELL_MASS_CONFUSION:
6203         _mons_mass_confuse(mons);
6204         return;
6205 
6206     case SPELL_ENGLACIATION:
6207         if (you.can_see(*mons))
6208             simple_monster_message(*mons, " radiates an aura of cold.");
6209         else if (mons->see_cell_no_trans(you.pos()))
6210             mpr("A wave of cold passes over you.");
6211         apply_area_visible([splpow, mons] (coord_def where) {
6212             return englaciate(where, min(splpow, 200), mons);
6213         }, mons->pos());
6214         return;
6215 
6216     case SPELL_AWAKEN_VINES:
6217         _awaken_vines(mons);
6218         return;
6219 
6220     case SPELL_WALL_OF_BRAMBLES:
6221         // If we can't cast this for some reason (can be expensive to determine
6222         // at every call to _monster_spell_goodness), refund the energy for it so that
6223         // the caster can do something else
6224         if (!_wall_of_brambles(mons))
6225         {
6226             mons->speed_increment +=
6227                 get_monster_data(mons->type)->energy_usage.spell;
6228         }
6229         return;
6230 
6231     case SPELL_WIND_BLAST:
6232     {
6233         // Wind blast is stopped by FFT_SOLID features.
6234         if (foe && cell_see_cell(mons->pos(), foe->pos(), LOS_SOLID))
6235             wind_blast(mons, splpow, foe->pos());
6236         return;
6237     }
6238 
6239     case SPELL_FREEZE:
6240         _mons_cast_freeze(mons);
6241         return;
6242 
6243     case SPELL_SUMMON_VERMIN:
6244         _do_high_level_summon(mons, spell_cast, _pick_vermin,
6245                               one_chance_in(4) ? 3 : 2 , god);
6246         return;
6247 
6248     case SPELL_DISCHARGE:
6249         cast_discharge(min(200, splpow), *mons);
6250         return;
6251 
6252     case SPELL_PORTAL_PROJECTILE:
6253     {
6254         // Swap weapons if necessary so that that happens before the spell
6255         // casting message.
6256         item_def *launcher = nullptr;
6257         mons_usable_missile(mons, &launcher);
6258         const item_def *weapon = mons->mslot_item(MSLOT_WEAPON);
6259         if (launcher && launcher != weapon)
6260             mons->swap_weapons();
6261         mons_cast_noise(mons, pbolt, spell_cast, slot_flags);
6262         handle_throw(mons, pbolt, true, false);
6263         return;
6264     }
6265 
6266     case SPELL_IGNITE_POISON:
6267         cast_ignite_poison(mons, splpow, false);
6268         return;
6269 
6270     case SPELL_BLACK_MARK:
6271         _cast_black_mark(mons);
6272         return;
6273 
6274     case SPELL_BLINK_ALLIES_AWAY:
6275         _blink_allies_away(mons);
6276         return;
6277 
6278     case SPELL_GLACIATE:
6279     {
6280         ASSERT(foe);
6281         cast_glaciate(mons, splpow, foe->pos());
6282         return;
6283     }
6284 
6285     case SPELL_PHANTOM_MIRROR:
6286     {
6287         // Find appropriate ally to clone.
6288         vector<monster*> targets;
6289         for (monster_near_iterator mi(mons); mi; ++mi)
6290         {
6291             if (_mirrorable(mons, *mi))
6292                 targets.push_back(*mi);
6293         }
6294 
6295         // If we've found something, mirror it.
6296         if (targets.size())
6297         {
6298             monster* targ = targets[random2(targets.size())];
6299             if (cast_phantom_mirror(mons, targ))
6300                 simple_monster_message(*targ, " shimmers and seems to become two!");
6301         }
6302         return;
6303     }
6304 
6305     case SPELL_SUMMON_MANA_VIPER:
6306     {
6307         const int num_vipers = 1 + random2(mons->spell_hd(spell_cast) / 5 + 1);
6308         for (int i = 0; i < num_vipers; ++i)
6309             _summon(*mons, MONS_MANA_VIPER, 2, slot);
6310         return;
6311     }
6312 
6313     case SPELL_SUMMON_EMPEROR_SCORPIONS:
6314     {
6315         const int num_scorps = 1 + random2(mons->spell_hd(spell_cast) / 5 + 1);
6316         for (int i = 0; i < num_scorps; ++i)
6317             _summon(*mons, MONS_EMPEROR_SCORPION, 5, slot);
6318         return;
6319     }
6320 
6321     case SPELL_BATTLECRY:
6322         _battle_cry(*mons);
6323         return;
6324 
6325     case SPELL_WARNING_CRY:
6326         return; // the entire point is the noise, handled elsewhere
6327 
6328     case SPELL_SEAL_DOORS:
6329         _seal_doors_and_stairs(mons);
6330         return;
6331 
6332     case SPELL_BERSERK_OTHER:
6333         _incite_monsters(mons, true);
6334         return;
6335 
6336     case SPELL_SPELLFORGED_SERVITOR:
6337     {
6338         monster* servitor = _summon(*mons, MONS_SPELLFORGED_SERVITOR, 4, slot);
6339         if (servitor)
6340             init_servitor(servitor, mons);
6341         else if (you.can_see(*mons))
6342             canned_msg(MSG_NOTHING_HAPPENS);
6343         return;
6344     }
6345 
6346     case SPELL_CORRUPTING_PULSE:
6347         _corrupting_pulse(mons);
6348         return;
6349 
6350     case SPELL_THROW_ALLY:
6351         _maybe_throw_ally(*mons);
6352         return;
6353 
6354     case SPELL_SIREN_SONG:
6355         _siren_sing(mons, false);
6356         return;
6357 
6358     case SPELL_AVATAR_SONG:
6359         _siren_sing(mons, true);
6360         return;
6361 
6362     case SPELL_REPEL_MISSILES:
6363         simple_monster_message(*mons, " begins repelling missiles!");
6364         mons->add_ench(mon_enchant(ENCH_REPEL_MISSILES));
6365         return;
6366 
6367     case SPELL_SUMMON_SCARABS:
6368     {
6369         const int num_scarabs = 1 + random2(mons->spell_hd(spell_cast) / 5 + 1);
6370         for (int i = 0; i < num_scarabs; ++i)
6371             _summon(*mons, MONS_DEATH_SCARAB, 2, slot);
6372         return;
6373     }
6374 
6375     case SPELL_CLEANSING_FLAME:
6376         simple_monster_message(*mons, " channels a blast of cleansing flame!");
6377         cleansing_flame(5 + (5 * mons->spell_hd(spell_cast) / 12),
6378                         cleansing_flame_source::spell, mons->pos(), mons);
6379         return;
6380 
6381     case SPELL_GRAVITAS:
6382         ASSERT(foe);
6383         fatal_attraction(foe->pos(), mons, splpow);
6384         return;
6385 
6386     case SPELL_ENTROPIC_WEAVE:
6387         ASSERT(foe);
6388         foe->corrode_equipment("the entropic weave");
6389         return;
6390 
6391     case SPELL_SUMMON_EXECUTIONERS:
6392     {
6393         const int num_exec = 1 + random2(mons->spell_hd(spell_cast) / 5 + 1);
6394         duration = min(2 + mons->spell_hd(spell_cast) / 10, 6);
6395         for (int i = 0; i < num_exec; ++i)
6396             _summon(*mons, MONS_EXECUTIONER, duration, slot);
6397         return;
6398     }
6399 
6400     case SPELL_DOOM_HOWL:
6401         _doom_howl(*mons);
6402         break;
6403 
6404     case SPELL_CALL_OF_CHAOS:
6405         _mons_call_of_chaos(*mons);
6406         return;
6407 
6408     case SPELL_AURA_OF_BRILLIANCE:
6409         simple_monster_message(*mons, " begins emitting a brilliant aura!");
6410         mons->add_ench(ENCH_BRILLIANCE_AURA);
6411         aura_of_brilliance(mons);
6412         return;
6413 
6414     case SPELL_BIND_SOULS:
6415         simple_monster_message(*mons, " binds the souls of nearby monsters.");
6416         for (monster_near_iterator mi(mons, LOS_NO_TRANS); mi; ++mi)
6417         {
6418             if (*mi == mons)
6419                 continue;
6420             if (_mons_can_bind_soul(mons, *mi))
6421             {
6422                 mi->add_ench(
6423                     mon_enchant(ENCH_BOUND_SOUL, 0, mons,
6424                                 random_range(10, 30) * BASELINE_DELAY));
6425             }
6426         }
6427         return;
6428 
6429 
6430     case SPELL_GREATER_SERVANT_MAKHLEB:
6431     {
6432         const monster_type servants[] = { MONS_EXECUTIONER, MONS_GREEN_DEATH,
6433                                           MONS_BLIZZARD_DEMON, MONS_BALRUG,
6434                                           MONS_CACODEMON };
6435         _summon(*mons, RANDOM_ELEMENT(servants), 5, slot);
6436         return;
6437     }
6438 
6439     case SPELL_UPHEAVAL:
6440         _mons_upheaval(*mons, *foe, true);
6441         return;
6442 
6443     case SPELL_ERUPTION:
6444         _mons_upheaval(*mons, *foe, false);
6445         return;
6446 
6447     case SPELL_SPORULATE:
6448     {
6449         mgen_data mgen (MONS_BALLISTOMYCETE_SPORE,
6450                 mons->friendly() ? BEH_FRIENDLY : BEH_HOSTILE, mons->pos(),
6451                 mons->foe);
6452         mgen.set_summoned(mons, 0, SPELL_SPORULATE);
6453         // Add 1HD to the spore for each additional HD the spawner has.
6454         mgen.hd = mons_class_hit_dice(MONS_BALLISTOMYCETE_SPORE) +
6455             max(0, mons->spell_hd() - mons_class_hit_dice(mons->type));
6456 
6457         if (monster* const spore = create_monster(mgen))
6458             spore->add_ench(ENCH_SHORT_LIVED);
6459 
6460         return;
6461     }
6462 
6463     case SPELL_ROLL:
6464         mons->add_ench(ENCH_ROLLING);
6465         simple_monster_message(*mons,
6466                 " curls into a ball and begins rolling!");
6467         return;
6468 
6469     case SPELL_GOAD_BEASTS:
6470         _cast_goad_beasts(mons);
6471         return;
6472 
6473     }
6474 
6475     if (spell_is_direct_explosion(spell_cast))
6476         _fire_direct_explosion(*mons, slot, pbolt);
6477     else
6478         _fire_simple_beam(*mons, slot, pbolt);
6479 }
6480 
_noise_level(const monster * mons,spell_type spell,bool silent,mon_spell_slot_flags slot_flags)6481 static int _noise_level(const monster* mons, spell_type spell,
6482                         bool silent, mon_spell_slot_flags slot_flags)
6483 {
6484     const spell_flags flags = get_spell_flags(spell);
6485 
6486     int noise;
6487 
6488     if (silent
6489         || (slot_flags & MON_SPELL_INNATE_MASK
6490             && !(slot_flags & MON_SPELL_NOISY)
6491             && !(flags & spflag::noisy)))
6492     {
6493         noise = 0;
6494     }
6495     else if (mons_genus(mons->type) == MONS_DRAGON)
6496         noise = get_shout_noise_level(S_LOUD_ROAR);
6497     else
6498         noise = spell_noise(spell);
6499 
6500     return noise;
6501 }
6502 
_speech_keys(vector<string> & key_list,const monster * mons,const bolt & pbolt,spell_type spell,mon_spell_slot_flags slot_flags,bool targeted)6503 static void _speech_keys(vector<string>& key_list,
6504                          const monster* mons, const bolt& pbolt,
6505                          spell_type spell, mon_spell_slot_flags slot_flags,
6506                          bool targeted)
6507 {
6508     const string cast_str = " cast";
6509 
6510     // Can't use copy-initialization 'wizard = slot_flags & ...' here,
6511     // because the bitfield-to-bool conversion is not implicit.
6512     const bool wizard  {slot_flags & MON_SPELL_WIZARD};
6513     const bool priest  {slot_flags & MON_SPELL_PRIEST};
6514     const bool natural {slot_flags & MON_SPELL_NATURAL
6515                         || slot_flags & MON_SPELL_VOCAL};
6516     const bool magical {slot_flags & MON_SPELL_MAGICAL};
6517 
6518     const mon_body_shape shape = get_mon_shape(*mons);
6519     const string    spell_name = spell_title(spell);
6520     const bool      real_spell = priest || wizard;
6521 
6522     // Before just using generic per-spell and per-monster casts, try
6523     // per-monster, per-spell, with the monster type name, then the
6524     // species name, then the genus name, then wizard/priest/magical/natural.
6525     // We don't include "real" or "gestures" here since that can be
6526     // be determined from the monster type; or "targeted" since that
6527     // can be determined from the spell.
6528     key_list.push_back(spell_name + " "
6529                        + mons_type_name(mons->type, DESC_PLAIN) + cast_str);
6530     key_list.push_back(spell_name + " "
6531                        + mons_type_name(mons_species(mons->type), DESC_PLAIN)
6532                        + cast_str);
6533     key_list.push_back(spell_name + " "
6534                        + mons_type_name(mons_genus(mons->type), DESC_PLAIN)
6535                        + cast_str);
6536     if (wizard)
6537     {
6538         key_list.push_back(make_stringf("%s %swizard%s",
6539                                spell_name.c_str(),
6540                                mon_shape_is_humanoid(shape) ? ""
6541                                                             : "non-humanoid ",
6542                                cast_str.c_str()));
6543     }
6544     else if (priest)
6545         key_list.push_back(spell_name + " priest" + cast_str);
6546     else if (magical)
6547         key_list.push_back(spell_name + " magical" + cast_str);
6548     else if (natural)
6549         key_list.push_back(spell_name + " natural" + cast_str);
6550 
6551 
6552     // Now try just the spell's name.
6553     if (mon_shape_is_humanoid(shape))
6554     {
6555         if (real_spell)
6556             key_list.push_back(spell_name + cast_str + " real");
6557         if (mons_intel(*mons) >= I_HUMAN)
6558             key_list.push_back(spell_name + cast_str + " gestures");
6559     }
6560 
6561     key_list.push_back(spell_name + cast_str);
6562 
6563     // Only postfix "targeted" after this point.
6564     const unsigned int num_spell_keys = key_list.size();
6565 
6566     // Next the monster type name, then species name, then genus name.
6567     key_list.push_back(mons_type_name(mons->type, DESC_PLAIN) + cast_str);
6568     key_list.push_back(mons_type_name(mons_species(mons->type), DESC_PLAIN)
6569                        + cast_str);
6570     key_list.push_back(mons_type_name(mons_genus(mons->type), DESC_PLAIN)
6571                        + cast_str);
6572 
6573     // Last, generic wizard, priest or magical.
6574     if (wizard)
6575     {
6576         key_list.push_back(make_stringf("%swizard%s",
6577                                mon_shape_is_humanoid(shape) ? ""
6578                                                             : "non-humanoid ",
6579                                cast_str.c_str()));
6580     }
6581     else if (priest)
6582         key_list.push_back("priest" + cast_str);
6583     else if (magical)
6584         key_list.push_back("magical" + cast_str);
6585 
6586     if (targeted)
6587     {
6588         // For targeted spells, try with the targeted suffix first.
6589         for (unsigned int i = key_list.size() - 1; i >= num_spell_keys; i--)
6590         {
6591             string str = key_list[i] + " targeted";
6592             key_list.insert(key_list.begin() + i, str);
6593         }
6594 
6595         // Generic beam messages.
6596         if (pbolt.visible())
6597         {
6598             key_list.push_back(pbolt.get_short_name() + " beam " + cast_str);
6599             key_list.emplace_back("beam catchall cast");
6600         }
6601     }
6602 }
6603 
_speech_message(const monster & mon,const vector<string> & key_list,bool silent,bool unseen)6604 static string _speech_message(const monster &mon,
6605                               const vector<string>& key_list,
6606                               bool silent, bool unseen)
6607 {
6608     string prefix;
6609     if (silent)
6610         prefix = "silent ";
6611     else if (unseen)
6612         prefix = "unseen ";
6613 
6614     string msg;
6615     for (const string &key : key_list)
6616     {
6617 #ifdef DEBUG_MONSPEAK
6618         dprf(DIAG_SPEECH, "monster casting lookup: %s%s",
6619              prefix.c_str(), key.c_str());
6620 #endif
6621 
6622         msg = getSpeakString(prefix + key);
6623 
6624         if (msg == "__NONE")
6625         {
6626             msg = "";
6627             break;
6628         }
6629 
6630         if (!msg.empty() && !invalid_msg(mon, msg))
6631             break;
6632 
6633         // If we got no message and we're using the silent prefix, then
6634         // try again without the prefix.
6635         if (prefix != "silent ")
6636             continue;
6637 
6638         msg = getSpeakString(key);
6639         if (msg == "__NONE")
6640         {
6641             msg = "";
6642             break;
6643         }
6644         else if (!msg.empty())
6645             break;
6646     }
6647 
6648     return msg;
6649 }
6650 
_speech_fill_target(string & targ_prep,string & target,const monster * mons,const bolt & pbolt,bool gestured)6651 static void _speech_fill_target(string& targ_prep, string& target,
6652                                 const monster* mons, const bolt& pbolt,
6653                                 bool gestured)
6654 {
6655     targ_prep = "at";
6656     target    = "nothing";
6657 
6658     bolt tracer = pbolt;
6659     // For a targeted but rangeless spell make the range positive so that
6660     // fire_tracer() will fill out path_taken.
6661     if (pbolt.range == 0 && pbolt.target != mons->pos())
6662         tracer.range = ENV_SHOW_DIAMETER;
6663     fire_tracer(mons, tracer);
6664 
6665     if (pbolt.target == you.pos())
6666         target = "you";
6667     else if (pbolt.target == mons->pos())
6668         target = mons->pronoun(PRONOUN_REFLEXIVE);
6669     // Monsters should only use targeted spells while foe == MHITNOT
6670     // if they're targeting themselves.
6671     else if (mons->foe == MHITNOT && !mons_is_confused(*mons, true))
6672         target = "NONEXISTENT FOE";
6673     else if (!invalid_monster_index(mons->foe)
6674              && env.mons[mons->foe].type == MONS_NO_MONSTER)
6675     {
6676         target = "DEAD FOE";
6677     }
6678     else if (in_bounds(pbolt.target) && you.see_cell(pbolt.target))
6679     {
6680         if (const monster* mtarg = monster_at(pbolt.target))
6681         {
6682             if (you.can_see(*mtarg))
6683                 target = mtarg->name(DESC_THE);
6684         }
6685     }
6686 
6687     const bool visible_path      = pbolt.visible() || gestured;
6688 
6689     // Monster might be aiming past the real target, or maybe some fuzz has
6690     // been applied because the target is invisible.
6691     if (target == "nothing")
6692     {
6693         if (pbolt.aimed_at_spot || pbolt.origin_spell == SPELL_DIG)
6694         {
6695             int count = 0;
6696             for (adjacent_iterator ai(pbolt.target); ai; ++ai)
6697             {
6698                 const actor* act = actor_at(*ai);
6699                 if (act && act != mons && you.can_see(*act))
6700                 {
6701                     targ_prep = "next to";
6702 
6703                     if (act->is_player() || one_chance_in(++count))
6704                         target = act->name(DESC_THE);
6705 
6706                     if (act->is_player())
6707                         break;
6708                 }
6709             }
6710 
6711             if (targ_prep == "at")
6712             {
6713                 if (env.grid(pbolt.target) != DNGN_FLOOR)
6714                 {
6715                     target = feature_description(env.grid(pbolt.target),
6716                                                  NUM_TRAPS, "", DESC_THE);
6717                 }
6718                 else
6719                     target = "thin air";
6720             }
6721 
6722             return;
6723         }
6724 
6725         bool mons_targ_aligned = false;
6726 
6727         for (const coord_def &pos : tracer.path_taken)
6728         {
6729             if (pos == mons->pos())
6730                 continue;
6731 
6732             const monster* m = monster_at(pos);
6733             if (pos == you.pos())
6734             {
6735                 // Be egotistical and assume that the monster is aiming at
6736                 // the player, rather than the player being in the path of
6737                 // a beam aimed at an ally.
6738                 if (!mons->wont_attack())
6739                 {
6740                     targ_prep = "at";
6741                     target    = "you";
6742                     break;
6743                 }
6744                 // If the ally is confused or aiming at an invisible enemy,
6745                 // with the player in the path, act like it's targeted at
6746                 // the player if there isn't any visible target earlier
6747                 // in the path.
6748                 else if (target == "nothing")
6749                 {
6750                     targ_prep         = "at";
6751                     target            = "you";
6752                     mons_targ_aligned = true;
6753                 }
6754             }
6755             else if (visible_path && m && you.can_see(*m))
6756             {
6757                 bool is_aligned  = mons_aligned(m, mons);
6758                 string name = m->name(DESC_THE);
6759 
6760                 if (target == "nothing")
6761                 {
6762                     mons_targ_aligned = is_aligned;
6763                     target            = name;
6764                 }
6765                 // If the first target was aligned with the beam source then
6766                 // the first subsequent non-aligned monster in the path will
6767                 // take it's place.
6768                 else if (mons_targ_aligned && !is_aligned)
6769                 {
6770                     mons_targ_aligned = false;
6771                     target            = name;
6772                 }
6773                 targ_prep = "at";
6774             }
6775             else if (visible_path && target == "nothing")
6776             {
6777                 int count = 0;
6778                 for (adjacent_iterator ai(pbolt.target); ai; ++ai)
6779                 {
6780                     const actor* act = monster_at(*ai);
6781                     if (act && act != mons && you.can_see(*act))
6782                     {
6783                         targ_prep = "past";
6784                         if (act->is_player()
6785                             || one_chance_in(++count))
6786                         {
6787                             target = act->name(DESC_THE);
6788                         }
6789 
6790                         if (act->is_player())
6791                             break;
6792                     }
6793                 }
6794             }
6795         } // for (const coord_def pos : path)
6796     } // if (target == "nothing" && targeted)
6797 
6798     const actor* foe = mons->get_foe();
6799 
6800     // If we still can't find what appears to be the target, and the
6801     // monster isn't just throwing the spell in a random direction,
6802     // we should be able to tell what the monster was aiming for if
6803     // we can see the monster's foe and the beam (or the beam path
6804     // implied by gesturing). But only if the beam didn't actually hit
6805     // anything (but if it did hit something, why didn't that monster
6806     // show up in the beam's path?)
6807     if (target == "nothing"
6808         && (tracer.foe_info.count + tracer.friend_info.count) == 0
6809         && foe != nullptr
6810         && you.can_see(*foe)
6811         && !mons->confused()
6812         && visible_path)
6813     {
6814         target = foe->name(DESC_THE);
6815         targ_prep = (pbolt.aimed_at_spot ? "next to" : "past");
6816     }
6817 
6818     // If the monster gestures to create an invisible beam then
6819     // assume that anything close to the beam is the intended target.
6820     // Also, if the monster gestures to create a visible beam but it
6821     // misses still say that the monster gestured "at" the target,
6822     // rather than "past".
6823     if (gestured || target == "nothing")
6824         targ_prep = "at";
6825 
6826     // "throws whatever at something" is better than "at nothing"
6827     if (target == "nothing")
6828         target = "something";
6829 }
6830 
mons_cast_noise(monster * mons,const bolt & pbolt,spell_type spell_cast,mon_spell_slot_flags slot_flags)6831 void mons_cast_noise(monster* mons, const bolt &pbolt,
6832                      spell_type spell_cast, mon_spell_slot_flags slot_flags)
6833 {
6834     const bool unseen = !you.can_see(*mons);
6835     const bool silent = silenced(mons->pos());
6836 
6837     if (unseen && silent)
6838         return;
6839 
6840     int noise = _noise_level(mons, spell_cast, silent, slot_flags);
6841 
6842     const spell_flags spflags = get_spell_flags(spell_cast);
6843     const bool targeted = bool(spflags & spflag::targeting_mask);
6844 
6845     vector<string> key_list;
6846     _speech_keys(key_list, mons, pbolt, spell_cast, slot_flags, targeted);
6847 
6848     string msg = _speech_message(*mons, key_list, silent, unseen);
6849 
6850     if (msg.empty())
6851     {
6852         if (silent)
6853             return;
6854 
6855         noisy(noise, mons->pos(), mons->mid);
6856         return;
6857     }
6858 
6859     // FIXME: we should not need to look at the message text.
6860     const bool gestured = msg.find("Gesture") != string::npos
6861                           || msg.find(" gesture") != string::npos
6862                           || msg.find("Point") != string::npos
6863                           || msg.find(" point") != string::npos;
6864 
6865     string targ_prep = "at";
6866     string target    = "NO_TARGET";
6867 
6868     if (targeted)
6869         _speech_fill_target(targ_prep, target, mons, pbolt, gestured);
6870 
6871     msg = replace_all(msg, "@at@",     targ_prep);
6872     msg = replace_all(msg, "@target@", target);
6873 
6874     string beam_name;
6875     if (!targeted)
6876         beam_name = "NON TARGETED BEAM";
6877     else if (pbolt.name.empty())
6878         beam_name = "INVALID BEAM";
6879     else
6880         beam_name = pbolt.get_short_name();
6881 
6882     msg = replace_all(msg, "@beam@", beam_name);
6883 
6884     const msg_channel_type chan =
6885         (unseen              ? MSGCH_SOUND :
6886          mons->friendly()    ? MSGCH_FRIEND_SPELL
6887                              : MSGCH_MONSTER_SPELL);
6888 
6889     if (silent || noise == 0)
6890         mons_speaks_msg(mons, msg, chan, true);
6891     else if (noisy(noise, mons->pos(), mons->mid) || !unseen)
6892     {
6893         // noisy() returns true if the player heard the noise.
6894         mons_speaks_msg(mons, msg, chan);
6895     }
6896 }
6897 
6898 static const int MIN_THROW_DIST = 2;
6899 
_valid_throw_dest(const actor & thrower,const actor & victim,const coord_def pos)6900 static bool _valid_throw_dest(const actor &thrower, const actor &victim,
6901                               const coord_def pos)
6902 {
6903     return thrower.pos().distance_from(pos) >= MIN_THROW_DIST
6904            && !actor_at(pos)
6905            && victim.is_habitable(pos)
6906            && thrower.see_cell(pos);
6907 }
6908 
6909 /**
6910  * Choose a landing site for a monster that is throwing someone.
6911  *
6912  * @param thrower      The monster performing the toss.
6913  * @param victim       The actor being thrown.
6914  * @param rater        A function that takes thrower, victim, and an arbitrary
6915  *                     coord_def and determines how good the throw is; a higher
6916  *                     number is better.
6917  * @return             The coord_def of one of the best (as determined by rater)
6918  *                     possible landing sites for a toss.
6919  *                     If no valid site is found, returns the origin (0,0).
6920  */
_choose_throwing_target(const monster & thrower,const actor & victim,function<int (const monster &,const actor &,coord_def)> rater)6921 static coord_def _choose_throwing_target(const monster &thrower,
6922                             const actor &victim,
6923                             function<int (const monster&, const actor&,
6924                                           coord_def)> rater)
6925 {
6926     int best_site_score = -1;
6927     vector<coord_def> best_sites;
6928 
6929     for (distance_iterator di(thrower.pos(), true, true, LOS_RADIUS); di; ++di)
6930     {
6931         ray_def ray;
6932         // Unusable landing sites.
6933         if (!_valid_throw_dest(thrower, victim, *di)
6934             || !find_ray(thrower.pos(), *di, ray, opc_solid_see))
6935         {
6936             continue;
6937         }
6938 
6939         const int site_score = rater(thrower, victim, *di);
6940         if (site_score > best_site_score)
6941         {
6942             best_site_score = site_score;
6943             best_sites.clear();
6944         }
6945         if (site_score == best_site_score)
6946             best_sites.push_back(*di);
6947     }
6948 
6949     // No valid landing site found.
6950     if (!best_sites.size())
6951         return coord_def(0,0);
6952 
6953     const coord_def best_site = best_sites[random2(best_sites.size())];
6954     return best_site;
6955 }
6956 
_will_throw_ally(const monster & thrower,const monster & throwee)6957 static bool _will_throw_ally(const monster& thrower, const monster& throwee)
6958 {
6959     switch (thrower.type)
6960     {
6961     case MONS_ROBIN:
6962         return throwee.mons_species() == MONS_GOBLIN;
6963     case MONS_POLYPHEMUS:
6964         return mons_genus(throwee.type) == MONS_YAK;
6965     case MONS_IRON_GIANT:
6966         return !mons_is_conjured(throwee.type);
6967     default:
6968         return false;
6969     }
6970 }
6971 
_find_ally_to_throw(const monster & mons)6972 static monster* _find_ally_to_throw(const monster &mons)
6973 {
6974     const actor *foe = mons.get_foe();
6975     if (!foe)
6976         return nullptr;
6977 
6978     int furthest_dist = -1;
6979 
6980     monster* best = nullptr;
6981     for (fair_adjacent_iterator ai(mons.pos(), true); ai; ++ai)
6982     {
6983         monster* throwee = monster_at(*ai);
6984 
6985         if (!throwee || !throwee->alive() || !mons_aligned(&mons, throwee)
6986             || !_will_throw_ally(mons, *throwee))
6987         {
6988             continue;
6989         }
6990 
6991         // Don't try to throw anything constricted.
6992         if (throwee->is_constricted())
6993             continue;
6994 
6995         // otherwise throw whoever's furthest from our target.
6996         const int dist = grid_distance(throwee->pos(), foe->pos());
6997         if (dist > furthest_dist)
6998         {
6999             best = throwee;
7000             furthest_dist = dist;
7001         }
7002     }
7003 
7004     if (best != nullptr)
7005         dprf("found a monster to toss");
7006     else
7007         dprf("couldn't find anyone to toss");
7008     return best;
7009 }
7010 
7011 /**
7012  * Toss an ally at the monster's foe, landing them in the given square after
7013  * maybe dealing a pittance of damage.
7014  *
7015  * XXX: some duplication with tentacle toss code
7016  *
7017  * @param thrower       The monster doing the throwing.
7018  * @param throwee       The monster being tossed.
7019  * @param chosen_dest   The location of the square throwee should land on.
7020  */
_throw_ally_to(const monster & thrower,monster & throwee,const coord_def chosen_dest)7021 static void _throw_ally_to(const monster &thrower, monster &throwee,
7022                            const coord_def chosen_dest)
7023 {
7024     ASSERT_IN_BOUNDS(chosen_dest);
7025     ASSERT(!throwee.is_constricted());
7026 
7027     actor* foe = thrower.get_foe();
7028     ASSERT(foe);
7029 
7030     const coord_def old_pos = throwee.pos();
7031     const bool thrower_seen = you.can_see(thrower);
7032     const bool throwee_was_seen = you.can_see(throwee);
7033     const bool throwee_will_be_seen = throwee.visible_to(&you)
7034                                       && you.see_cell(chosen_dest);
7035     const bool throwee_seen = throwee_was_seen || throwee_will_be_seen;
7036 
7037     if (!(throwee.flags & MF_WAS_IN_VIEW))
7038         throwee.seen_context = SC_THROWN_IN;
7039 
7040     if (thrower_seen || throwee_seen)
7041     {
7042         const string destination = you.can_see(*foe) ?
7043                                    make_stringf("at %s",
7044                                                 foe->name(DESC_THE).c_str()) :
7045                                    "out of sight";
7046 
7047         mprf("%s throws %s %s!",
7048              (thrower_seen ? thrower.name(DESC_THE).c_str() : "Something"),
7049              (throwee_seen ? throwee.name(DESC_THE, true).c_str() : "something"),
7050              destination.c_str());
7051 
7052         bolt beam;
7053         beam.range   = INFINITE_DISTANCE;
7054         beam.hit     = AUTOMATIC_HIT;
7055         beam.flavour = BEAM_VISUAL;
7056         beam.source  = thrower.pos();
7057         beam.target  = chosen_dest;
7058         beam.glyph   = mons_char(throwee.type);
7059         const monster_info mi(&throwee);
7060         beam.colour  = mi.colour();
7061 
7062         beam.draw_delay = 30; // Make beam animation somewhat slower than normal.
7063         beam.aimed_at_spot = true;
7064         beam.fire();
7065     }
7066 
7067     throwee.move_to_pos(chosen_dest);
7068     throwee.apply_location_effects(old_pos);
7069     throwee.check_redraw(old_pos);
7070 
7071     const string killed_by = make_stringf("Hit by %s thrown by %s",
7072                                           throwee.name(DESC_A, true).c_str(),
7073                                           thrower.name(DESC_PLAIN, true).c_str());
7074     const int dam = foe->apply_ac(random2(thrower.get_hit_dice() * 2));
7075     foe->hurt(&thrower, dam, BEAM_NONE, KILLED_BY_BEAM, "", killed_by, true);
7076 
7077     // wake sleepy goblins
7078     behaviour_event(&throwee, ME_DISTURB, &thrower, throwee.pos());
7079 }
7080 
_throw_ally_site_score(const monster & thrower,const actor &,coord_def pos)7081 static int _throw_ally_site_score(const monster& thrower, const actor& /*throwee*/,
7082                                   coord_def pos)
7083 {
7084     const actor *foe = thrower.get_foe();
7085     if (!foe || !adjacent(foe->pos(), pos))
7086         return -2;
7087     return grid_distance(thrower.pos(), pos);
7088 }
7089 
_maybe_throw_ally(const monster & mons)7090 static void _maybe_throw_ally(const monster &mons)
7091 {
7092     monster* throwee = _find_ally_to_throw(mons);
7093     if (!throwee)
7094         return;
7095 
7096     const coord_def toss_target =
7097         _choose_throwing_target(mons, *static_cast<actor*>(throwee),
7098                                 _throw_ally_site_score);
7099 
7100     if (toss_target.origin())
7101         return;
7102 
7103     _throw_ally_to(mons, *throwee, toss_target);
7104 }
7105 
7106 /**
7107  * Check if a siren or merfolk avatar should sing its song.
7108  *
7109  * @param mons   The singing monster.
7110  * @param avatar Whether to use the more powerful "avatar song".
7111  * @return       Whether the song should be sung.
7112  */
_siren_goodness(monster * mons,bool avatar)7113 static ai_action::goodness _siren_goodness(monster* mons, bool avatar)
7114 {
7115     // Don't behold observer in the arena.
7116     if (crawl_state.game_is_arena())
7117         return ai_action::impossible();
7118 
7119     // Don't behold player already half down or up the stairs.
7120     if (player_stair_delay())
7121     {
7122         dprf("Taking stairs, don't mesmerise.");
7123         return ai_action::impossible();
7124     }
7125 
7126     // Won't sing if either of you silenced, or it's friendly,
7127     // confused, fleeing, or leaving the level.
7128     if (mons->has_ench(ENCH_CONFUSION)
7129         || mons_is_fleeing(*mons)
7130         || mons->pacified()
7131         || mons->friendly()
7132         || !player_can_hear(mons->pos()))
7133     {
7134         return ai_action::bad();
7135     }
7136 
7137     // Don't even try on berserkers. Sirens know their limits.
7138     // (merfolk avatars should still sing since their song has other effects)
7139     if (!avatar && you.berserk())
7140         return ai_action::bad();
7141 
7142     // If the mer is trying to mesmerise you anew, only sing half as often.
7143     if (!you.beheld_by(*mons) && mons->foe == MHITYOU && you.can_see(*mons)
7144         && coinflip())
7145     {
7146         return ai_action::bad();
7147     }
7148 
7149     // We can do it!
7150     return ai_action::good();
7151 }
7152 
7153 /**
7154  * Have a monster attempt to cast Doom Howl.
7155  *
7156  * @param mon   The howling monster.
7157  */
_doom_howl(monster & mon)7158 static void _doom_howl(monster &mon)
7159 {
7160     mprf("%s unleashes a %s howl, and it begins to echo in your mind!",
7161          mon.name(DESC_THE).c_str(),
7162          silenced(mon.pos()) ? "silent" : "terrible");
7163     you.duration[DUR_DOOM_HOWL] = random_range(120, 180);
7164     mon.props[DOOM_HOUND_HOWLED_KEY] = true;
7165 }
7166 
7167 /**
7168  * Have a monster cast Awaken Earth.
7169  *
7170  * @param mon    The monster casting the spell.
7171  * @param target The target cell.
7172  */
_mons_awaken_earth(monster & mon,const coord_def & target)7173 static void _mons_awaken_earth(monster &mon, const coord_def &target)
7174 {
7175     if (!in_bounds(target))
7176     {
7177         if (you.can_see(mon))
7178             canned_msg(MSG_NOTHING_HAPPENS);
7179         return;
7180     }
7181 
7182     bool seen = false;
7183     int count = 0;
7184     const int max = 1 + (mon.spell_hd(SPELL_AWAKEN_EARTH) > 15)
7185                       + random2(mon.spell_hd(SPELL_AWAKEN_EARTH) / 7 + 1);
7186 
7187     for (fair_adjacent_iterator ai(target, false); ai; ++ai)
7188     {
7189         if (!_feat_is_awakenable(env.grid(*ai))
7190             || env.markers.property_at(*ai, MAT_ANY, "veto_destroy")
7191                == "veto")
7192         {
7193             continue;
7194         }
7195 
7196         destroy_wall(*ai);
7197         if (you.see_cell(*ai))
7198             seen = true;
7199 
7200         if (create_monster(mgen_data(
7201                 MONS_EARTH_ELEMENTAL, SAME_ATTITUDE((&mon)), *ai, mon.foe)
7202                 .set_summoned(&mon, 2, SPELL_AWAKEN_EARTH, mon.god)))
7203         {
7204             count++;
7205         }
7206 
7207         if (count >= max)
7208             break;
7209     }
7210 
7211     if (seen)
7212     {
7213         noisy(20, target);
7214         mprf("Some walls %s!",
7215              count > 0 ? "begin to move on their own"
7216                        : "crumble away");
7217     }
7218     else
7219         noisy(20, target, "You hear rumbling.");
7220 
7221     if (!seen && !count && you.can_see(mon))
7222         canned_msg(MSG_NOTHING_HAPPENS);
7223 }
7224 
7225 /**
7226  * Have a siren or merfolk avatar attempt to mesmerize the player.
7227  *
7228  * @param mons   The singing monster.
7229  * @param avatar Whether to use the more powerful "avatar song".
7230  */
_siren_sing(monster * mons,bool avatar)7231 static void _siren_sing(monster* mons, bool avatar)
7232 {
7233     const msg_channel_type spl = (mons->friendly() ? MSGCH_FRIEND_SPELL
7234                                                        : MSGCH_MONSTER_SPELL);
7235     const bool already_mesmerised = you.beheld_by(*mons);
7236 
7237     noisy(LOS_DEFAULT_RANGE, mons->pos(), mons->mid);
7238 
7239     if (avatar && !mons->has_ench(ENCH_MERFOLK_AVATAR_SONG))
7240         mons->add_ench(mon_enchant(ENCH_MERFOLK_AVATAR_SONG, 0, mons, 70));
7241 
7242     if (you.can_see(*mons))
7243     {
7244         const char * const song_adj = already_mesmerised ? "its luring"
7245                                                          : "a haunting";
7246         const string song_desc = make_stringf(" chants %s song.", song_adj);
7247         simple_monster_message(*mons, song_desc.c_str(), spl);
7248     }
7249     else
7250     {
7251         mprf(MSGCH_SOUND, "You hear %s.",
7252                           already_mesmerised ? "a luring song" :
7253                           coinflip()         ? "a haunting song"
7254                                              : "an eerie melody");
7255 
7256         // If you're already mesmerised by an invisible siren, it
7257         // can still prolong the enchantment.
7258         if (!already_mesmerised)
7259             return;
7260     }
7261 
7262     // power is the same for siren & avatar song, so just use siren
7263     const int pow = _ench_power(SPELL_SIREN_SONG, *mons);
7264     const int willpower = you.check_willpower(pow);
7265 
7266     // Once mesmerised by a particular monster, you cannot resist anymore.
7267     if (you.duration[DUR_MESMERISE_IMMUNE]
7268         || !already_mesmerised
7269            && (willpower > 0 || you.clarity()))
7270     {
7271         if (you.clarity())
7272             canned_msg(MSG_YOU_UNAFFECTED);
7273         else if (you.duration[DUR_MESMERISE_IMMUNE] && !already_mesmerised)
7274             canned_msg(MSG_YOU_RESIST);
7275         else
7276             mprf("You%s", you.resist_margin_phrase(willpower).c_str());
7277         return;
7278     }
7279 
7280     you.add_beholder(*mons);
7281 }
7282 
7283 // Checks to see if a particular spell is worth casting in the first place.
_monster_spell_goodness(monster * mon,mon_spell_slot slot)7284 static ai_action::goodness _monster_spell_goodness(monster* mon, mon_spell_slot slot)
7285 {
7286     spell_type monspell = slot.spell;
7287     actor *foe = mon->get_foe();
7288     const bool friendly = mon->friendly();
7289 
7290     if (!foe && (get_spell_flags(monspell) & spflag::targeting_mask))
7291         return ai_action::impossible();
7292 
7293     // Keep friendly summoners from spamming summons constantly.
7294     if (friendly && !foe && spell_typematch(monspell, spschool::summoning))
7295         return ai_action::bad();
7296 
7297 
7298     // Don't use abilities while rolling.
7299     if (mon->has_ench(ENCH_ROLLING))
7300         return ai_action::impossible();
7301 
7302     // Don't try to cast spells at players who are stepped from time.
7303     if (foe && foe->is_player() && you.duration[DUR_TIME_STEP])
7304         return ai_action::impossible();
7305 
7306     if (!mon->wont_attack())
7307     {
7308         if (spell_harms_area(monspell) && env.sanctuary_time > 0)
7309             return ai_action::impossible();
7310 
7311         if (spell_harms_target(monspell) && is_sanctuary(mon->target))
7312             return ai_action::impossible();
7313     }
7314 
7315     if (slot.flags & MON_SPELL_BREATH && mon->has_ench(ENCH_BREATH_WEAPON))
7316         return ai_action::impossible();
7317 
7318     // Don't bother casting a summon spell if we're already at its cap
7319     if (summons_are_capped(monspell)
7320         && count_summons(mon, monspell) >= summons_limit(monspell))
7321     {
7322         return ai_action::impossible();
7323     }
7324 
7325     const mons_spell_logic* logic = map_find(spell_to_logic, monspell);
7326     if (logic && logic->calc_goodness)
7327         return logic->calc_goodness(*mon);
7328 
7329     const bool no_clouds = env.level_state & LSTATE_STILL_WINDS;
7330 
7331     // Eventually, we'll probably want to be able to have monsters
7332     // learn which of their elemental bolts were resisted and have those
7333     // handled here as well. - bwr
7334     switch (monspell)
7335     {
7336     case SPELL_CALL_TIDE:
7337         if (!player_in_branch(BRANCH_SHOALS) || mon->has_ench(ENCH_TIDE))
7338             return ai_action::impossible();
7339         else if (!foe || (env.grid(mon->pos()) == DNGN_DEEP_WATER
7340                      && env.grid(foe->pos()) == DNGN_DEEP_WATER))
7341         {
7342             return ai_action::bad();
7343         }
7344         else
7345             return ai_action::good();
7346     case SPELL_BRAIN_FEED:
7347         ASSERT(foe);
7348         return ai_action::good_or_bad(foe->is_player());
7349 
7350     case SPELL_BOLT_OF_DRAINING:
7351     case SPELL_MALIGN_OFFERING:
7352     case SPELL_GHOSTLY_FIREBALL:
7353         ASSERT(foe);
7354         return _negative_energy_spell_goodness(foe);
7355 
7356     case SPELL_DEATH_RATTLE:
7357     case SPELL_MIASMA_BREATH:
7358         ASSERT(foe);
7359         return ai_action::good_or_bad(!foe->res_miasma() && !no_clouds);
7360 
7361     case SPELL_DISPEL_UNDEAD_RANGE:
7362         // [ds] How is dispel undead intended to interact with vampires?
7363         // Currently if the vampire's undead state returns MH_UNDEAD it
7364         // affects the player.
7365         ASSERT(foe);
7366         return ai_action::good_or_bad(!!(foe->holiness() & MH_UNDEAD));
7367 
7368     case SPELL_BERSERKER_RAGE:
7369         return ai_action::good_or_impossible(mon->needs_berserk(false));
7370 
7371 #if TAG_MAJOR_VERSION == 34
7372     case SPELL_SWIFTNESS:
7373 #endif
7374     case SPELL_SPRINT:
7375         return ai_action::good_or_impossible(!mon->has_ench(ENCH_SWIFT));
7376 
7377     case SPELL_MAJOR_HEALING:
7378         return ai_action::good_or_bad(mon->hit_points <= mon->max_hit_points / 2);
7379 
7380     case SPELL_WOODWEAL:
7381     {
7382         bool touch_wood = false;
7383         for (adjacent_iterator ai(mon->pos()); ai; ai++)
7384         {
7385             if (feat_is_tree(env.grid(*ai)))
7386             {
7387                 touch_wood = true;
7388                 break;
7389             }
7390             const monster *adj_mons = monster_at(*ai);
7391             if (adj_mons && mons_genus(adj_mons->type) == MONS_SHAMBLING_MANGROVE)
7392             {
7393                 touch_wood = true;
7394                 break;
7395             }
7396         }
7397         if (!touch_wood)
7398             return ai_action::impossible();
7399         return ai_action::good_or_bad(mon->hit_points <= mon->max_hit_points / 2);
7400     }
7401 
7402     case SPELL_BLINK_CLOSE:
7403         ASSERT(foe);
7404         if (adjacent(mon->pos(), foe->pos()))
7405             return ai_action::bad();
7406         // intentional fall-through
7407     case SPELL_BLINK:
7408     case SPELL_BLINK_RANGE:
7409     case SPELL_BLINK_AWAY:
7410         if (mon->no_tele(true, false))
7411             return ai_action::impossible();
7412         else // Prefer to keep a polar vortex going rather than blink.
7413             return ai_action::good_or_bad(!mon->has_ench(ENCH_POLAR_VORTEX));
7414 
7415     case SPELL_BLINK_OTHER:
7416     case SPELL_BLINK_OTHER_CLOSE:
7417         return _foe_effect_viable(*mon, DUR_DIMENSION_ANCHOR, ENCH_DIMENSION_ANCHOR);
7418 
7419     case SPELL_DREAM_DUST:
7420         return _foe_sleep_viable(*mon);
7421 
7422     // Mara shouldn't cast player ghost if he can't see the player
7423     case SPELL_SUMMON_ILLUSION:
7424         ASSERT(foe);
7425         return ai_action::good_or_impossible(mon->see_cell_no_trans(foe->pos())
7426                && mon->can_see(*foe)
7427                && actor_is_illusion_cloneable(foe));
7428 
7429     case SPELL_AWAKEN_FOREST:
7430         if (mon->has_ench(ENCH_AWAKEN_FOREST)
7431                || env.forest_awoken_until > you.elapsed_time)
7432         {
7433             return ai_action::impossible();
7434         }
7435         return ai_action::good_or_bad(forest_near_enemy(mon));
7436 
7437     case SPELL_BATTLESPHERE:
7438         return ai_action::good_or_bad(!find_battlesphere(mon));
7439 
7440     case SPELL_INJURY_BOND:
7441         for (monster_iterator mi; mi; ++mi)
7442         {
7443             if (mons_aligned(mon, *mi) && !mi->has_ench(ENCH_CHARM)
7444                 && !mi->has_ench(ENCH_HEXED)
7445                 && *mi != mon && mon->see_cell_no_trans(mi->pos())
7446                 && !mi->has_ench(ENCH_INJURY_BOND))
7447             {
7448                 return ai_action::good(); // We found at least one target; that's enough.
7449             }
7450         }
7451         return ai_action::bad();
7452 
7453     case SPELL_BLINK_ALLIES_ENCIRCLE:
7454         ASSERT(foe);
7455         if (!mon->see_cell_no_trans(foe->pos()) || !mon->can_see(*foe))
7456             return ai_action::impossible();
7457 
7458         for (monster_near_iterator mi(mon, LOS_NO_TRANS); mi; ++mi)
7459             if (_valid_encircle_ally(mon, *mi, foe->pos()))
7460                 return ai_action::good(); // We found at least one valid ally; that's enough.
7461         return ai_action::bad();
7462 
7463     case SPELL_AWAKEN_VINES:
7464         return ai_action::good_or_impossible(
7465                     (!mon->has_ench(ENCH_AWAKEN_VINES)
7466                         || mon->props["vines_awakened"].get_int() <= 3)
7467                     && _awaken_vines(mon, true)); // test cast: would anything happen?
7468 
7469     case SPELL_WATERSTRIKE:
7470         ASSERT(foe);
7471         return ai_action::good_or_impossible(feat_is_watery(env.grid(foe->pos())));
7472 
7473     // Don't use unless our foe is close to us and there are no allies already
7474     // between the two of us
7475     case SPELL_WIND_BLAST:
7476         ASSERT(foe);
7477         if (foe->pos().distance_from(mon->pos()) < 4)
7478         {
7479             bolt tracer;
7480             tracer.target = foe->pos();
7481             tracer.range  = LOS_RADIUS;
7482             tracer.hit    = AUTOMATIC_HIT;
7483             fire_tracer(mon, tracer);
7484 
7485             actor* act = actor_at(tracer.path_taken.back());
7486             // XX does this handle multiple actors?
7487             return ai_action::good_or_bad(!act || !mons_aligned(mon, act));
7488         }
7489         else
7490             return ai_action::bad(); // no close foe
7491 
7492     case SPELL_BROTHERS_IN_ARMS:
7493         return ai_action::good_or_bad(
7494             !mon->props.exists("brothers_count")
7495                || mon->props["brothers_count"].get_int() < 2);
7496 
7497     case SPELL_HOLY_FLAMES:
7498         return ai_action::good_or_impossible(!no_clouds);
7499 
7500     case SPELL_FREEZE:
7501         ASSERT(foe);
7502         return ai_action::good_or_impossible(adjacent(mon->pos(), foe->pos()));
7503 
7504     case SPELL_DRUIDS_CALL:
7505         // Don't cast unless there's at least one valid target
7506         for (monster_iterator mi; mi; ++mi)
7507             if (_valid_druids_call_target(mon, *mi))
7508                 return ai_action::good();
7509         return ai_action::impossible();
7510 
7511     case SPELL_MESMERISE:
7512         // Don't spam mesmerisation if you're already mesmerised
7513         // TODO: is this really the right place for randomization like this?
7514         // or is there a better way to handle repeated mesmerise? Long-run:
7515         // the goodness should be lower in this case which would prioritize
7516         // better actions, if actions were calculated comparatively.
7517         return ai_action::good_or_bad(!you.beheld_by(*mon) || coinflip());
7518 
7519     case SPELL_DISCHARGE:
7520         // TODO: possibly check for friendlies nearby?
7521         // Perhaps it will be used recklessly like chain lightning...
7522         return ai_action::good_or_bad(foe && adjacent(foe->pos(), mon->pos()));
7523 
7524     case SPELL_PORTAL_PROJECTILE:
7525     {
7526         bolt beam;
7527         beam.source    = mon->pos();
7528         beam.target    = mon->target;
7529         beam.source_id = mon->mid;
7530         return ai_action::good_or_bad(handle_throw(mon, beam, true, true));
7531     }
7532 
7533     case SPELL_FLASH_FREEZE:
7534         return _foe_effect_viable(*mon, DUR_FROZEN, ENCH_FROZEN);
7535 
7536     case SPELL_BLACK_MARK:
7537         return ai_action::good_or_impossible(!mon->has_ench(ENCH_BLACK_MARK));
7538 
7539     case SPELL_BLINK_ALLIES_AWAY:
7540         ASSERT(foe);
7541         if (!mon->see_cell_no_trans(foe->pos()) && !mon->can_see(*foe))
7542             return ai_action::impossible();
7543 
7544         for (monster_near_iterator mi(mon, LOS_NO_TRANS); mi; ++mi)
7545             if (_valid_blink_away_ally(mon, *mi, foe->pos()))
7546                 return ai_action::good();
7547         return ai_action::bad();
7548 
7549     // Don't let clones duplicate anything, to prevent exponential explosion
7550     case SPELL_FAKE_MARA_SUMMON:
7551         return ai_action::good_or_impossible(!mon->has_ench(ENCH_PHANTOM_MIRROR));
7552 
7553     case SPELL_PHANTOM_MIRROR:
7554         if (mon->has_ench(ENCH_PHANTOM_MIRROR))
7555             return ai_action::impossible();
7556         for (monster_near_iterator mi(mon); mi; ++mi)
7557         {
7558             // A single valid target is enough.
7559             if (_mirrorable(mon, *mi))
7560                 return ai_action::good();
7561         }
7562         return ai_action::impossible();
7563 
7564     case SPELL_THROW_BARBS:
7565     case SPELL_HARPOON_SHOT:
7566         // Don't fire barbs in melee range.
7567         ASSERT(foe);
7568         return ai_action::good_or_bad(!adjacent(mon->pos(), foe->pos()));
7569 
7570     case SPELL_BATTLECRY:
7571         return ai_action::good_or_bad(_battle_cry(*mon, true));
7572 
7573     case SPELL_WARNING_CRY:
7574         return ai_action::good_or_bad(!friendly);
7575 
7576     case SPELL_CONJURE_BALL_LIGHTNING:
7577         if (!!(mon->holiness() & MH_DEMONIC))
7578             return ai_action::good(); // demons are rude
7579         return ai_action::good_or_bad(
7580                         !(friendly && (you.res_elec() <= 0 || you.hp <= 50)));
7581 
7582     case SPELL_SEAL_DOORS:
7583         return ai_action::good_or_bad(!friendly && _seal_doors_and_stairs(mon, true));
7584 
7585     //XXX: unify with the other SPELL_FOO_OTHER spells?
7586     case SPELL_BERSERK_OTHER:
7587         return ai_action::good_or_bad(_incite_monsters(mon, false));
7588 
7589     case SPELL_CAUSE_FEAR:
7590         return ai_action::good_or_bad(_mons_cause_fear(mon, false) >= 0);
7591 
7592     case SPELL_MASS_CONFUSION:
7593         return ai_action::good_or_bad(_mons_mass_confuse(mon, false) >= 0);
7594 
7595     case SPELL_THROW_ALLY:
7596         return ai_action::good_or_impossible(_find_ally_to_throw(*mon));
7597 
7598     case SPELL_CREATE_TENTACLES:
7599         return ai_action::good_or_impossible(mons_available_tentacles(mon));
7600 
7601     case SPELL_WORD_OF_RECALL:
7602         return ai_action::good_or_bad(_should_recall(mon));
7603 
7604     case SPELL_SHATTER:
7605         return ai_action::good_or_bad(!friendly && mons_shatter(mon, false));
7606 
7607     case SPELL_SYMBOL_OF_TORMENT:
7608         if (you.visible_to(mon)
7609             && friendly
7610             && !you.res_torment()
7611             && !player_kiku_res_torment())
7612         {
7613             return ai_action::bad();
7614         }
7615         else
7616             return ai_action::good_or_bad(_trace_los(mon, _torment_vulnerable));
7617 
7618     case SPELL_CHAIN_LIGHTNING:
7619         if (you.visible_to(mon) && friendly)
7620             return ai_action::bad(); // don't zap player
7621         return ai_action::good_or_bad(_trace_los(mon, [] (const actor * /*a*/)
7622                                                           { return true; }));
7623 
7624     case SPELL_CHAIN_OF_CHAOS:
7625         if (you.visible_to(mon) && friendly)
7626             return ai_action::bad(); // don't zap player
7627         return ai_action::good_or_bad(_trace_los(mon, [] (const actor * /*a*/)
7628                                                           { return true; }));
7629 
7630     case SPELL_CORRUPTING_PULSE:
7631         if (you.visible_to(mon) && friendly)
7632             return ai_action::bad(); // don't zap player
7633         else
7634             return ai_action::good_or_bad(_trace_los(mon, _mutation_vulnerable));
7635 
7636     case SPELL_POLAR_VORTEX:
7637         if (mon->has_ench(ENCH_POLAR_VORTEX) || mon->has_ench(ENCH_POLAR_VORTEX_COOLDOWN))
7638             return ai_action::impossible();
7639         else if (you.visible_to(mon) && friendly && !(mon->holiness() & MH_DEMONIC))
7640             return ai_action::bad(); // don't zap player (but demons are rude)
7641         else
7642             return ai_action::good_or_bad(_trace_los(mon, _vortex_vulnerable));
7643 
7644     case SPELL_ENGLACIATION:
7645         return ai_action::good_or_bad(foe && mon->see_cell_no_trans(foe->pos())
7646                                         && foe->res_cold() <= 0);
7647 
7648     case SPELL_OLGREBS_TOXIC_RADIANCE:
7649         if (mon->has_ench(ENCH_TOXIC_RADIANCE))
7650             return ai_action::impossible();
7651         else
7652         {
7653             return ai_action::good_or_bad(
7654                 cast_toxic_radiance(mon, 100, false, true) == spret::success);
7655         }
7656 
7657     case SPELL_IGNITE_POISON:
7658         return ai_action::good_or_bad(
7659             cast_ignite_poison(mon, 0, false, true) == spret::success);
7660 
7661     case SPELL_GLACIATE:
7662         ASSERT(foe);
7663         return ai_action::good_or_bad(
7664             _glaciate_tracer(mon, mons_spellpower(*mon, monspell), foe->pos()));
7665 
7666     case SPELL_MALIGN_GATEWAY:
7667         return ai_action::good_or_bad(can_cast_malign_gateway());
7668 
7669     case SPELL_SIREN_SONG:
7670         return _siren_goodness(mon, false);
7671 
7672     case SPELL_AVATAR_SONG:
7673         return _siren_goodness(mon, true);
7674 
7675     case SPELL_REPEL_MISSILES:
7676         return ai_action::good_or_impossible(!mon->has_ench(ENCH_REPEL_MISSILES));
7677 
7678     case SPELL_CONFUSION_GAZE:
7679         // why is this handled here unlike other gazes?
7680         return _caster_sees_foe(*mon);
7681 
7682     case SPELL_CLEANSING_FLAME:
7683     {
7684         bolt tracer;
7685         setup_cleansing_flame_beam(tracer,
7686                                    5 + (7 * mon->spell_hd(monspell)) / 12,
7687                                    cleansing_flame_source::spell,
7688                                    mon->pos(), mon);
7689         fire_tracer(mon, tracer, true);
7690         return ai_action::good_or_bad(mons_should_fire(tracer));
7691     }
7692 
7693     case SPELL_GRAVITAS:
7694         if (!foe)
7695             return ai_action::bad();
7696 
7697         for (actor_near_iterator ai(foe->pos(), LOS_SOLID); ai; ++ai)
7698             if (*ai != mon && *ai != foe && !ai->is_stationary()
7699                 && mon->can_see(**ai))
7700             {
7701                 return ai_action::good();
7702             }
7703 
7704         return ai_action::bad();
7705 
7706     case SPELL_DOOM_HOWL:
7707         ASSERT(foe);
7708         if (!foe->is_player() || you.duration[DUR_DOOM_HOWL]
7709                 || mon->props[DOOM_HOUND_HOWLED_KEY]
7710                 || mon->is_summoned())
7711         {
7712             return ai_action::impossible();
7713         }
7714         return ai_action::good();
7715 
7716     case SPELL_CALL_OF_CHAOS:
7717         return ai_action::good_or_bad(_mons_call_of_chaos(*mon, true));
7718 
7719     case SPELL_AURA_OF_BRILLIANCE:
7720         if (!foe || !mon->can_see(*foe))
7721             return ai_action::bad();
7722 
7723         if (mon->has_ench(ENCH_BRILLIANCE_AURA))
7724             return ai_action::impossible();
7725 
7726         for (monster_near_iterator mi(mon, LOS_NO_TRANS); mi; ++mi)
7727             if (_valid_aura_of_brilliance_ally(mon, *mi))
7728                 return ai_action::good();
7729         return ai_action::bad();
7730 
7731     case SPELL_BIND_SOULS:
7732         for (monster_near_iterator mi(mon, LOS_NO_TRANS); mi; ++mi)
7733             if (_mons_can_bind_soul(mon, *mi))
7734                 return ai_action::good();
7735         return ai_action::bad();
7736 
7737     case SPELL_CORPSE_ROT:
7738     case SPELL_POISONOUS_CLOUD:
7739     case SPELL_FREEZING_CLOUD:
7740     case SPELL_MEPHITIC_CLOUD:
7741     case SPELL_NOXIOUS_CLOUD:
7742     case SPELL_SPECTRAL_CLOUD:
7743     case SPELL_FLAMING_CLOUD:
7744     case SPELL_CHAOS_BREATH:
7745         return ai_action::good_or_impossible(!no_clouds);
7746 
7747     case SPELL_ROLL:
7748     {
7749         const coord_def delta = mon->props["mmov"].get_coord();
7750         // We can roll if we have a foe we're not already adjacent to and where
7751         // we have a move that brings us closer.
7752         return ai_action::good_or_bad(
7753                 mon->get_foe()
7754                 && !adjacent(mon->pos(), mon->get_foe()->pos())
7755                 && !delta.origin()
7756                 && mon_can_move_to_pos(mon, delta));
7757     }
7758 
7759     case SPELL_GOAD_BEASTS:
7760         for (monster_near_iterator mi(mon, LOS_NO_TRANS); mi; ++mi)
7761             if (_valid_goad_beasts_target(mon, *mi))
7762                 return ai_action::good();
7763         return ai_action::impossible();
7764 
7765 #if TAG_MAJOR_VERSION == 34
7766     case SPELL_SUMMON_SWARM:
7767     case SPELL_INNER_FLAME:
7768     case SPELL_ANIMATE_DEAD:
7769     case SPELL_SIMULACRUM:
7770     case SPELL_DEATHS_DOOR:
7771     case SPELL_FULMINANT_PRISM:
7772     case SPELL_DAZZLING_FLASH:
7773     case SPELL_OZOCUBUS_ARMOUR:
7774 #endif
7775     case SPELL_NO_SPELL:
7776         return ai_action::bad();
7777 
7778     default:
7779         // is this the right approach for this case? There are currently around
7780         // 280 spells not handled in this switch, most of them purely
7781         // targeted, removed, or handled via spell_to_logic.
7782         return ai_action::good();
7783     }
7784 }
7785 
_god_name(god_type god)7786 static string _god_name(god_type god)
7787 {
7788     return god_has_name(god) ? god_name(god) : "Something";
7789 }
7790