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