1 /**
2 * @file
3 * @brief Monster enchantments.
4 **/
5
6 #include "AppHdr.h"
7
8 #include "monster.h"
9
10 #include <sstream>
11 #include <unordered_map>
12
13 #include "act-iter.h"
14 #include "areas.h"
15 #include "attitude-change.h"
16 #include "bloodspatter.h"
17 #include "cloud.h"
18 #include "coordit.h"
19 #include "corpse.h"
20 #include "delay.h"
21 #include "dgn-shoals.h"
22 #include "english.h"
23 #include "env.h"
24 #include "fight.h"
25 #include "hints.h"
26 #include "item-status-flag-type.h"
27 #include "items.h"
28 #include "libutil.h"
29 #include "losglobal.h"
30 #include "message.h"
31 #include "mon-abil.h"
32 #include "mon-behv.h"
33 #include "mon-cast.h"
34 #include "mon-death.h"
35 #include "mon-explode.h"
36 #include "mon-place.h"
37 #include "mon-poly.h"
38 #include "mon-tentacle.h"
39 #include "religion.h"
40 #include "spl-clouds.h"
41 #include "spl-damage.h"
42 #include "spl-summoning.h"
43 #include "state.h"
44 #include "stepdown.h"
45 #include "stringutil.h"
46 #include "tag-version.h"
47 #include "teleport.h"
48 #include "terrain.h"
49 #include "timed-effects.h"
50 #include "traps.h"
51 #include "unwind.h"
52 #include "view.h"
53
54 static const unordered_map<enchant_type, cloud_type, std::hash<int>> _cloud_ring_ench_to_cloud = {
55 { ENCH_RING_OF_THUNDER, CLOUD_STORM },
56 { ENCH_RING_OF_FLAMES, CLOUD_FIRE },
57 { ENCH_RING_OF_CHAOS, CLOUD_CHAOS },
58 { ENCH_RING_OF_MUTATION, CLOUD_MUTAGENIC },
59 { ENCH_RING_OF_FOG, CLOUD_GREY_SMOKE },
60 { ENCH_RING_OF_ICE, CLOUD_COLD },
61 { ENCH_RING_OF_DRAINING, CLOUD_NEGATIVE_ENERGY },
62 { ENCH_RING_OF_ACID, CLOUD_ACID },
63 { ENCH_RING_OF_MIASMA, CLOUD_MIASMA },
64 };
65
_has_other_cloud_ring(monster * mons,enchant_type ench)66 static bool _has_other_cloud_ring(monster* mons, enchant_type ench)
67 {
68 for (auto i : _cloud_ring_ench_to_cloud)
69 {
70 if (mons->has_ench(i.first) && i.first != ench)
71 return true;
72 }
73 return false;
74 }
75
76 /**
77 * If the monster has a cloud ring enchantment, surround them with clouds.
78 */
update_mons_cloud_ring(monster * mons)79 void update_mons_cloud_ring(monster* mons)
80 {
81 for (auto i : _cloud_ring_ench_to_cloud)
82 {
83 if (mons->has_ench(i.first))
84 {
85 surround_actor_with_cloud(mons, i.second);
86 break; // there can only be one cloud ring
87 }
88 }
89 }
90
91 #ifdef DEBUG_ENCH_CACHE_DIAGNOSTICS
has_ench(enchant_type ench) const92 bool monster::has_ench(enchant_type ench) const
93 {
94 mon_enchant e = get_ench(ench);
95 if (e.ench == ench)
96 {
97 if (!ench_cache[ench])
98 {
99 die("monster %s has ench '%s' not in cache",
100 name(DESC_PLAIN).c_str(),
101 string(e).c_str());
102 }
103 }
104 else if (e.ench == ENCH_NONE)
105 {
106 if (ench_cache[ench])
107 {
108 die("monster %s has no ench '%s' but cache says it does",
109 name(DESC_PLAIN).c_str(),
110 string(mon_enchant(ench)).c_str());
111 }
112 }
113 else
114 {
115 die("get_ench returned '%s' when asked for '%s'",
116 string(e).c_str(),
117 string(mon_enchant(ench)).c_str());
118 }
119 return ench_cache[ench];
120 }
121 #endif
122
has_ench(enchant_type ench,enchant_type ench2) const123 bool monster::has_ench(enchant_type ench, enchant_type ench2) const
124 {
125 if (ench2 == ENCH_NONE)
126 ench2 = ench;
127
128 for (int i = ench; i <= ench2; ++i)
129 if (has_ench(static_cast<enchant_type>(i)))
130 return true;
131
132 return false;
133 }
134
get_ench(enchant_type ench1,enchant_type ench2) const135 mon_enchant monster::get_ench(enchant_type ench1,
136 enchant_type ench2) const
137 {
138 if (ench2 == ENCH_NONE)
139 ench2 = ench1;
140
141 for (int e = ench1; e <= ench2; ++e)
142 {
143 auto i = enchantments.find(static_cast<enchant_type>(e));
144
145 if (i != enchantments.end())
146 return i->second;
147 }
148
149 return mon_enchant();
150 }
151
update_ench(const mon_enchant & ench)152 void monster::update_ench(const mon_enchant &ench)
153 {
154 if (ench.ench != ENCH_NONE)
155 {
156 if (mon_enchant *curr_ench = map_find(enchantments, ench.ench))
157 *curr_ench = ench;
158 }
159 }
160
add_ench(const mon_enchant & ench)161 bool monster::add_ench(const mon_enchant &ench)
162 {
163 // silliness
164 if (ench.ench == ENCH_NONE)
165 return false;
166
167 if (ench.ench == ENCH_FEAR && !can_feel_fear(true))
168 return false;
169
170 if (ench.ench == ENCH_BLIND && !mons_can_be_blinded(type))
171 return false;
172
173 // If we have never changed shape, mark us as shapeshifter, so that
174 // "goblin perm_ench:shapeshifter" reverts on death.
175 if (ench.ench == ENCH_SHAPESHIFTER)
176 {
177 if (!props.exists(ORIGINAL_TYPE_KEY))
178 props[ORIGINAL_TYPE_KEY].get_int() = MONS_SHAPESHIFTER;
179 }
180 else if (ench.ench == ENCH_GLOWING_SHAPESHIFTER)
181 {
182 if (!props.exists(ORIGINAL_TYPE_KEY))
183 props[ORIGINAL_TYPE_KEY].get_int() = MONS_GLOWING_SHAPESHIFTER;
184 }
185
186 bool new_enchantment = false;
187 mon_enchant *added = map_find(enchantments, ench.ench);
188 if (added)
189 *added += ench;
190 else
191 {
192 new_enchantment = true;
193 added = &(enchantments[ench.ench] = ench);
194 ench_cache.set(ench.ench, true);
195 }
196
197 // If the duration is not set, we must calculate it (depending on the
198 // enchantment).
199 if (!ench.duration)
200 added->set_duration(this, new_enchantment ? nullptr : &ench);
201
202 if (new_enchantment)
203 add_enchantment_effect(ench);
204
205 if (ench.ench == ENCH_CHARM
206 || ench.ench == ENCH_NEUTRAL_BRIBED
207 || ench.ench == ENCH_FRIENDLY_BRIBED
208 || ench.ench == ENCH_HEXED)
209 {
210 remove_summons();
211 }
212 return true;
213 }
214
add_enchantment_effect(const mon_enchant & ench,bool quiet)215 void monster::add_enchantment_effect(const mon_enchant &ench, bool quiet)
216 {
217 // Check for slow/haste.
218 switch (ench.ench)
219 {
220 case ENCH_BERSERK:
221 // Inflate hp.
222 scale_hp(3, 2);
223 // deliberate fall-through
224
225 case ENCH_INSANE:
226 if (has_ench(ENCH_SUBMERGED))
227 del_ench(ENCH_SUBMERGED);
228
229 calc_speed();
230 break;
231
232 case ENCH_HASTE:
233 calc_speed();
234 break;
235
236 case ENCH_SLOW:
237 calc_speed();
238 break;
239
240 case ENCH_SUBMERGED:
241 dprf("%s submerges.", name(DESC_A, true).c_str());
242 break;
243
244 case ENCH_CHARM:
245 case ENCH_NEUTRAL_BRIBED:
246 case ENCH_FRIENDLY_BRIBED:
247 case ENCH_HEXED:
248 {
249 behaviour = BEH_SEEK;
250
251 actor *source_actor = actor_by_mid(ench.source, true);
252 if (!source_actor)
253 {
254 target = pos();
255 foe = MHITNOT;
256 }
257 else if (source_actor->is_player())
258 {
259 target = you.pos();
260 foe = MHITYOU;
261 }
262 else
263 {
264 foe = source_actor->as_monster()->foe;
265 if (foe == MHITYOU)
266 target = you.pos();
267 else if (foe != MHITNOT)
268 target = env.mons[source_actor->as_monster()->foe].pos();
269 }
270
271 if (type == MONS_FLAYED_GHOST)
272 {
273 // temporarly change our attitude back (XXX: scary code...)
274 unwind_var<mon_enchant_list> enchants(enchantments, mon_enchant_list{});
275 unwind_var<FixedBitVector<NUM_ENCHANTMENTS>> ecache(ench_cache, {});
276 end_flayed_effect(this);
277 }
278 del_ench(ENCH_STILL_WINDS);
279
280 if (is_patrolling())
281 {
282 // Charmed monsters stop patrolling and forget their patrol
283 // point; they're supposed to follow you now.
284 patrol_point.reset();
285 firing_pos.reset();
286 }
287 mons_att_changed(this);
288 // clear any constrictions on/by you
289 stop_constricting(MID_PLAYER, true);
290 you.stop_constricting(mid, true);
291
292 if (invisible() && you.see_cell(pos()) && !you.can_see_invisible()
293 && !backlit() && !has_ench(ENCH_SUBMERGED))
294 {
295 if (!quiet)
296 {
297 mprf("You %sdetect the %s %s.",
298 friendly() ? "" : "can no longer ",
299 ench.ench == ENCH_HEXED ? "hexed" :
300 ench.ench == ENCH_CHARM ? "charmed"
301 : "bribed",
302 name(DESC_PLAIN, true).c_str());
303 }
304
305 autotoggle_autopickup(!friendly());
306 handle_seen_interrupt(this);
307 }
308
309 // TODO -- and friends
310
311 if (you.can_see(*this) && friendly())
312 learned_something_new(HINT_MONSTER_FRIENDLY, pos());
313 break;
314 }
315
316 case ENCH_LIQUEFYING:
317 case ENCH_SILENCE:
318 invalidate_agrid(true);
319 break;
320
321 case ENCH_FROZEN:
322 calc_speed();
323 break;
324
325 case ENCH_INVIS:
326 if (testbits(flags, MF_WAS_IN_VIEW))
327 {
328 went_unseen_this_turn = true;
329 unseen_pos = pos();
330 }
331 break;
332
333 case ENCH_STILL_WINDS:
334 start_still_winds();
335 break;
336
337 case ENCH_RING_OF_THUNDER:
338 case ENCH_RING_OF_FLAMES:
339 case ENCH_RING_OF_CHAOS:
340 case ENCH_RING_OF_MUTATION:
341 case ENCH_RING_OF_FOG:
342 case ENCH_RING_OF_ICE:
343 case ENCH_RING_OF_DRAINING:
344 case ENCH_RING_OF_ACID:
345 case ENCH_RING_OF_MIASMA:
346 if (_has_other_cloud_ring(this, ench.ench))
347 die("%s already has a cloud ring!", name(DESC_THE).c_str());
348 surround_actor_with_cloud(this, _cloud_ring_ench_to_cloud.at(ench.ench));
349 break;
350
351 case ENCH_VILE_CLUTCH:
352 case ENCH_GRASPING_ROOTS:
353 {
354 actor *source_actor = actor_by_mid(ench.source, true);
355 const string noun = ench.ench == ENCH_VILE_CLUTCH ? "Zombie hands" :
356 "Roots";
357 source_actor->start_constricting(*this);
358 if (you.see_cell(pos()))
359 {
360 mprf(MSGCH_WARN, "%s grab %s.", noun.c_str(),
361 name(DESC_THE).c_str());
362 }
363 break;
364 }
365
366 default:
367 break;
368 }
369 }
370
_prepare_del_ench(monster * mon,const mon_enchant & me)371 static bool _prepare_del_ench(monster* mon, const mon_enchant &me)
372 {
373 if (me.ench != ENCH_SUBMERGED)
374 return true;
375
376 int midx = mon->mindex();
377
378 if (!monster_at(mon->pos()))
379 env.mgrid(mon->pos()) = midx;
380
381 if (mon->pos() != you.pos() && midx == env.mgrid(mon->pos()))
382 return true;
383
384 if (midx != env.mgrid(mon->pos()))
385 {
386 monster* other_mon = &env.mons[env.mgrid(mon->pos())];
387
388 if (other_mon->type == MONS_NO_MONSTER
389 || other_mon->type == MONS_PROGRAM_BUG)
390 {
391 env.mgrid(mon->pos()) = midx;
392
393 mprf(MSGCH_ERROR, "env.mgrid(%d,%d) points to %s monster, even "
394 "though it contains submerged monster %s (see bug 2293518)",
395 mon->pos().x, mon->pos().y,
396 other_mon->type == MONS_NO_MONSTER ? "dead" : "buggy",
397 mon->name(DESC_PLAIN, true).c_str());
398
399 if (mon->pos() != you.pos())
400 return true;
401 }
402 else
403 mprf(MSGCH_ERROR, "%s tried to unsubmerge while on same square as "
404 "%s (see bug 2293518)", mon->name(DESC_THE, true).c_str(),
405 mon->name(DESC_A, true).c_str());
406 }
407
408 // Monster un-submerging while under player or another monster. Try to
409 // move to an adjacent square in which the monster could have been
410 // submerged and have it unsubmerge from there.
411 coord_def target_square;
412 int okay_squares = 0;
413
414 for (adjacent_iterator ai(mon->pos()); ai; ++ai)
415 if (!actor_at(*ai)
416 && monster_can_submerge(mon, env.grid(*ai))
417 && one_chance_in(++okay_squares))
418 {
419 target_square = *ai;
420 }
421
422 if (okay_squares > 0)
423 return mon->move_to_pos(target_square);
424
425 // No available adjacent squares from which the monster could also
426 // have unsubmerged. Can it just stay submerged where it is?
427 if (monster_can_submerge(mon, env.grid(mon->pos())))
428 return false;
429
430 // The terrain changed and the monster can't remain submerged.
431 // Try to move to an adjacent square where it would be happy.
432 for (adjacent_iterator ai(mon->pos()); ai; ++ai)
433 {
434 if (!actor_at(*ai)
435 && monster_habitable_grid(mon, env.grid(*ai))
436 && !trap_at(*ai))
437 {
438 if (one_chance_in(++okay_squares))
439 target_square = *ai;
440 }
441 }
442
443 if (okay_squares > 0)
444 return mon->move_to_pos(target_square);
445
446 return true;
447 }
448
del_ench(enchant_type ench,bool quiet,bool effect)449 bool monster::del_ench(enchant_type ench, bool quiet, bool effect)
450 {
451 auto i = enchantments.find(ench);
452 if (i == enchantments.end())
453 return false;
454
455 const mon_enchant me = i->second;
456 const enchant_type et = i->first;
457
458 if (!_prepare_del_ench(this, me))
459 return false;
460
461 enchantments.erase(et);
462 ench_cache.set(et, false);
463 if (effect)
464 remove_enchantment_effect(me, quiet);
465 return true;
466 }
467
remove_enchantment_effect(const mon_enchant & me,bool quiet)468 void monster::remove_enchantment_effect(const mon_enchant &me, bool quiet)
469 {
470 switch (me.ench)
471 {
472 case ENCH_TIDE:
473 shoals_release_tide(this);
474 break;
475
476 case ENCH_INSANE:
477 if (mons_is_elven_twin(this))
478 {
479 monster* twin = mons_find_elven_twin_of(this);
480 if (twin && !twin->has_ench(ENCH_INSANE))
481 attitude = twin->attitude;
482 else
483 attitude = ATT_HOSTILE;
484 }
485 mons_att_changed(this);
486 break;
487
488 case ENCH_BERSERK:
489 scale_hp(2, 3);
490 calc_speed();
491 break;
492
493 case ENCH_HASTE:
494 calc_speed();
495 if (!quiet)
496 simple_monster_message(*this, " is no longer moving quickly.");
497 break;
498
499 case ENCH_SWIFT:
500 if (!quiet)
501 {
502 if (type == MONS_ALLIGATOR)
503 simple_monster_message(*this, " slows down.");
504 else
505 simple_monster_message(*this, " is no longer moving quickly.");
506 }
507 break;
508
509 case ENCH_SILENCE:
510 invalidate_agrid();
511 if (!quiet && !silenced(pos()))
512 {
513 if (alive())
514 simple_monster_message(*this, " becomes audible again.");
515 else
516 mprf("As %s %s, the sound returns.",
517 name(DESC_THE).c_str(),
518 wounded_damaged(holiness()) ? "is destroyed" : "dies");
519 }
520 break;
521
522 case ENCH_MIGHT:
523 if (!quiet)
524 simple_monster_message(*this, " no longer looks unusually strong.");
525 break;
526
527 case ENCH_SLOW:
528 if (!quiet)
529 simple_monster_message(*this, " is no longer moving slowly.");
530 calc_speed();
531 break;
532
533 case ENCH_PARALYSIS:
534 if (!quiet)
535 simple_monster_message(*this, " is no longer paralysed.");
536
537 behaviour_event(this, ME_EVAL);
538 break;
539
540 case ENCH_PETRIFIED:
541 if (!quiet)
542 simple_monster_message(*this, " is no longer petrified.");
543 del_ench(ENCH_PETRIFYING);
544
545 behaviour_event(this, ME_EVAL);
546 break;
547
548 case ENCH_PETRIFYING:
549 fully_petrify(quiet);
550
551 if (alive()) // losing active flight over lava
552 behaviour_event(this, ME_EVAL);
553 break;
554
555 case ENCH_FEAR:
556 {
557 string msg;
558 if (is_nonliving() || berserk_or_insane())
559 {
560 // This should only happen because of fleeing sanctuary
561 msg = " stops retreating.";
562 }
563 else if (!mons_is_tentacle_or_tentacle_segment(type))
564 {
565 msg = " seems to regain " + pronoun(PRONOUN_POSSESSIVE, true)
566 + " courage.";
567 }
568
569 if (!quiet)
570 simple_monster_message(*this, msg.c_str());
571
572 // Reevaluate behaviour.
573 behaviour_event(this, ME_EVAL);
574 break;
575 }
576
577 case ENCH_CONFUSION:
578 if (!quiet)
579 simple_monster_message(*this, " seems less confused.");
580
581 // Reevaluate behaviour.
582 behaviour_event(this, ME_EVAL);
583 break;
584
585 case ENCH_INVIS:
586 // Note: Invisible monsters are not forced to stay invisible, so
587 // that they can properly have their invisibility removed just
588 // before being polymorphed into a non-invisible monster.
589 if (you.see_cell(pos()) && !you.can_see_invisible() && !backlit()
590 && !has_ench(ENCH_SUBMERGED)
591 && !friendly())
592 {
593 if (!quiet)
594 mprf("%s appears from thin air!", name(DESC_A, true).c_str());
595
596 autotoggle_autopickup(false);
597 handle_seen_interrupt(this);
598 }
599 break;
600
601 case ENCH_CHARM:
602 case ENCH_NEUTRAL_BRIBED:
603 case ENCH_FRIENDLY_BRIBED:
604 case ENCH_HEXED:
605 if (invisible() && you.see_cell(pos()) && !you.can_see_invisible()
606 && !backlit() && !has_ench(ENCH_SUBMERGED))
607 {
608 if (!quiet)
609 {
610 if (me.ench == ENCH_CHARM && props.exists("charmed_demon"))
611 {
612 mprf("%s breaks free of your control!",
613 name(DESC_THE, true).c_str());
614 }
615 else
616 mprf("%s is no longer %s.", name(DESC_THE, true).c_str(),
617 me.ench == ENCH_CHARM ? "charmed"
618 : me.ench == ENCH_HEXED ? "hexed"
619 : "bribed");
620
621 mprf("You can %s detect the %s.",
622 friendly() ? "once again" : "no longer",
623 name(DESC_PLAIN, true).c_str());
624 }
625
626 autotoggle_autopickup(friendly());
627 }
628 else
629 {
630 if (!quiet)
631 {
632 if (me.ench == ENCH_CHARM && props.exists("charmed_demon"))
633 {
634 simple_monster_message(*this,
635 " breaks free of your control!");
636 }
637 else
638 simple_monster_message(*this,
639 me.ench == ENCH_CHARM
640 ? " is no longer charmed."
641 : me.ench == ENCH_HEXED
642 ? " is no longer hexed."
643 : " is no longer bribed.");
644 }
645
646 }
647
648 if (you.can_see(*this))
649 {
650 // and fire activity interrupts
651 interrupt_activity(activity_interrupt::see_monster,
652 activity_interrupt_data(this, SC_UNCHARM));
653 }
654
655 if (is_patrolling())
656 {
657 // Charmed monsters stop patrolling and forget their patrol point,
658 // in case they were on order to wait.
659 patrol_point.reset();
660 }
661 mons_att_changed(this);
662
663 // If a greater demon is breaking free, give the player time to respond
664 if (me.ench == ENCH_CHARM && props.exists("charmed_demon"))
665 {
666 speed_increment -= speed;
667 props.erase("charmed_demon");
668 }
669
670 // Reevaluate behaviour.
671 behaviour_event(this, ME_EVAL);
672 break;
673
674 case ENCH_CORONA:
675 case ENCH_SILVER_CORONA:
676 if (!quiet)
677 {
678 if (visible_to(&you))
679 simple_monster_message(*this, " stops glowing.");
680 else if (has_ench(ENCH_INVIS) && you.see_cell(pos()))
681 {
682 mprf("%s stops glowing and disappears.",
683 name(DESC_THE, true).c_str());
684 }
685 }
686 break;
687
688 case ENCH_STICKY_FLAME:
689 if (!quiet)
690 simple_monster_message(*this, " stops burning.");
691 break;
692
693 case ENCH_POISON:
694 if (!quiet)
695 simple_monster_message(*this, " looks more healthy.");
696 break;
697
698 case ENCH_HELD:
699 {
700 int net = get_trapping_net(pos());
701 if (net != NON_ITEM)
702 {
703 free_stationary_net(net);
704
705 if (props.exists(NEWLY_TRAPPED_KEY))
706 props.erase(NEWLY_TRAPPED_KEY);
707
708 if (!quiet)
709 simple_monster_message(*this, " breaks free.");
710 break;
711 }
712
713 monster_web_cleanup(*this, true);
714 break;
715 }
716 case ENCH_FAKE_ABJURATION:
717 if (type == MONS_BATTLESPHERE)
718 return end_battlesphere(this, false);
719 case ENCH_ABJ:
720 if (type == MONS_SPECTRAL_WEAPON)
721 return end_spectral_weapon(this, false);
722 // Set duration to -1 so that monster_die() and any of its
723 // callees can tell that the monster ran out of time or was
724 // abjured.
725 add_ench(mon_enchant(
726 (me.ench != ENCH_FAKE_ABJURATION) ?
727 ENCH_ABJ : ENCH_FAKE_ABJURATION, 0, 0, -1));
728
729 if (berserk())
730 simple_monster_message(*this, " is no longer berserk.");
731
732 monster_die(*this, (me.ench == ENCH_FAKE_ABJURATION) ? KILL_MISC :
733 (quiet) ? KILL_DISMISSED : KILL_RESET, NON_MONSTER);
734 break;
735 case ENCH_SHORT_LIVED:
736 // Conjured ball lightnings explode when they time out.
737 suicide();
738 monster_die(*this, KILL_TIMEOUT, NON_MONSTER);
739 break;
740 case ENCH_SUBMERGED:
741 if (mons_is_wandering(*this))
742 {
743 behaviour = BEH_SEEK;
744 behaviour_event(this, ME_EVAL);
745 }
746
747 if (you.pos() == pos())
748 {
749 // If, despite our best efforts, it unsubmerged on the same
750 // square as the player, teleport it away.
751 monster_teleport(this, true, false);
752 if (you.pos() == pos())
753 {
754 mprf(MSGCH_ERROR, "%s is on the same square as you!",
755 name(DESC_A).c_str());
756 }
757 }
758
759 if (you.can_see(*this))
760 {
761 if (!quiet && feat_is_watery(env.grid(pos())))
762 {
763 mprf(MSGCH_WARN, "%s bursts forth from the water.",
764 name(DESC_A, true).c_str());
765 seen_monster(this);
766 }
767 }
768 else if (you.see_cell(pos()) && feat_is_watery(env.grid(pos())))
769 {
770 mpr("Something invisible bursts forth from the water.");
771 interrupt_activity(activity_interrupt::force);
772 }
773 break;
774
775 case ENCH_SOUL_RIPE:
776 if (!quiet)
777 {
778 simple_monster_message(*this,
779 "'s soul is no longer ripe for the taking.");
780 }
781 break;
782
783 case ENCH_AWAKEN_FOREST:
784 env.forest_awoken_until = 0;
785 if (!quiet)
786 forest_message(pos(), "The forest calms down.");
787 break;
788
789 case ENCH_LIQUEFYING:
790 invalidate_agrid();
791
792 if (!quiet)
793 simple_monster_message(*this, " is no longer liquefying the ground.");
794 break;
795
796 case ENCH_FLIGHT:
797 apply_location_effects(pos(), me.killer(), me.kill_agent());
798 break;
799
800 case ENCH_DAZED:
801 if (!quiet && alive())
802 simple_monster_message(*this, " is no longer dazed.");
803 break;
804
805 case ENCH_INNER_FLAME:
806 if (!quiet && alive())
807 simple_monster_message(*this, "'s inner flame fades away.");
808 break;
809
810 //The following should never happen, but just in case...
811
812 case ENCH_MUTE:
813 if (!quiet && alive())
814 simple_monster_message(*this, " is no longer mute.");
815 break;
816
817 case ENCH_BLIND:
818 if (!quiet && alive())
819 simple_monster_message(*this, " is no longer blind.");
820
821 // Reevaluate behaviour.
822 behaviour_event(this, ME_EVAL);
823 break;
824
825 case ENCH_DUMB:
826 if (!quiet && alive())
827 simple_monster_message(*this, " is no longer stupefied.");
828
829 // Reevaluate behaviour.
830 behaviour_event(this, ME_EVAL);
831 break;
832
833 case ENCH_MAD:
834 if (!quiet && alive())
835 simple_monster_message(*this, " is no longer mad.");
836
837 // Reevaluate behaviour.
838 behaviour_event(this, ME_EVAL);
839 break;
840
841 case ENCH_REGENERATION:
842 if (!quiet)
843 simple_monster_message(*this, " is no longer regenerating.");
844 break;
845
846 case ENCH_STRONG_WILLED:
847 if (!quiet)
848 simple_monster_message(*this, " is no longer strong-willed.");
849 break;
850
851 case ENCH_WRETCHED:
852 if (!quiet)
853 {
854 const string msg = " seems to return to " +
855 pronoun(PRONOUN_POSSESSIVE, true) +
856 " normal shape.";
857 simple_monster_message(*this, msg.c_str());
858 }
859 break;
860
861 case ENCH_FLAYED:
862 heal_flayed_effect(this);
863 break;
864
865 case ENCH_HAUNTING:
866 {
867 mon_enchant abj = get_ench(ENCH_ABJ);
868 abj.degree = 1;
869 abj.duration = min(5 + random2(30), abj.duration);
870 update_ench(abj);
871 break;
872 }
873
874 case ENCH_WEAK:
875 if (!quiet)
876 simple_monster_message(*this, " is no longer weakened.");
877 break;
878
879 case ENCH_AWAKEN_VINES:
880 unawaken_vines(this, quiet);
881 break;
882
883 case ENCH_TOXIC_RADIANCE:
884 if (!quiet && you.can_see(*this))
885 mprf("%s toxic aura wanes.", name(DESC_ITS).c_str());
886 break;
887
888 case ENCH_FIRE_VULN:
889 if (!quiet)
890 simple_monster_message(*this, " is no longer more vulnerable to fire.");
891 break;
892
893 case ENCH_MERFOLK_AVATAR_SONG:
894 props.erase("merfolk_avatar_call");
895 break;
896
897 case ENCH_POISON_VULN:
898 if (!quiet)
899 simple_monster_message(*this, " is no longer more vulnerable to poison.");
900 break;
901
902 case ENCH_ICEMAIL:
903 if (!quiet && you.can_see(*this))
904 {
905 mprf("%s icy envelope dissipates!",
906 apostrophise(name(DESC_THE)).c_str());
907 }
908 break;
909
910 case ENCH_AGILE:
911 if (!quiet)
912 simple_monster_message(*this, " is no longer unusually agile.");
913 break;
914
915 case ENCH_FROZEN:
916 if (!quiet)
917 simple_monster_message(*this, " is no longer encased in ice.");
918 calc_speed();
919 break;
920
921 case ENCH_BLACK_MARK:
922 if (!quiet)
923 {
924 simple_monster_message(*this, " is no longer absorbing vital"
925 " energies.");
926 }
927 calc_speed();
928 break;
929
930 case ENCH_SAP_MAGIC:
931 if (!quiet)
932 simple_monster_message(*this, " is no longer being sapped.");
933 break;
934
935 case ENCH_CORROSION:
936 if (!quiet)
937 simple_monster_message(*this, " is no longer covered in acid.");
938 break;
939
940 case ENCH_GOLD_LUST:
941 if (!quiet)
942 simple_monster_message(*this, " is no longer distracted by gold.");
943 break;
944
945 case ENCH_DRAINED:
946 if (!quiet)
947 simple_monster_message(*this, " seems less drained.");
948 break;
949
950 case ENCH_REPEL_MISSILES:
951 if (!quiet)
952 simple_monster_message(*this, " is no longer repelling missiles.");
953 break;
954
955 case ENCH_RESISTANCE:
956 if (!quiet)
957 simple_monster_message(*this, " is no longer unusually resistant.");
958 break;
959
960 case ENCH_BRILLIANCE_AURA:
961 if (!quiet)
962 simple_monster_message(*this, " is no longer giving off an aura.");
963 break;
964
965 case ENCH_EMPOWERED_SPELLS:
966 if (!quiet)
967 simple_monster_message(*this, " seems less brilliant.");
968 break;
969
970 case ENCH_IDEALISED:
971 if (!quiet)
972 simple_monster_message(*this, " loses the glow of perfection.");
973 break;
974
975 case ENCH_BOUND_SOUL:
976 if (!quiet && you.can_see(*this))
977 mprf("%s soul is no longer bound.", name(DESC_ITS).c_str());
978 break;
979
980 case ENCH_INFESTATION:
981 if (!quiet)
982 simple_monster_message(*this, " is no longer infested.");
983 break;
984
985 case ENCH_VILE_CLUTCH:
986 case ENCH_GRASPING_ROOTS:
987 {
988 const string noun = me.ench == ENCH_VILE_CLUTCH ? "zombie hands"
989 : "roots";
990 if (is_constricted())
991 {
992 // We handle the end-of-enchantment message here since the method
993 // of constriction is no longer detectable.
994 if (!quiet && you.can_see(*this))
995 {
996 mprf("The %s release their grip on %s.", noun.c_str(),
997 name(DESC_THE).c_str());
998 }
999 stop_being_constricted(true);
1000 }
1001 break;
1002 }
1003
1004 case ENCH_STILL_WINDS:
1005 end_still_winds();
1006 break;
1007
1008 case ENCH_WATERLOGGED:
1009 if (!quiet)
1010 simple_monster_message(*this, " is no longer waterlogged.");
1011 break;
1012
1013 case ENCH_ROLLING:
1014 if (!quiet)
1015 simple_monster_message(*this, " stops rolling and uncurls.");
1016 break;
1017
1018 case ENCH_CONCENTRATE_VENOM:
1019 if (!quiet)
1020 simple_monster_message(*this, " no longer looks unusually toxic.");
1021 break;
1022
1023 default:
1024 break;
1025 }
1026 }
1027
lose_ench_levels(const mon_enchant & e,int lev,bool infinite)1028 bool monster::lose_ench_levels(const mon_enchant &e, int lev, bool infinite)
1029 {
1030 if (!lev)
1031 return false;
1032
1033 if (e.duration >= INFINITE_DURATION && !infinite)
1034 return false;
1035 if (e.degree <= lev)
1036 {
1037 del_ench(e.ench);
1038 return true;
1039 }
1040 else
1041 {
1042 mon_enchant newe(e);
1043 newe.degree -= lev;
1044 update_ench(newe);
1045 return false;
1046 }
1047 }
1048
lose_ench_duration(const mon_enchant & e,int dur)1049 bool monster::lose_ench_duration(const mon_enchant &e, int dur)
1050 {
1051 if (!dur)
1052 return false;
1053
1054 if (e.duration >= INFINITE_DURATION)
1055 return false;
1056 if (e.duration <= dur)
1057 {
1058 del_ench(e.ench);
1059 return true;
1060 }
1061 else
1062 {
1063 mon_enchant newe(e);
1064 newe.duration -= dur;
1065 update_ench(newe);
1066 return false;
1067 }
1068 }
1069
describe_enchantments() const1070 string monster::describe_enchantments() const
1071 {
1072 ostringstream oss;
1073 for (auto i = enchantments.begin(); i != enchantments.end(); ++i)
1074 {
1075 if (i != enchantments.begin())
1076 oss << ", ";
1077 oss << string(i->second);
1078 }
1079 return oss.str();
1080 }
1081
decay_enchantment(enchant_type en,bool decay_degree)1082 bool monster::decay_enchantment(enchant_type en, bool decay_degree)
1083 {
1084 if (!has_ench(en))
1085 return false;
1086
1087 const mon_enchant& me(get_ench(en));
1088
1089 if (me.duration >= INFINITE_DURATION)
1090 return false;
1091
1092 // Gozag-incited haste/berserk is permanent.
1093 if (has_ench(ENCH_GOZAG_INCITE)
1094 && (en == ENCH_HASTE || en == ENCH_BERSERK))
1095 {
1096 return false;
1097 }
1098
1099 // Faster monsters can wiggle out of the net more quickly.
1100 const int spd = (me.ench == ENCH_HELD) ? speed :
1101 10;
1102 int actdur = speed_to_duration(spd);
1103
1104 // Don't let ENCH_SLOW time out while a torpor snail is around.
1105 if (en == ENCH_SLOW)
1106 {
1107 if (torpor_slowed())
1108 actdur = min(actdur, me.duration - 1);
1109 else
1110 props.erase(TORPOR_SLOWED_KEY);
1111 }
1112
1113 if (lose_ench_duration(me, actdur))
1114 return true;
1115
1116 if (!decay_degree)
1117 return false;
1118
1119 // Decay degree so that higher degrees decay faster than lower
1120 // degrees, and a degree of 1 does not decay (it expires when the
1121 // duration runs out).
1122 const int level = me.degree;
1123 if (level <= 1)
1124 return false;
1125
1126 const int decay_factor = level * (level + 1) / 2;
1127 if (me.duration < me.maxduration * (decay_factor - 1) / decay_factor)
1128 {
1129 mon_enchant newme = me;
1130 --newme.degree;
1131 newme.maxduration = newme.duration;
1132
1133 if (newme.degree <= 0)
1134 {
1135 del_ench(me.ench);
1136 return true;
1137 }
1138 else
1139 update_ench(newme);
1140 }
1141 return false;
1142 }
1143
clear_far_engulf(bool)1144 bool monster::clear_far_engulf(bool)
1145 {
1146 if (you.duration[DUR_WATER_HOLD]
1147 && (mid_t) you.props["water_holder"].get_int() == mid)
1148 {
1149 you.clear_far_engulf();
1150 }
1151
1152 const mon_enchant& me = get_ench(ENCH_WATER_HOLD);
1153 if (me.ench == ENCH_NONE)
1154 return false;
1155 const bool nonadj = !me.agent() || !adjacent(me.agent()->pos(), pos());
1156 if (nonadj)
1157 del_ench(ENCH_WATER_HOLD);
1158 return nonadj;
1159 }
1160
1161 // Returns true if you resist the merfolk avatar's call.
_merfolk_avatar_movement_effect(const monster * mons)1162 static bool _merfolk_avatar_movement_effect(const monster* mons)
1163 {
1164 bool do_resist = (you.attribute[ATTR_HELD]
1165 || you.duration[DUR_TIME_STEP]
1166 || you.cannot_act()
1167 || you.clarity()
1168 || you.is_stationary());
1169
1170 if (!do_resist)
1171 {
1172 // We use a beam tracer here since it is better at navigating
1173 // obstructing walls than merely comparing our relative positions
1174 bolt tracer;
1175 tracer.pierce = true;
1176 tracer.affects_nothing = true;
1177 tracer.target = mons->pos();
1178 tracer.source = you.pos();
1179 tracer.range = LOS_RADIUS;
1180 tracer.is_tracer = true;
1181 tracer.aimed_at_spot = true;
1182 tracer.fire();
1183
1184 const coord_def newpos = tracer.path_taken[0];
1185
1186 if (!in_bounds(newpos)
1187 || is_feat_dangerous(env.grid(newpos))
1188 || !you.can_pass_through_feat(env.grid(newpos))
1189 || !cell_see_cell(mons->pos(), newpos, LOS_NO_TRANS))
1190 {
1191 do_resist = true;
1192 }
1193 else
1194 {
1195 bool swapping = false;
1196 monster* mon = monster_at(newpos);
1197 if (mon)
1198 {
1199 coord_def swapdest;
1200 if (mon->wont_attack()
1201 && !mon->is_stationary()
1202 && !mons_is_projectile(*mon)
1203 && !mon->cannot_act()
1204 && !mon->asleep()
1205 && swap_check(mon, swapdest, true))
1206 {
1207 swapping = true;
1208 }
1209 else if (!mon->submerged())
1210 do_resist = true;
1211 }
1212
1213 if (!do_resist)
1214 {
1215 const coord_def oldpos = you.pos();
1216 mpr("The pull of its song draws you forwards.");
1217
1218 if (swapping)
1219 {
1220 if (monster_at(oldpos))
1221 {
1222 mprf("Something prevents you from swapping places "
1223 "with %s.",
1224 mon->name(DESC_THE).c_str());
1225 return do_resist;
1226 }
1227
1228 int swap_mon = env.mgrid(newpos);
1229 // Pick the monster up.
1230 env.mgrid(newpos) = NON_MONSTER;
1231 mon->moveto(oldpos);
1232
1233 // Plunk it down.
1234 env.mgrid(mon->pos()) = swap_mon;
1235
1236 mprf("You swap places with %s.",
1237 mon->name(DESC_THE).c_str());
1238 }
1239 move_player_to_grid(newpos, true);
1240 stop_delay(true);
1241
1242 if (swapping)
1243 mon->apply_location_effects(newpos);
1244 }
1245 }
1246 }
1247
1248 return do_resist;
1249 }
1250
_merfolk_avatar_song(monster * mons)1251 static void _merfolk_avatar_song(monster* mons)
1252 {
1253 // First, attempt to pull the player, if mesmerised
1254 if (you.beheld_by(*mons) && coinflip())
1255 {
1256 // Don't pull the player if they walked forward voluntarily this
1257 // turn (to avoid making you jump two spaces at once)
1258 if (!mons->props["foe_approaching"].get_bool())
1259 {
1260 _merfolk_avatar_movement_effect(mons);
1261
1262 // Reset foe tracking position so that we won't automatically
1263 // veto pulling on a subsequent turn because you 'approached'
1264 mons->props["foe_pos"].get_coord() = you.pos();
1265 }
1266 }
1267
1268 // Only call up drowned souls if we're largely alone; otherwise our
1269 // mesmerisation can support the present allies well enough.
1270 int ally_hd = 0;
1271 for (monster_near_iterator mi(you.pos()); mi; ++mi)
1272 {
1273 if (*mi != mons && mons_aligned(mons, *mi) && mons_is_threatening(**mi)
1274 && mi->type != MONS_DROWNED_SOUL)
1275 {
1276 ally_hd += mi->get_experience_level();
1277 }
1278 }
1279 if (ally_hd > mons->get_experience_level())
1280 {
1281 if (mons->props.exists("merfolk_avatar_call"))
1282 {
1283 // Normally can only happen if allies of the merfolk avatar show up
1284 // during a song that has already summoned drowned souls (though is
1285 // technically possible if some existing ally gains HD instead)
1286 if (you.see_cell(mons->pos()))
1287 mpr("The shadowy forms in the deep grow still as others approach.");
1288 mons->props.erase("merfolk_avatar_call");
1289 }
1290
1291 return;
1292 }
1293
1294 // Can only call up drowned souls if there's free deep water nearby
1295 vector<coord_def> deep_water;
1296 for (radius_iterator ri(mons->pos(), LOS_RADIUS, C_SQUARE); ri; ++ri)
1297 if (env.grid(*ri) == DNGN_DEEP_WATER && !actor_at(*ri))
1298 deep_water.push_back(*ri);
1299
1300 if (deep_water.size())
1301 {
1302 if (!mons->props.exists("merfolk_avatar_call"))
1303 {
1304 if (you.see_cell(mons->pos()))
1305 {
1306 mprf("Shadowy forms rise from the deep at %s song!",
1307 mons->name(DESC_ITS).c_str());
1308 }
1309 mons->props["merfolk_avatar_call"].get_bool() = true;
1310 }
1311
1312 if (coinflip())
1313 {
1314 int num = 1 + one_chance_in(4);
1315 shuffle_array(deep_water);
1316
1317 int existing = 0;
1318 for (monster_near_iterator mi(mons); mi; ++mi)
1319 {
1320 if (mi->type == MONS_DROWNED_SOUL)
1321 existing++;
1322 }
1323 num = min(min(num, 5 - existing), int(deep_water.size()));
1324
1325 for (int i = 0; i < num; ++i)
1326 {
1327 monster* soul = create_monster(
1328 mgen_data(MONS_DROWNED_SOUL, SAME_ATTITUDE(mons),
1329 deep_water[i], mons->foe, MG_FORCE_PLACE)
1330 .set_summoned(mons, 1, SPELL_NO_SPELL));
1331
1332 // Scale down drowned soul damage for low level merfolk avatars
1333 if (soul)
1334 soul->set_hit_dice(mons->get_hit_dice());
1335 }
1336 }
1337 }
1338 }
1339
apply_enchantment(const mon_enchant & me)1340 void monster::apply_enchantment(const mon_enchant &me)
1341 {
1342 enchant_type en = me.ench;
1343 switch (me.ench)
1344 {
1345 case ENCH_INSANE:
1346 if (decay_enchantment(en))
1347 {
1348 simple_monster_message(*this, " is no longer in an insane frenzy.");
1349 const int duration = random_range(70, 130);
1350 add_ench(mon_enchant(ENCH_FATIGUE, 0, 0, duration));
1351 add_ench(mon_enchant(ENCH_SLOW, 0, 0, duration));
1352 }
1353 break;
1354
1355 case ENCH_BERSERK:
1356 if (decay_enchantment(en))
1357 {
1358 simple_monster_message(*this, " is no longer berserk.");
1359 const int duration = random_range(70, 130);
1360 add_ench(mon_enchant(ENCH_FATIGUE, 0, 0, duration));
1361 add_ench(mon_enchant(ENCH_SLOW, 0, 0, duration));
1362 }
1363 break;
1364
1365 case ENCH_FATIGUE:
1366 if (decay_enchantment(en))
1367 {
1368 simple_monster_message(*this, " looks more energetic.");
1369 del_ench(ENCH_SLOW, true);
1370 }
1371 break;
1372
1373 case ENCH_SLOW:
1374 case ENCH_HASTE:
1375 case ENCH_SWIFT:
1376 case ENCH_MIGHT:
1377 case ENCH_FEAR:
1378 case ENCH_PARALYSIS:
1379 case ENCH_PETRIFYING:
1380 case ENCH_PETRIFIED:
1381 case ENCH_SICK:
1382 case ENCH_CORONA:
1383 case ENCH_ABJ:
1384 case ENCH_CHARM:
1385 case ENCH_SLEEP_WARY:
1386 case ENCH_LOWERED_WL:
1387 case ENCH_SOUL_RIPE:
1388 case ENCH_TIDE:
1389 case ENCH_REGENERATION:
1390 case ENCH_STRONG_WILLED:
1391 case ENCH_IDEALISED:
1392 case ENCH_LIFE_TIMER:
1393 case ENCH_FLIGHT:
1394 case ENCH_DAZED:
1395 case ENCH_FAKE_ABJURATION:
1396 case ENCH_RECITE_TIMER:
1397 case ENCH_INNER_FLAME:
1398 case ENCH_MUTE:
1399 case ENCH_BLIND:
1400 case ENCH_DUMB:
1401 case ENCH_MAD:
1402 case ENCH_WRETCHED:
1403 case ENCH_SCREAMED:
1404 case ENCH_WEAK:
1405 case ENCH_AWAKEN_VINES:
1406 case ENCH_FIRE_VULN:
1407 case ENCH_BARBS:
1408 case ENCH_POISON_VULN:
1409 case ENCH_DIMENSION_ANCHOR:
1410 case ENCH_AGILE:
1411 case ENCH_FROZEN:
1412 case ENCH_SAP_MAGIC:
1413 case ENCH_CORROSION:
1414 case ENCH_GOLD_LUST:
1415 case ENCH_RESISTANCE:
1416 case ENCH_HEXED:
1417 case ENCH_BRILLIANCE_AURA:
1418 case ENCH_EMPOWERED_SPELLS:
1419 case ENCH_ANTIMAGIC:
1420 case ENCH_BOUND_SOUL:
1421 case ENCH_INFESTATION:
1422 case ENCH_BLACK_MARK:
1423 case ENCH_STILL_WINDS:
1424 case ENCH_VILE_CLUTCH:
1425 case ENCH_GRASPING_ROOTS:
1426 case ENCH_WATERLOGGED:
1427 case ENCH_ROLLING:
1428 decay_enchantment(en);
1429 break;
1430
1431 case ENCH_MIRROR_DAMAGE:
1432 if (decay_enchantment(en))
1433 simple_monster_message(*this, "'s dark mirror aura disappears.");
1434 break;
1435
1436 case ENCH_SILENCE:
1437 case ENCH_LIQUEFYING:
1438 decay_enchantment(en);
1439 invalidate_agrid();
1440 break;
1441
1442 case ENCH_DRAINED:
1443 decay_enchantment(en, false);
1444 break;
1445
1446 case ENCH_AQUATIC_LAND:
1447 // Aquatic monsters lose hit points every turn they spend on dry land.
1448 ASSERT(mons_habitat(*this) == HT_WATER || mons_habitat(*this) == HT_LAVA);
1449 if (monster_habitable_grid(this, env.grid(pos())))
1450 {
1451 del_ench(ENCH_AQUATIC_LAND);
1452 break;
1453 }
1454
1455 // Zombies don't take damage from flopping about on land.
1456 if (mons_is_zombified(*this))
1457 break;
1458
1459 hurt(me.agent(), 1 + random2(5), BEAM_NONE);
1460 break;
1461
1462 case ENCH_HELD:
1463 break; // handled in mon-act.cc:struggle_against_net()
1464 case ENCH_BREATH_WEAPON:
1465 break; // handled in mon-act.cc:catch_breath()
1466
1467 case ENCH_CONFUSION:
1468 if (!mons_class_flag(type, M_CONFUSED))
1469 decay_enchantment(en);
1470 break;
1471
1472 case ENCH_INVIS:
1473 if (!mons_class_flag(type, M_INVIS))
1474 decay_enchantment(en);
1475 break;
1476
1477 case ENCH_SUBMERGED:
1478 {
1479 // Don't unsubmerge into a harmful cloud
1480 if (!is_harmless_cloud(cloud_type_at(pos())))
1481 break;
1482
1483 // Now we handle the others:
1484 const dungeon_feature_type grid = env.grid(pos());
1485
1486 if (!monster_can_submerge(this, grid))
1487 del_ench(ENCH_SUBMERGED); // forced to surface
1488 break;
1489 }
1490 case ENCH_POISON:
1491 {
1492 const int poisonval = me.degree;
1493 int dam = (poisonval >= 4) ? 1 : 0;
1494
1495 if (coinflip())
1496 dam += roll_dice(1, poisonval + 1);
1497
1498 if (res_poison() < 0)
1499 dam += roll_dice(2, poisonval) - 1;
1500
1501 if (dam > 0)
1502 {
1503 dprf("%s takes poison damage: %d (degree %d)",
1504 name(DESC_THE).c_str(), dam, me.degree);
1505
1506 hurt(me.agent(), dam, BEAM_POISON, KILLED_BY_POISON);
1507 }
1508
1509 decay_enchantment(en, true);
1510 break;
1511 }
1512
1513 // Assumption: monster::res_fire has already been checked.
1514 case ENCH_STICKY_FLAME:
1515 {
1516 if (feat_is_watery(env.grid(pos())) && ground_level())
1517 {
1518 if (you.can_see(*this))
1519 {
1520 mprf("The flames covering %s go out.",
1521 name(DESC_THE, false).c_str());
1522 }
1523 del_ench(ENCH_STICKY_FLAME);
1524 break;
1525 }
1526 const int dam = resist_adjust_damage(this, BEAM_FIRE,
1527 roll_dice(2, 4) - 1);
1528
1529 if (dam > 0)
1530 {
1531 simple_monster_message(*this, " burns!");
1532 dprf("sticky flame damage: %d", dam);
1533 hurt(me.agent(), dam, BEAM_STICKY_FLAME);
1534 }
1535
1536 decay_enchantment(en, true);
1537 break;
1538 }
1539
1540 case ENCH_SHORT_LIVED:
1541 // This should only be used for ball lightning -- bwr
1542 if (decay_enchantment(en))
1543 suicide();
1544 break;
1545
1546 case ENCH_SLOWLY_DYING:
1547 // If you are no longer dying, you must be dead.
1548 if (decay_enchantment(en))
1549 {
1550 if (you.can_see(*this))
1551 {
1552 switch (type)
1553 {
1554 case MONS_PILLAR_OF_SALT:
1555 case MONS_WITHERED_PLANT:
1556 mprf("%s crumbles away.", name(DESC_THE, false).c_str());
1557 break;
1558 case MONS_BLOCK_OF_ICE:
1559 mprf("%s melts away.", name(DESC_THE, false).c_str());
1560 break;
1561 default:
1562 mprf("A nearby %s withers and dies.",
1563 name(DESC_PLAIN, false).c_str());
1564 break;
1565
1566 }
1567 }
1568
1569 monster_die(*this, KILL_MISC, NON_MONSTER, true);
1570 }
1571 break;
1572
1573 case ENCH_EXPLODING:
1574 {
1575 // Reduce the timer, if that means we lose the enchantment then
1576 // spawn a spore and re-add the enchantment
1577 if (decay_enchantment(en))
1578 {
1579 monster_type mtype = type;
1580 bolt beam;
1581
1582 setup_spore_explosion(beam, *this);
1583
1584 beam.explode();
1585
1586 // Ballistos are immune to their own explosions, but must
1587 // die some time
1588 this->set_hit_dice(this->get_experience_level() - 1);
1589 if (this->get_experience_level() <= 0)
1590 this->self_destruct();
1591
1592 // The ballisto dying, then a spore being created in its slot
1593 // env.mons means we can appear to be alive, but in fact be
1594 // an entirely different monster.
1595 if (alive() && type == mtype)
1596 add_ench(ENCH_EXPLODING);
1597 }
1598
1599 }
1600 break;
1601
1602 case ENCH_PORTAL_TIMER:
1603 {
1604 if (decay_enchantment(en))
1605 {
1606 coord_def base_position = props["base_position"].get_coord();
1607 // Do a thing.
1608 if (you.see_cell(base_position))
1609 mprf("The portal closes; %s is severed.", name(DESC_THE).c_str());
1610
1611 if (env.grid(base_position) == DNGN_MALIGN_GATEWAY)
1612 env.grid(base_position) = DNGN_FLOOR;
1613
1614 maybe_bloodify_square(base_position);
1615 add_ench(ENCH_SEVERED);
1616
1617 // Severed tentacles immediately become "hostile" to everyone
1618 // (or insane)
1619 attitude = ATT_NEUTRAL;
1620 mons_att_changed(this);
1621 if (!crawl_state.game_is_arena())
1622 behaviour_event(this, ME_ALERT);
1623 }
1624 }
1625 break;
1626
1627 case ENCH_PORTAL_PACIFIED:
1628 {
1629 if (decay_enchantment(en))
1630 {
1631 if (has_ench(ENCH_SEVERED))
1632 break;
1633
1634 if (!friendly())
1635 break;
1636
1637 if (!silenced(you.pos()))
1638 {
1639 if (you.can_see(*this))
1640 simple_monster_message(*this, " suddenly becomes enraged!");
1641 else
1642 mpr("You hear a distant and violent thrashing sound.");
1643 }
1644
1645 attitude = ATT_HOSTILE;
1646 mons_att_changed(this);
1647 if (!crawl_state.game_is_arena())
1648 behaviour_event(this, ME_ALERT, &you);
1649 }
1650 }
1651 break;
1652
1653 case ENCH_SEVERED:
1654 {
1655 simple_monster_message(*this, " writhes!");
1656 coord_def base_position = props["base_position"].get_coord();
1657 maybe_bloodify_square(base_position);
1658 hurt(me.agent(), 20);
1659 }
1660
1661 break;
1662
1663 case ENCH_GLOWING_SHAPESHIFTER: // This ench never runs out!
1664 // Number of actions is fine for shapeshifters. Don't change
1665 // shape while taking the stairs because monster_polymorph() has
1666 // an assert about it. -cao
1667 if (!(flags & MF_TAKING_STAIRS)
1668 && !(paralysed() || petrified() || petrifying() || asleep())
1669 && (type == MONS_GLOWING_SHAPESHIFTER
1670 || one_chance_in(4)))
1671 {
1672 monster_polymorph(this, RANDOM_MONSTER);
1673 }
1674 break;
1675
1676 case ENCH_SHAPESHIFTER: // This ench never runs out!
1677 if (!(flags & MF_TAKING_STAIRS)
1678 && !(paralysed() || petrified() || petrifying() || asleep())
1679 && (type == MONS_SHAPESHIFTER
1680 || x_chance_in_y(1000 / (15 * max(1, get_hit_dice()) / 5),
1681 1000)))
1682 {
1683 monster_polymorph(this, RANDOM_MONSTER);
1684 }
1685 break;
1686
1687 case ENCH_TP:
1688 if (decay_enchantment(en, true) && !no_tele(true, false))
1689 monster_teleport(this, true);
1690 break;
1691
1692 case ENCH_AWAKEN_FOREST:
1693 forest_damage(this);
1694 decay_enchantment(en);
1695 break;
1696
1697 case ENCH_POLAR_VORTEX:
1698 polar_vortex_damage(this, speed_to_duration(speed));
1699 if (decay_enchantment(en))
1700 {
1701 add_ench(ENCH_POLAR_VORTEX_COOLDOWN);
1702 if (you.can_see(*this))
1703 {
1704 mprf("The winds around %s start to calm down.",
1705 name(DESC_THE).c_str());
1706 }
1707 }
1708 break;
1709
1710 // This is like Corona, but if silver harms them, it has sticky
1711 // flame levels of damage.
1712 case ENCH_SILVER_CORONA:
1713 if (how_chaotic())
1714 {
1715 int dam = roll_dice(2, 4) - 1;
1716 simple_monster_message(*this, " is seared!");
1717 dprf("Zin's Corona damage: %d", dam);
1718 hurt(me.agent(), dam);
1719 }
1720
1721 decay_enchantment(en, true);
1722 break;
1723
1724 case ENCH_WORD_OF_RECALL:
1725 // If we've gotten silenced or somehow incapacitated since we started,
1726 // cancel the recitation
1727 if (is_silenced() || cannot_act() || has_ench(ENCH_BREATH_WEAPON)
1728 || confused() || asleep() || has_ench(ENCH_FEAR))
1729 {
1730 del_ench(en, true, false);
1731 if (you.can_see(*this))
1732 mprf("%s chant is interrupted.", name(DESC_ITS).c_str());
1733 break;
1734 }
1735
1736 if (decay_enchantment(en))
1737 {
1738 const int breath_timeout_turns = random_range(4, 12);
1739
1740 mons_word_of_recall(this, random_range(3, 7));
1741 add_ench(mon_enchant(ENCH_BREATH_WEAPON, 1, this,
1742 breath_timeout_turns * BASELINE_DELAY));
1743 }
1744 break;
1745
1746 case ENCH_INJURY_BOND:
1747 // It's hard to absorb someone else's injuries when you're dead
1748 if (!me.agent() || !me.agent()->alive()
1749 || me.agent()->mid == MID_ANON_FRIEND)
1750 {
1751 del_ench(ENCH_INJURY_BOND, true, false);
1752 }
1753 else
1754 decay_enchantment(en);
1755 break;
1756
1757 case ENCH_WATER_HOLD:
1758 if (!clear_far_engulf())
1759 {
1760 if (res_water_drowning() <= 0)
1761 {
1762 lose_ench_duration(me, -speed_to_duration(speed));
1763 int dur = speed_to_duration(speed); // sequence point for randomness
1764 int dam = div_rand_round((50 + stepdown((float)me.duration, 30.0))
1765 * dur,
1766 BASELINE_DELAY * 10);
1767 if (dam > 0)
1768 {
1769 simple_monster_message(*this, " is asphyxiated!");
1770 hurt(me.agent(), dam);
1771 }
1772 }
1773 }
1774 break;
1775
1776 case ENCH_FLAYED:
1777 {
1778 bool near_ghost = false;
1779 for (monster_iterator mi; mi; ++mi)
1780 {
1781 if (mi->type == MONS_FLAYED_GHOST && !mons_aligned(this, *mi)
1782 && see_cell(mi->pos()))
1783 {
1784 near_ghost = true;
1785 break;
1786 }
1787 }
1788 if (!near_ghost)
1789 decay_enchantment(en);
1790
1791 break;
1792 }
1793
1794 case ENCH_HAUNTING:
1795 if (!me.agent() || !me.agent()->alive())
1796 del_ench(ENCH_HAUNTING);
1797 break;
1798
1799 case ENCH_TOXIC_RADIANCE:
1800 toxic_radiance_effect(this, 10);
1801 decay_enchantment(en);
1802 break;
1803
1804 case ENCH_POLAR_VORTEX_COOLDOWN:
1805 if (decay_enchantment(en))
1806 {
1807 remove_vortex_clouds(mid);
1808 if (you.can_see(*this))
1809 mprf("The winds around %s calm down.", name(DESC_THE).c_str());
1810 }
1811 break;
1812
1813 case ENCH_MERFOLK_AVATAR_SONG:
1814 // If we've gotten silenced or somehow incapacitated since we started,
1815 // cancel the song
1816 if (silenced(pos()) || paralysed() || petrified()
1817 || confused() || asleep() || has_ench(ENCH_FEAR))
1818 {
1819 del_ench(ENCH_MERFOLK_AVATAR_SONG, true, false);
1820 if (you.can_see(*this))
1821 {
1822 mprf("%s song is interrupted.",
1823 name(DESC_ITS).c_str());
1824 }
1825 break;
1826 }
1827
1828 _merfolk_avatar_song(this);
1829
1830 // The merfolk avatar will stop singing without her audience
1831 if (!see_cell_no_trans(you.pos()))
1832 decay_enchantment(en);
1833
1834 break;
1835
1836 case ENCH_PAIN_BOND:
1837 if (decay_enchantment(en))
1838 {
1839 const string msg = " is no longer sharing " +
1840 pronoun(PRONOUN_POSSESSIVE, true) +
1841 " pain.";
1842 simple_monster_message(*this, msg.c_str());
1843 }
1844 break;
1845
1846 default:
1847 break;
1848 }
1849 }
1850
mark_summoned(int longevity,bool mark_items,int summon_type,bool abj)1851 void monster::mark_summoned(int longevity, bool mark_items, int summon_type, bool abj)
1852 {
1853 if (abj)
1854 add_ench(mon_enchant(ENCH_ABJ, longevity));
1855 if (summon_type != 0)
1856 add_ench(mon_enchant(ENCH_SUMMON, summon_type, 0, INT_MAX));
1857
1858 if (mark_items)
1859 for (mon_inv_iterator ii(*this); ii; ++ii)
1860 ii->flags |= ISFLAG_SUMMONED;
1861 }
1862
1863 /* Is the monster temporarily summoned?
1864 *
1865 * Monsters must have ENCH_ABJ (giving how long they last) to be considered
1866 * summons. If they additionally set ENCH_SUMMON, which gives how they were
1867 * derived, this must not be from certain spells or "monster summoning types"
1868 * we don't consider actual summons. Temporary monsters with
1869 * ENCH_FAKE_ABJURATION also aren't summons, and durably summoned monsters
1870 * aren't temporary.
1871 *
1872 * @param[out] duration The monster's summon duration in aut.
1873 * @param[out] summon_type The monster's means of summoning. If negative, this
1874 * is a mon_summon_type, otherwise it's a spell_type.
1875 * @returns True if the monster is a temporary summon, false otherwise.
1876 */
is_summoned(int * duration,int * summon_type) const1877 bool monster::is_summoned(int* duration, int* summon_type) const
1878 {
1879 const mon_enchant abj = get_ench(ENCH_ABJ);
1880 if (abj.ench == ENCH_NONE)
1881 {
1882 if (duration != nullptr)
1883 *duration = -1;
1884 if (summon_type != nullptr)
1885 *summon_type = 0;
1886
1887 return false;
1888 }
1889 if (duration != nullptr)
1890 *duration = abj.duration;
1891
1892 const mon_enchant summ = get_ench(ENCH_SUMMON);
1893 if (summ.ench == ENCH_NONE)
1894 {
1895 if (summon_type != nullptr)
1896 *summon_type = 0;
1897
1898 return true;
1899 }
1900 if (summon_type != nullptr)
1901 *summon_type = summ.degree;
1902
1903 // Conjured things (fire vortices, ball lightning, IOOD) are not summoned.
1904 if (mons_is_conjured(type))
1905 return false;
1906
1907 // Certain spells or monster summon types that set abjuration but aren't
1908 // considered summons.
1909 switch (summ.degree)
1910 {
1911 // Temporarily dancing weapons are really there.
1912 case SPELL_TUKIMAS_DANCE:
1913
1914 // Clones aren't really summoned (though their equipment might be).
1915 case MON_SUMM_CLONE:
1916
1917 // Nor are body parts.
1918 case SPELL_CREATE_TENTACLES:
1919
1920 // Some object which was animated, and thus not really summoned.
1921 case MON_SUMM_ANIMATE:
1922 return false;
1923 }
1924
1925 return true;
1926 }
1927
is_perm_summoned() const1928 bool monster::is_perm_summoned() const
1929 {
1930 return testbits(flags, MF_HARD_RESET | MF_NO_REWARD);
1931 }
1932
apply_enchantments()1933 void monster::apply_enchantments()
1934 {
1935 if (enchantments.empty())
1936 return;
1937
1938 // We process an enchantment only if it existed both at the start of this
1939 // function and when getting to it in order; any enchantment can add, modify
1940 // or remove others -- or even itself.
1941 FixedBitVector<NUM_ENCHANTMENTS> ec = ench_cache;
1942
1943 // The ordering in enchant_type makes sure that "super-enchantments"
1944 // like berserk time out before their parts.
1945 for (int i = 0; i < NUM_ENCHANTMENTS; ++i)
1946 if (ec[i] && has_ench(static_cast<enchant_type>(i)))
1947 apply_enchantment(enchantments.find(static_cast<enchant_type>(i))->second);
1948 }
1949
1950 // Used to adjust time durations in calc_duration() for monster speed.
_mod_speed(int val,int speed)1951 static inline int _mod_speed(int val, int speed)
1952 {
1953 if (!speed)
1954 speed = BASELINE_DELAY;
1955 const int modded = val * BASELINE_DELAY / speed;
1956 return modded? modded : 1;
1957 }
1958
1959 /////////////////////////////////////////////////////////////////////////
1960 // mon_enchant
1961
1962 static const char *enchant_names[] =
1963 {
1964 "none", "berserk", "haste", "might", "fatigue", "slow", "fear",
1965 "confusion", "invis", "poison",
1966 #if TAG_MAJOR_VERSION == 34
1967 "rot",
1968 #endif
1969 "summon", "abj", "corona",
1970 "charm", "sticky_flame", "glowing_shapeshifter", "shapeshifter", "tp",
1971 "sleep_wary", "submerged", "short_lived", "paralysis", "sick",
1972 #if TAG_MAJOR_VERSION == 34
1973 "sleepy",
1974 #endif
1975 "held",
1976 #if TAG_MAJOR_VERSION == 34
1977 "battle_frenzy", "temp_pacif",
1978 #endif
1979 "petrifying",
1980 "petrified", "lowered_mr", "soul_ripe", "slowly_dying",
1981 #if TAG_MAJOR_VERSION == 34
1982 "eat_items",
1983 #endif
1984 "aquatic_land",
1985 #if TAG_MAJOR_VERSION == 34
1986 "spore_production",
1987 "slouch",
1988 #endif
1989 "swift", "tide",
1990 "insane", "silenced", "awaken_forest", "exploding",
1991 #if TAG_MAJOR_VERSION == 34
1992 "bleeding",
1993 #endif
1994 "tethered", "severed", "antimagic",
1995 #if TAG_MAJOR_VERSION == 34
1996 "fading_away", "preparing_resurrect",
1997 #endif
1998 "regen",
1999 "magic_res", "mirror_dam",
2000 #if TAG_MAJOR_VERSION == 34
2001 "stoneskin", "fear inspiring",
2002 #endif
2003 "temporarily pacified",
2004 #if TAG_MAJOR_VERSION == 34
2005 "withdrawn", "attached",
2006 #endif
2007 "guardian_timer", "flight", "liquefying", "polar_vortex", "fake_abjuration",
2008 "dazed", "mute", "blind", "dumb", "mad", "silver_corona", "recite timer",
2009 "inner_flame",
2010 #if TAG_MAJOR_VERSION == 34
2011 "roused",
2012 #endif
2013 "breath timer",
2014 #if TAG_MAJOR_VERSION == 34
2015 "deaths_door",
2016 #endif
2017 "rolling",
2018 #if TAG_MAJOR_VERSION == 34
2019 "ozocubus_armour",
2020 #endif
2021 "wretched", "screamed", "rune_of_recall",
2022 "injury bond", "drowning", "flayed", "haunting",
2023 #if TAG_MAJOR_VERSION == 34
2024 "retching",
2025 #endif
2026 "weak", "dimension_anchor", "awaken vines",
2027 #if TAG_MAJOR_VERSION == 34
2028 "control_winds", "wind_aided",
2029 #endif
2030 "summon_capped",
2031 "toxic_radiance",
2032 #if TAG_MAJOR_VERSION == 34
2033 "grasping_roots_source",
2034 #endif
2035 "grasping_roots",
2036 "iood_charged", "fire_vuln", "polar_vortex_cooldown", "merfolk_avatar_song",
2037 "barbs",
2038 #if TAG_MAJOR_VERSION == 34
2039 "building_charge",
2040 #endif
2041 "poison_vuln", "icemail", "agile",
2042 "frozen",
2043 #if TAG_MAJOR_VERSION == 34
2044 "ephemeral_infusion",
2045 #endif
2046 "black_mark",
2047 #if TAG_MAJOR_VERSION == 34
2048 "grand_avatar",
2049 #endif
2050 "sap magic",
2051 #if TAG_MAJOR_VERSION == 34
2052 "shroud",
2053 #endif
2054 "phantom_mirror", "bribed", "permabribed",
2055 "corrosion", "gold_lust", "drained", "repel missiles",
2056 #if TAG_MAJOR_VERSION == 34
2057 "deflect missiles",
2058 "negative_vuln", "condensation_shield",
2059 #endif
2060 "resistant", "hexed",
2061 #if TAG_MAJOR_VERSION == 34
2062 "corpse_armour",
2063 "chanting_fire_storm", "chanting_word_of_entropy",
2064 #endif
2065 "aura_of_brilliance", "empowered_spells", "gozag_incite", "pain_bond",
2066 "idealised", "bound_soul", "infestation",
2067 "stilling the winds", "thunder_ringed",
2068 #if TAG_MAJOR_VERSION == 34
2069 "pinned_by_whirlwind", "vortex", "vortex_cooldown",
2070 #endif
2071 "vile_clutch", "waterlogged", "ring_of_flames",
2072 "ring_chaos", "ring_mutation", "ring_fog", "ring_ice", "ring_neg",
2073 "ring_acid", "ring_miasma", "concentrate_venom",
2074 "buggy", // NUM_ENCHANTMENTS
2075 };
2076
_mons_enchantment_name(enchant_type ench)2077 static const char *_mons_enchantment_name(enchant_type ench)
2078 {
2079 COMPILE_CHECK(ARRAYSZ(enchant_names) == NUM_ENCHANTMENTS+1);
2080
2081 if (ench > NUM_ENCHANTMENTS)
2082 ench = NUM_ENCHANTMENTS;
2083
2084 return enchant_names[ench];
2085 }
2086
name_to_ench(const char * name)2087 enchant_type name_to_ench(const char *name)
2088 {
2089 for (unsigned int i = ENCH_NONE; i < ARRAYSZ(enchant_names); i++)
2090 if (!strcmp(name, enchant_names[i]))
2091 return (enchant_type)i;
2092 return ENCH_NONE;
2093 }
2094
mon_enchant(enchant_type e,int deg,const actor * a,int dur)2095 mon_enchant::mon_enchant(enchant_type e, int deg, const actor* a,
2096 int dur)
2097 : ench(e), degree(deg), duration(dur), maxduration(0)
2098 {
2099 if (a)
2100 {
2101 who = a->kill_alignment();
2102 source = a->mid;
2103 }
2104 else
2105 {
2106 who = KC_OTHER;
2107 source = 0;
2108 }
2109 }
2110
operator string() const2111 mon_enchant::operator string () const
2112 {
2113 const actor *a = agent();
2114 return make_stringf("%s (%d:%d%s %s)",
2115 _mons_enchantment_name(ench),
2116 degree,
2117 duration,
2118 kill_category_desc(who),
2119 source == MID_ANON_FRIEND ? "anon friend" :
2120 source == MID_YOU_FAULTLESS ? "you w/o fault" :
2121 a ? a->name(DESC_PLAIN, true).c_str() : "N/A");
2122 }
2123
kill_category_desc(kill_category k) const2124 const char *mon_enchant::kill_category_desc(kill_category k) const
2125 {
2126 return k == KC_YOU ? " you" :
2127 k == KC_FRIENDLY ? " pet" : "";
2128 }
2129
merge_killer(kill_category k,mid_t m)2130 void mon_enchant::merge_killer(kill_category k, mid_t m)
2131 {
2132 if (who >= k) // prefer the new one
2133 who = k, source = m;
2134 }
2135
cap_degree()2136 void mon_enchant::cap_degree()
2137 {
2138 // Sickness & draining are not capped.
2139 if (ench == ENCH_SICK || ench == ENCH_DRAINED)
2140 return;
2141
2142 // Hard cap to simulate old enum behaviour, we should really throw this
2143 // out entirely.
2144 const int max = (ench == ENCH_ABJ || ench == ENCH_FAKE_ABJURATION) ?
2145 MAX_ENCH_DEGREE_ABJURATION : MAX_ENCH_DEGREE_DEFAULT;
2146 if (degree > max)
2147 degree = max;
2148 }
2149
operator +=(const mon_enchant & other)2150 mon_enchant &mon_enchant::operator += (const mon_enchant &other)
2151 {
2152 if (ench == other.ench)
2153 {
2154 degree += other.degree;
2155 cap_degree();
2156 duration += other.duration;
2157 if (duration > INFINITE_DURATION)
2158 duration = INFINITE_DURATION;
2159 merge_killer(other.who, other.source);
2160 }
2161 return *this;
2162 }
2163
operator +(const mon_enchant & other) const2164 mon_enchant mon_enchant::operator + (const mon_enchant &other) const
2165 {
2166 mon_enchant tmp(*this);
2167 tmp += other;
2168 return tmp;
2169 }
2170
killer() const2171 killer_type mon_enchant::killer() const
2172 {
2173 return who == KC_YOU ? KILL_YOU :
2174 who == KC_FRIENDLY ? KILL_MON
2175 : KILL_MISC;
2176 }
2177
kill_agent() const2178 int mon_enchant::kill_agent() const
2179 {
2180 return who == KC_FRIENDLY ? ANON_FRIENDLY_MONSTER : 0;
2181 }
2182
agent() const2183 actor* mon_enchant::agent() const
2184 {
2185 return find_agent(source, who);
2186 }
2187
modded_speed(const monster * mons,int hdplus) const2188 int mon_enchant::modded_speed(const monster* mons, int hdplus) const
2189 {
2190 return _mod_speed(mons->get_hit_dice() + hdplus, mons->speed);
2191 }
2192
calc_duration(const monster * mons,const mon_enchant * added) const2193 int mon_enchant::calc_duration(const monster* mons,
2194 const mon_enchant *added) const
2195 {
2196 int cturn = 0;
2197
2198 const int newdegree = added ? added->degree : degree;
2199 const int deg = newdegree ? newdegree : 1;
2200
2201 // Beneficial enchantments (like Haste) should not be throttled by
2202 // monster HD via modded_speed(). Use _mod_speed instead!
2203 switch (ench)
2204 {
2205 case ENCH_SWIFT:
2206 cturn = 1000 / _mod_speed(25, mons->speed);
2207 break;
2208 case ENCH_HASTE:
2209 case ENCH_MIGHT:
2210 case ENCH_INVIS:
2211 case ENCH_AGILE:
2212 case ENCH_BLACK_MARK:
2213 case ENCH_RESISTANCE:
2214 case ENCH_IDEALISED:
2215 case ENCH_BOUND_SOUL:
2216 cturn = 1000 / _mod_speed(25, mons->speed);
2217 break;
2218 case ENCH_LIQUEFYING:
2219 case ENCH_SILENCE:
2220 case ENCH_REGENERATION:
2221 case ENCH_STRONG_WILLED:
2222 case ENCH_MIRROR_DAMAGE:
2223 case ENCH_SAP_MAGIC:
2224 case ENCH_STILL_WINDS:
2225 case ENCH_CONCENTRATE_VENOM:
2226 cturn = 300 / _mod_speed(25, mons->speed);
2227 break;
2228 case ENCH_SLOW:
2229 case ENCH_CORROSION:
2230 cturn = 250 / (1 + modded_speed(mons, 10));
2231 break;
2232 case ENCH_FEAR:
2233 cturn = 150 / (1 + modded_speed(mons, 5));
2234 break;
2235 case ENCH_PARALYSIS:
2236 cturn = max(90 / modded_speed(mons, 5), 3);
2237 break;
2238 case ENCH_PETRIFIED:
2239 cturn = max(8, 150 / (1 + modded_speed(mons, 5)));
2240 break;
2241 case ENCH_DAZED:
2242 case ENCH_PETRIFYING:
2243 cturn = 50 / _mod_speed(10, mons->speed);
2244 break;
2245 case ENCH_CONFUSION:
2246 cturn = max(100 / modded_speed(mons, 5), 3);
2247 break;
2248 case ENCH_HELD:
2249 cturn = 120 / _mod_speed(25, mons->speed);
2250 break;
2251 case ENCH_POISON:
2252 cturn = 1000 * deg / _mod_speed(125, mons->speed);
2253 break;
2254 case ENCH_STICKY_FLAME:
2255 cturn = 1000 * deg / _mod_speed(200, mons->speed);
2256 break;
2257 case ENCH_CORONA:
2258 case ENCH_SILVER_CORONA:
2259 if (deg > 1)
2260 cturn = 1000 * (deg - 1) / _mod_speed(200, mons->speed);
2261 cturn += 1000 / _mod_speed(100, mons->speed);
2262 break;
2263 case ENCH_SHORT_LIVED:
2264 cturn = 1200 / _mod_speed(200, mons->speed);
2265 break;
2266 case ENCH_SLOWLY_DYING:
2267 {
2268 // This may be a little too direct but the randomization at the end
2269 // of this function is excessive for toadstools. -cao
2270 int dur = speed_to_duration(mons->speed); // uses div_rand_round, so we need a sequence point
2271 return (2 * FRESHEST_CORPSE + random2(10))
2272 * dur;
2273 }
2274 case ENCH_EXPLODING:
2275 return random_range(3, 7) * 10;
2276
2277 case ENCH_PORTAL_PACIFIED:
2278 // Must be set by spell.
2279 return 0;
2280
2281 case ENCH_BREATH_WEAPON:
2282 // Must be set by creature.
2283 return 0;
2284
2285 case ENCH_PORTAL_TIMER:
2286 cturn = 30 * 10 / _mod_speed(10, mons->speed);
2287 break;
2288
2289 case ENCH_FAKE_ABJURATION:
2290 case ENCH_ABJ:
2291 // The duration is:
2292 // deg = 1 90 aut
2293 // deg = 2 180 aut
2294 // deg = 3 270 aut
2295 // deg = 4 360 aut
2296 // deg = 5 810 aut
2297 // deg = 6 1710 aut
2298 // with a large fuzz
2299 if (deg >= 6)
2300 cturn = 1000 / _mod_speed(10, mons->speed);
2301 if (deg >= 5)
2302 cturn += 1000 / _mod_speed(20, mons->speed);
2303 cturn += 1000 * min(4, deg) / _mod_speed(100, mons->speed);
2304 break;
2305 case ENCH_CHARM:
2306 case ENCH_HEXED:
2307 cturn = 500 / modded_speed(mons, 10);
2308 break;
2309 case ENCH_TP:
2310 cturn = 1000 * deg / _mod_speed(1000, mons->speed);
2311 break;
2312 case ENCH_SLEEP_WARY:
2313 cturn = 1000 / _mod_speed(50, mons->speed);
2314 break;
2315 case ENCH_LIFE_TIMER:
2316 cturn = 20 * (4 + random2(4)) / _mod_speed(10, mons->speed);
2317 break;
2318 case ENCH_INNER_FLAME:
2319 return random_range(25, 35) * 10;
2320 case ENCH_BERSERK:
2321 return (16 + random2avg(13, 2)) * 10;
2322 case ENCH_ROLLING:
2323 return random_range(10 * BASELINE_DELAY, 15 * BASELINE_DELAY);
2324 case ENCH_WRETCHED:
2325 cturn = (20 + roll_dice(3, 10)) * 10 / _mod_speed(10, mons->speed);
2326 break;
2327 case ENCH_POLAR_VORTEX_COOLDOWN:
2328 cturn = random_range(25, 35) * 10 / _mod_speed(10, mons->speed);
2329 break;
2330 case ENCH_FROZEN:
2331 cturn = 3 * 10 / _mod_speed(10, mons->speed);
2332 break;
2333 case ENCH_BRILLIANCE_AURA:
2334 cturn = 20 * 10 / _mod_speed(10, mons->speed);
2335 break;
2336 case ENCH_EMPOWERED_SPELLS:
2337 cturn = 20 * 10 / _mod_speed(10, mons->speed);
2338 break;
2339 case ENCH_RING_OF_THUNDER:
2340 case ENCH_RING_OF_FLAMES:
2341 case ENCH_RING_OF_CHAOS:
2342 case ENCH_RING_OF_MUTATION:
2343 case ENCH_RING_OF_FOG:
2344 case ENCH_RING_OF_ICE:
2345 case ENCH_RING_OF_DRAINING:
2346 case ENCH_RING_OF_ACID:
2347 case ENCH_RING_OF_MIASMA:
2348 case ENCH_GOZAG_INCITE:
2349 cturn = 100; // is never decremented
2350 break;
2351 default:
2352 break;
2353 }
2354
2355 cturn = max(2, cturn);
2356
2357 int raw_duration = (cturn * speed_to_duration(mons->speed));
2358 // Note: this fuzzing is _not_ symmetric, resulting in 90% of input
2359 // on the average.
2360 raw_duration = max(15, fuzz_value(raw_duration, 60, 40));
2361
2362 dprf("cturn: %d, raw_duration: %d", cturn, raw_duration);
2363
2364 return raw_duration;
2365 }
2366
2367 // Calculate the effective duration (in terms of normal player time - 10
2368 // duration units being one normal player action) of this enchantment.
set_duration(const monster * mons,const mon_enchant * added)2369 void mon_enchant::set_duration(const monster* mons, const mon_enchant *added)
2370 {
2371 if (duration && !added)
2372 return;
2373
2374 if (added && added->duration)
2375 duration += added->duration;
2376 else
2377 duration += calc_duration(mons, added);
2378
2379 if (duration > maxduration)
2380 maxduration = duration;
2381 }
2382