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