1 /**
2  * @file
3  * @brief Divine retribution.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "god-wrath.h"
9 
10 #include <cmath>
11 #include <queue>
12 #include <sstream>
13 
14 #include "areas.h"
15 #include "artefact.h"
16 #include "attitude-change.h"
17 #include "cleansing-flame-source-type.h"
18 #include "coordit.h"
19 #include "corpse.h"
20 #include "database.h"
21 #include "death-curse.h"
22 #include "decks.h"
23 #include "env.h"
24 #include "ghost.h"
25 #include "god-abil.h"
26 #include "god-passive.h" // shadow_monster
27 #include "item-prop.h"
28 #include "item-status-flag-type.h"
29 #include "items.h"
30 #include "losglobal.h"
31 #include "makeitem.h"
32 #include "message.h"
33 #include "misc.h"
34 #include "mon-behv.h"
35 #include "mon-cast.h"
36 #include "mon-pick.h"
37 #include "mon-place.h"
38 #include "mutation.h"
39 #include "notes.h"
40 #include "player-stats.h"
41 #include "random.h"
42 #include "religion.h"
43 #include "shopping.h"
44 #include "shout.h"
45 #include "spl-clouds.h"
46 #include "spl-goditem.h"
47 #include "spl-selfench.h"
48 #include "spl-summoning.h"
49 #include "spl-transloc.h"
50 #include "spl-util.h"
51 #include "state.h"
52 #include "stringutil.h"
53 #include "tag-version.h"
54 #include "terrain.h"
55 #include "transform.h"
56 #include "view.h"
57 #include "xom.h"
58 
59 static void _god_smites_you(god_type god, const char *message = nullptr,
60                             kill_method_type death_type = NUM_KILLBY);
61 static void _tso_blasts_cleansing_flame(const char *message = nullptr);
62 
63 static const char *_god_wrath_adjectives[] =
64 {
65     "bugginess",        // NO_GOD
66     "wrath",            // Zin
67     "wrath",            // the Shining One (unused)
68     "malice",           // Kikubaaqudgha
69     "anger",            // Yredelemnul
70     "capriciousness",   // Xom
71     "wrath",            // Vehumet
72     "fury",             // Okawaru
73     "fury",             // Makhleb
74     "will",             // Sif Muna
75     "fiery rage",       // Trog
76     "wrath",            // Nemelex
77     "displeasure",      // Elyvilon
78     "touch",            // Lugonu
79     "wrath",            // Beogh
80     "vengeance",        // Jiyva
81     "enmity",           // Fedhas Madhash
82     "meddling",         // Cheibriados
83     "doom",             // Ashenzari (unused)
84     "darkness",         // Dithmenos
85     "greed",            // Gozag (unused)
86     "adversity",        // Qazlal
87     "disappointment",   // Ru
88 #if TAG_MAJOR_VERSION == 34
89     "progress",         // Pakellas
90 #endif
91     "fury",             // Uskayaw
92     "memory",           // Hepliaklqana (unused)
93     "rancor",           // Wu Jian
94 };
95 COMPILE_CHECK(ARRAYSZ(_god_wrath_adjectives) == NUM_GODS);
96 
97 /**
98  * Return a name associated with the given god's wrath.
99  *
100  * E.g., "the darkness of Dithmenos".
101  * Used for cause of death messages (e.g. 'killed by a titan (summoned by the
102  * wrath of Okawaru)')
103  *
104  * @param god   The god in question.
105  * @return      A string name for the god's wrath.
106  */
_god_wrath_name(god_type god)107 static string _god_wrath_name(god_type god)
108 {
109     const bool use_full_name = god == GOD_FEDHAS      // fedhas is very formal.
110                                || god == GOD_WU_JIAN; // apparently.
111 
112     return make_stringf("the %s of %s",
113                         _god_wrath_adjectives[god],
114                         god_name(god, use_full_name).c_str());
115 }
116 
_wrath_mon_data(monster_type mtyp,god_type god)117 static mgen_data _wrath_mon_data(monster_type mtyp, god_type god)
118 {
119     mgen_data mg = mgen_data::hostile_at(mtyp, true, you.pos())
120                     .set_summoned(nullptr, 0, 0, god)
121                     .set_non_actor_summoner(_god_wrath_name(god));
122     mg.extra_flags |= (MF_NO_REWARD | MF_HARD_RESET);
123     return mg;
124 }
125 
_yred_random_zombified_hostile()126 static bool _yred_random_zombified_hostile()
127 {
128     const bool skel = one_chance_in(4);
129 
130     monster_type z_base;
131 
132     do
133     {
134         // XXX: better zombie selection?
135         level_id place(BRANCH_DUNGEON,
136                        min(27, you.experience_level + 5));
137         z_base = pick_local_zombifiable_monster(place, RANDOM_MONSTER,
138                                                 you.pos());
139     }
140     while (skel && !mons_skeleton(z_base));
141 
142     mgen_data temp = _wrath_mon_data(skel ? MONS_SKELETON : MONS_ZOMBIE,
143                                      GOD_YREDELEMNUL)
144                      .set_base(z_base);
145 
146     return create_monster(temp, false);
147 }
148 
149 static const vector<pop_entry> _okawaru_servants =
150 { // warriors
151   {  1,  3,   3, FALL, MONS_ORC },
152   {  1,  3,   3, FALL, MONS_GNOLL },
153   {  2,  6,   3, PEAK, MONS_OGRE },
154   {  2,  6,   2, PEAK, MONS_GNOLL_SERGEANT },
155   {  3,  7,   1, FLAT, MONS_TWO_HEADED_OGRE },
156   {  3, 13,   3, PEAK, MONS_ORC_WARRIOR },
157   {  5, 15,   3, PEAK, MONS_ORC_KNIGHT },
158   {  5, 15,   2, PEAK, MONS_CYCLOPS },
159   {  7, 21,   2, PEAK, MONS_CENTAUR_WARRIOR },
160   {  7, 21,   2, PEAK, MONS_NAGA_WARRIOR },
161   {  7, 21,   2, PEAK, MONS_TENGU_WARRIOR },
162   {  7, 21,   1, FLAT, MONS_MERFOLK_IMPALER },
163   {  7, 21,   1, FLAT, MONS_MERFOLK_JAVELINEER },
164   {  7, 21,   1, FLAT, MONS_MINOTAUR },
165   {  9, 27,   2, FLAT, MONS_STONE_GIANT },
166   {  9, 27,   1, FLAT, MONS_DEEP_ELF_KNIGHT },
167   {  9, 27,   1, FLAT, MONS_DEEP_ELF_ARCHER },
168   { 11, 21,   1, FLAT, MONS_ORC_WARLORD },
169   { 11, 27,   2, FLAT, MONS_FIRE_GIANT },
170   { 11, 27,   2, FLAT, MONS_FROST_GIANT },
171   { 13, 27,   1, FLAT, MONS_DEEP_ELF_BLADEMASTER },
172   { 13, 27,   1, FLAT, MONS_DEEP_ELF_MASTER_ARCHER },
173   { 13, 27,   1, FLAT, RANDOM_BASE_DRACONIAN },
174   { 15, 27,   2, FLAT, MONS_TITAN },
175 };
176 
_okawaru_random_servant()177 static bool _okawaru_random_servant()
178 {
179     monster_type mon_type = pick_monster_from(_okawaru_servants,
180                                               you.experience_level);
181 
182     mgen_data temp = _wrath_mon_data(mon_type, GOD_OKAWARU);
183 
184     // Don't send dream sheep into battle, but otherwise let bands in.
185     // This makes sure you get multiple orcs/gnolls early on.
186     if (mon_type != MONS_CYCLOPS)
187         temp.flags |= MG_PERMIT_BANDS;
188 
189     return create_monster(temp, false);
190 }
191 
_dithmenos_random_shadow(const int count,const int tier)192 static bool _dithmenos_random_shadow(const int count, const int tier)
193 {
194     monster_type mon_type = MONS_SHADOW;
195     if (tier >= 2 && count == 0 && coinflip())
196         mon_type = MONS_TZITZIMITL;
197     else if (tier >= 1 && count < 3 && coinflip())
198         mon_type = MONS_SHADOW_DEMON;
199 
200     return create_monster(_wrath_mon_data(mon_type, GOD_DITHMENOS), false);
201 }
202 
203 /**
204  * Summon divine warriors of the Shining One to punish the player.
205  */
_tso_summon_warriors()206 static void _tso_summon_warriors()
207 {
208     bool success = false;
209     int how_many = 1 + random2(you.experience_level / 5) + random2(3);
210 
211     for (; how_many > 0; --how_many)
212     {
213         if (summon_holy_warrior(100, true))
214             success = true;
215     }
216 
217     simple_god_message(success ? " sends the divine host to punish "
218                        "you for your evil ways!"
219                        : "'s divine host fails to appear.", GOD_SHINING_ONE);
220 
221 }
222 
223 /**
224  * The Shining One shouts angrily to alert the player's foes!
225  */
_tso_shouts()226 static void _tso_shouts()
227 {
228     simple_god_message(" booms out: "
229                        "\"Take the path of righteousness! REPENT!\"",
230                        GOD_SHINING_ONE);
231     noisy(25, you.pos()); // same as scroll of noise
232 }
233 
234 /**
235  * The Shining One silences the player!!
236  */
_tso_squelches()237 static void _tso_squelches()
238 {
239     god_speaks(GOD_SHINING_ONE,
240                "You feel the Shining One's silent rage upon you!");
241     cast_silence(25);
242 }
243 
244 /**
245  * Call down the wrath of the Shining One upon the player!
246  *
247  * Holy warriors/cleansing theme.
248  *
249  * @return Whether to take further divine wrath actions afterward.
250  */
_tso_retribution()251 static bool _tso_retribution()
252 {
253     switch (random2(7))
254     {
255     case 0:
256     case 1:
257     case 2:
258         _tso_summon_warriors();
259         break;
260     case 3:
261     case 4:
262         _tso_blasts_cleansing_flame();
263         break;
264     case 5:
265         _tso_shouts();
266         break;
267     case 6:
268         _tso_squelches();
269         break;
270     }
271     return true;
272 }
273 
_zin_remove_good_mutations()274 static void _zin_remove_good_mutations()
275 {
276     if (!you.how_mutated())
277         return;
278 
279     const god_type god = GOD_ZIN;
280     bool success = false;
281 
282     simple_god_message(" draws some chaos from your body!", god);
283 
284     bool failMsg = true;
285 
286     for (int i = 7; i >= 0; --i)
287     {
288         // Ensure that only good mutations are removed.
289         if (i <= random2(10)
290             && delete_mutation(RANDOM_GOOD_MUTATION, _god_wrath_name(god),
291                                failMsg, false, true, true))
292         {
293             success = true;
294         }
295         else
296             failMsg = false;
297     }
298 
299     if (success && !you.how_mutated())
300         simple_god_message(" rids your body of chaos!", god);
301 }
302 
_zin_retribution()303 static bool _zin_retribution()
304 {
305     // preaching/creeping doom theme
306     const god_type god = GOD_ZIN;
307 
308     // If not mutated, do something else instead.
309     const int punishment = you.how_mutated() ? random2(6) : random2(4);
310 
311     switch (punishment)
312     {
313     case 0:
314     case 1:
315     case 2: // recital
316         simple_god_message(" recites the Axioms of Law to you!", god);
317         switch (random2(3))
318         {
319         case 0:
320             confuse_player(5 + random2(3));
321             break;
322         case 1:
323             you.put_to_sleep(nullptr, 30 + random2(20));
324             break;
325         case 2:
326             paralyse_player(_god_wrath_name(god));
327             return false;
328         }
329         break;
330     case 3: // noisiness
331         simple_god_message(" booms out: \"Turn to the light! REPENT!\"", god);
332         noisy(25, you.pos()); // same as scroll of noise
333         break;
334     case 4:
335     case 5: // remove good mutations
336         _zin_remove_good_mutations();
337         break;
338     }
339     return true;
340 }
341 
_cheibriados_retribution()342 static bool _cheibriados_retribution()
343 {
344     // time god/slowness theme
345     const god_type god = GOD_CHEIBRIADOS;
346 
347     // Chei retribution might only make sense in combat.
348     // We can crib some Xom code for this. {bh}
349     int tension = get_tension(GOD_CHEIBRIADOS);
350     int wrath_value = random2(tension);
351 
352     // Determine the level of wrath
353     int wrath_type = 0;
354     if (wrath_value < 2)
355         wrath_type = 0;
356     else if (wrath_value < 4)
357         wrath_type = 1;
358     else if (wrath_value < 8)
359         wrath_type = 2;
360     else if (wrath_value < 16)
361         wrath_type = 3;
362     else
363         wrath_type = 4;
364 
365     // Strip away extra speed
366     dec_haste_player(10000);
367 
368     switch (wrath_type)
369     {
370     // Very high tension wrath.
371     // Add noise then start sleeping and slow the player with 2/3 chance.
372     case 4:
373         simple_god_message(" strikes the hour.", god);
374         noisy(40, you.pos());
375         dec_penance(god, 1); // and fall-through.
376     // High tension wrath
377     // Sleep the player and slow the player with 50% chance.
378     case 3:
379         mpr("You lose track of time.");
380         you.put_to_sleep(nullptr, 30 + random2(20));
381         if (one_chance_in(wrath_type - 1))
382             break;
383         else
384             dec_penance(god, 1); // and fall-through.
385     // Medium tension
386     case 2:
387         if (you.duration[DUR_SLOW] < 180 * BASELINE_DELAY)
388         {
389             mprf(MSGCH_WARN, "You feel the world leave you behind!");
390             slow_player(100);
391         }
392         break;
393     // Low/no tension; lose stats.
394     case 1:
395     case 0:
396         mpr("Time shudders.");
397         lose_stat(STAT_RANDOM, 1 + random2avg(5, 2));
398         break;
399 
400     default:
401         break;
402     }
403 
404     return true;
405 }
406 
_spell_retribution(monster * avatar,spell_type spell,god_type god,const char * message=nullptr)407 static void _spell_retribution(monster* avatar, spell_type spell, god_type god,
408                                const char* message = nullptr)
409 {
410     simple_god_message(message ? message : " rains destruction down upon you!",
411                        god);
412     bolt beam;
413     beam.source = you.pos();
414     beam.target = you.pos();
415     beam.aimed_at_feet = true;
416     beam.source_name = avatar->mname;
417     mons_cast(avatar, beam, spell, MON_SPELL_PRIEST, false);
418 }
419 
420 /**
421  * Choose a type of destruction with which to punish the player.
422  *
423  * @return A spell type to hurl at the player.
424  */
_makhleb_destruction_type()425 static spell_type _makhleb_destruction_type()
426 {
427     const int severity = min(random_range(you.experience_level / 14,
428                                           you.experience_level / 9),
429                              2);
430     switch (severity)
431     {
432         case 0:
433         default:
434             // minor destruction
435             return random_choose(SPELL_THROW_FLAME,
436                                  SPELL_PAIN,
437                                  SPELL_STONE_ARROW,
438                                  SPELL_SHOCK,
439                                  SPELL_SPIT_ACID);
440         case 1:
441             // major destruction
442             return random_choose(SPELL_BOLT_OF_FIRE,
443                                  SPELL_FIREBALL,
444                                  SPELL_LIGHTNING_BOLT,
445                                  SPELL_STICKY_FLAME,
446                                  SPELL_IRON_SHOT,
447                                  SPELL_BOLT_OF_DRAINING,
448                                  SPELL_ORB_OF_ELECTRICITY);
449         case 2:
450             // legendary destruction (no IOOD because it doesn't really
451             // work here)
452             return random_choose(SPELL_FIREBALL,
453                                  SPELL_LEHUDIBS_CRYSTAL_SPEAR,
454                                  SPELL_ORB_OF_ELECTRICITY,
455                                  SPELL_FLASH_FREEZE,
456                                  SPELL_GHOSTLY_FIREBALL);
457     }
458 }
459 
460 /**
461  * Create a fake 'avatar' monster representing a god, with which to hurl
462  * destructive magic at foolish players.
463  *
464  * @param god           The god doing the wrath-hurling.
465  * @return              An avatar monster, or nullptr if none could be set up.
466  */
get_avatar(god_type god)467 static monster* get_avatar(god_type god)
468 {
469     // TODO: it would be better to abstract the fake monster code from both
470     // this and shadow monster and possibly use different monster types --
471     // doing it this way makes it easier for bugs where the two are conflated
472     // to creep in
473     monster* avatar = shadow_monster(false);
474     if (!avatar)
475         return nullptr;
476 
477     // shadow_monster() has the player's mid, which is no good here.
478     avatar->set_new_monster_id();
479 
480     avatar->mname = _god_wrath_name(god);
481     avatar->flags |= MF_NAME_REPLACE;
482     avatar->attitude = ATT_HOSTILE;
483     avatar->set_hit_dice(you.experience_level);
484 
485     return avatar;
486 }
487 
488 /// Cleanup a temporary 'avatar' monster.
_reset_avatar(monster & avatar)489 static void _reset_avatar(monster &avatar)
490 {
491     env.mid_cache.erase(avatar.mid);
492     shadow_monster_reset(&avatar);
493 }
494 
495 /**
496  * Rain down Makhleb's destruction upon the player!
497  *
498  * @return Whether to take further divine wrath actions afterward.
499  */
_makhleb_call_down_destruction()500 static bool _makhleb_call_down_destruction()
501 {
502     const god_type god = GOD_MAKHLEB;
503 
504     monster* avatar = get_avatar(god);
505     // can't be const because mons_cast() doesn't accept const monster*
506 
507     if (avatar == nullptr)
508     {
509         simple_god_message(" has no time to deal with you just now.", god);
510         return false; // not a very dazzling divine experience...
511     }
512 
513     _spell_retribution(avatar, _makhleb_destruction_type(), god);
514     _reset_avatar(*avatar);
515     return true;
516 }
517 
518 /**
519  * Figure out how many greater servants (2s) an instance of Makhleb's wrath
520  * should summon.
521  *
522  * @return The number of greater servants to be summoned by Makhleb's wrath.
523  */
_makhleb_num_greater_servants()524 static int _makhleb_num_greater_servants()
525 {
526     const int severity = 1 + you.experience_level / 2
527                            + random2(you.experience_level / 2);
528 
529     if (severity > 13)
530         return 2 + random2(you.experience_level / 5 - 2); // up to 6 at XL27
531     else if (severity > 7 && !one_chance_in(5))
532         return 1;
533     return 0;
534 }
535 
536 /**
537  * Attempt to summon one of Makhleb's diabolical servants to punish the player.
538  *
539  * @param servant   The type of servant to be summoned.
540  * @return          Whether the summoning was successful.
541  */
_makhleb_summon_servant(monster_type servant)542 static bool _makhleb_summon_servant(monster_type servant)
543 {
544     return create_monster(_wrath_mon_data(servant, GOD_MAKHLEB), false);
545 }
546 
547 /**
548  * Unleash Makhleb's fiendish minions on the player!
549  *
550  * @return Whether to take further divine wrath actions afterward. (true.)
551  */
_makhleb_summon_servants()552 static bool _makhleb_summon_servants()
553 {
554     const int greater_servants = _makhleb_num_greater_servants();
555 
556     // up to 6 at XL25+
557     const int total_servants = max(greater_servants,
558                                1 + (random2(you.experience_level)
559                                  + random2(you.experience_level)) / 10);
560     const int lesser_servants = total_servants - greater_servants;
561 
562     int summoned = 0;
563 
564     for (int i = 0; i < greater_servants; i++)
565     {
566         const monster_type servant = random_choose(MONS_EXECUTIONER,
567                                                    MONS_GREEN_DEATH,
568                                                    MONS_BLIZZARD_DEMON,
569                                                    MONS_BALRUG,
570                                                    MONS_CACODEMON);
571         if (_makhleb_summon_servant(servant))
572             summoned++;
573     }
574 
575     for (int i = 0; i < lesser_servants; i++)
576     {
577         const monster_type servant = random_choose(MONS_HELLWING,
578                                                    MONS_NEQOXEC,
579                                                    MONS_ORANGE_DEMON,
580                                                    MONS_SMOKE_DEMON,
581                                                    MONS_YNOXINUL);
582         if (_makhleb_summon_servant(servant))
583             summoned++;
584     }
585 
586     simple_god_message(summoned > 1 ? " sends minions to punish you." :
587                        summoned > 0 ? " sends a minion to punish you."
588                        : "'s minions fail to arrive.", GOD_MAKHLEB);
589 
590     return true;
591 
592 }
593 
594 /**
595  * Call down the wrath of Makhleb upon the player!
596  *
597  * Demonic servant theme.
598  *
599  * @return Whether to take further divine wrath actions afterward.
600  */
_makhleb_retribution()601 static bool _makhleb_retribution()
602 {
603     if (coinflip())
604         return _makhleb_call_down_destruction();
605     else
606         return _makhleb_summon_servants();
607 }
608 
_count_corpses_in_los(vector<stack_iterator> * positions)609 static int _count_corpses_in_los(vector<stack_iterator> *positions)
610 {
611     int count = 0;
612 
613     for (radius_iterator rad(you.pos(), LOS_NO_TRANS, true); rad;
614          ++rad)
615     {
616         if (actor_at(*rad))
617             continue;
618 
619         for (stack_iterator stack_it(*rad); stack_it; ++stack_it)
620         {
621             if (stack_it->is_type(OBJ_CORPSES, CORPSE_BODY))
622             {
623                 if (positions)
624                     positions->push_back(stack_it);
625                 count++;
626                 break;
627             }
628         }
629     }
630 
631     return count;
632 }
633 
_kikubaaqudgha_retribution()634 static bool _kikubaaqudgha_retribution()
635 {
636     // death/necromancy theme
637     const god_type god = GOD_KIKUBAAQUDGHA;
638 
639     god_speaks(god, coinflip() ? "You hear Kikubaaqudgha cackling."
640                                : "Kikubaaqudgha's malice focuses upon you.");
641 
642     if (!_count_corpses_in_los(nullptr) || random2(you.experience_level) > 4)
643     {
644         // Either zombies, or corpse rot + skeletons.
645         kiku_receive_corpses(you.experience_level * 4);
646 
647         if (coinflip())
648             corpse_rot(nullptr);
649     }
650 
651     if (x_chance_in_y(you.experience_level, 27))
652     {
653         // torment, or 3 death curses of maximum power
654         if (!you.res_torment())
655             torment(nullptr, TORMENT_KIKUBAAQUDGHA, you.pos());
656         else
657         {
658             for (int i = 0; i < 3; ++i)
659             {
660                 death_curse(you, nullptr,
661                             _god_wrath_name(god), you.experience_level);
662             }
663         }
664     }
665     else if (random2(you.experience_level) >= 4)
666     {
667         // death curse, 25% chance of additional curse
668         const int num_curses = one_chance_in(4) ? 2 : 1;
669         for (int i = 0; i < num_curses; i++)
670         {
671                 death_curse(you, nullptr,
672                             _god_wrath_name(god), you.experience_level);
673         }
674     }
675 
676     // Every act of retribution causes corpses in view to rise against
677     // you.
678     animate_dead(&you, 1 + random2(3), BEH_HOSTILE, MHITYOU, 0,
679                  _god_wrath_name(god), god);
680 
681     return true;
682 }
683 
_yredelemnul_retribution()684 static bool _yredelemnul_retribution()
685 {
686     // undead theme
687     const god_type god = GOD_YREDELEMNUL;
688 
689     if (coinflip())
690     {
691         if (you_worship(god) && coinflip() && yred_slaves_abandon_you())
692             ;
693         else
694         {
695             int how_many = 1 + random2avg(1 + (you.experience_level / 5), 2);
696             int count = 0;
697 
698             for (; how_many > 0; --how_many)
699             {
700                 if (one_chance_in(you.experience_level))
701                 {
702                     if (_yred_random_zombified_hostile())
703                         count++;
704                 }
705                 else
706                 {
707                     const int num = yred_random_servants(0, true);
708                     if (num >= 0)
709                         count += num;
710                     else
711                         ++how_many;
712                 }
713             }
714 
715             simple_god_message(count > 1 ? " sends servants to punish you." :
716                                count > 0 ? " sends a servant to punish you."
717                                          : "'s servants fail to arrive.", god);
718         }
719     }
720     else
721     {
722         monster* avatar = get_avatar(god);
723         // can't be const because mons_cast() doesn't accept const monster*
724 
725         if (avatar == nullptr)
726         {
727             simple_god_message(" has no time to deal with you just now.", god);
728             return false;
729         }
730 
731         _spell_retribution(avatar, SPELL_BOLT_OF_DRAINING, god,
732                            "'s anger turns toward you for a moment.");
733         _reset_avatar(*avatar);
734     }
735 
736     return true;
737 }
738 
_trog_retribution()739 static bool _trog_retribution()
740 {
741     // physical/berserk theme
742     const god_type god = GOD_TROG;
743 
744     if (coinflip())
745     {
746         int count = 0;
747         int points = 3 + you.experience_level * 3;
748 
749         {
750             msg::suppress msg;
751 
752             while (points > 0)
753             {
754                 int cost =
755                     min(min(random2avg((1 + you.experience_level / 3), 2) + 3,
756                             10),
757                         points);
758 
759                 // quick reduction for large values
760                 if (points > 20 && coinflip())
761                 {
762                     points -= 10;
763                     cost = min(1 + div_rand_round(you.experience_level, 2), 10);
764                 }
765 
766                 points -= cost;
767 
768                 if (summon_berserker(cost * 20, 0))
769                     count++;
770             }
771         }
772 
773         simple_god_message(count > 1 ? " sends monsters to punish you." :
774                            count > 0 ? " sends a monster to punish you."
775                                      : " has no time to punish you... now.",
776                            god);
777     }
778     else if (!one_chance_in(3))
779     {
780         simple_god_message("'s voice booms out, \"Feel my wrath!\"", god);
781 
782         // A collection of physical effects that might be better
783         // suited to Trog than wild fire magic... messages could
784         // be better here... something more along the lines of apathy
785         // or loss of rage to go with the anti-berserk effect-- bwr
786         switch (random2(6))
787         {
788         case 0:
789         case 1:
790         case 2:
791             lose_stat(STAT_STR, 1 + random2(you.strength() / 5));
792             break;
793 
794         case 3:
795             if (!you.duration[DUR_PARALYSIS])
796             {
797                 mprf(MSGCH_WARN, "You suddenly pass out!");
798                 const int turns = 2 + random2(6);
799                 take_note(Note(NOTE_PARALYSIS, min(turns, 13), 0, "Trog"));
800                 you.increase_duration(DUR_PARALYSIS, turns, 13);
801             }
802             return false;
803 
804         case 4:
805         case 5:
806             if (you.duration[DUR_SLOW] < 180 * BASELINE_DELAY)
807             {
808                 mprf(MSGCH_WARN, "You suddenly feel lethargic!");
809                 slow_player(100);
810             }
811             break;
812         }
813     }
814     else
815     {
816         // A fireball is magic when used by a mortal but just a manifestation
817         // of pure rage when used by a god. --ebering
818 
819         monster* avatar = get_avatar(god);
820         // can't be const because mons_cast() doesn't accept const monster*
821 
822         if (avatar == nullptr)
823         {
824             simple_god_message(" has no time to deal with you just now.", god);
825             return false; // not a very dazzling divine experience...
826         }
827 
828         _spell_retribution(avatar, SPELL_FIREBALL,
829                            god, " hurls fiery rage upon you!");
830         _reset_avatar(*avatar);
831     }
832 
833     return true;
834 }
835 
_beogh_retribution()836 static bool _beogh_retribution()
837 {
838     // orcish theme
839     const god_type god = GOD_BEOGH;
840 
841     switch (random2(8))
842     {
843     case 0: // smiting (25%)
844     case 1:
845         _god_smites_you(god);
846         break;
847 
848     case 2: // send out one or two dancing weapons (12.5%)
849     {
850         int num_created = 0;
851         int num_to_create = random_range(1, 2);
852 
853         for (int i = 0; i < num_to_create; ++i)
854         {
855             const int wpn_type =
856                 random_choose(WPN_CLUB,        WPN_MACE,      WPN_FLAIL,
857                               WPN_MORNINGSTAR, WPN_DAGGER,    WPN_SHORT_SWORD,
858                               WPN_LONG_SWORD,  WPN_SCIMITAR,  WPN_GREAT_SWORD,
859                               WPN_HAND_AXE,    WPN_BATTLEAXE, WPN_SPEAR,
860                               WPN_HALBERD);
861 
862             // Now create monster.
863             if (monster *mon =
864                 create_monster(_wrath_mon_data(MONS_DANCING_WEAPON, god)))
865             {
866                 ASSERT(mon->weapon() != nullptr);
867                 item_def& wpn(*mon->weapon());
868 
869                 set_item_ego_type(wpn, OBJ_WEAPONS, SPWPN_ELECTROCUTION);
870 
871                 wpn.plus  = random2(3);
872                 wpn.sub_type = wpn_type;
873 
874                 set_ident_flags(wpn, ISFLAG_KNOW_TYPE);
875 
876                 item_colour(wpn);
877 
878                 ghost_demon newstats;
879                 newstats.init_dancing_weapon(wpn,
880                                              you.experience_level * 50 / 9);
881 
882                 mon->set_ghost(newstats);
883                 mon->ghost_demon_init();
884 
885                 num_created++;
886             }
887         }
888 
889         if (num_created > 0)
890         {
891             ostringstream msg;
892             msg << " throws "
893                 << (num_created == 1 ? "an implement" : "implements")
894                 << " of electrocution at you.";
895             simple_god_message(msg.str().c_str(), god);
896             break;
897         } // else fall through
898     }
899     case 3: // 25%, relatively harmless
900     case 4: // in effect, only for penance
901         if (you_worship(god) && beogh_followers_abandon_you())
902             break;
903         // else fall through
904     default: // send orcs after you (3/8 to 5/8)
905     {
906         const int points = you.experience_level + 3
907                            + random2(you.experience_level * 3);
908 
909         monster_type punisher;
910         // "natural" bands
911         if (points >= 30) // min: lvl 7, always: lvl 27
912             punisher = MONS_ORC_WARLORD;
913         else if (points >= 24) // min: lvl 6, always: lvl 21
914             punisher = MONS_ORC_HIGH_PRIEST;
915         else if (points >= 18) // min: lvl 4, always: lvl 15
916             punisher = MONS_ORC_KNIGHT;
917         else if (points > 10) // min: lvl 3, always: lvl 8
918             punisher = MONS_ORC_WARRIOR;
919         else
920             punisher = MONS_ORC;
921 
922         mgen_data temp = _wrath_mon_data(punisher, god);
923         temp.flags |=  MG_PERMIT_BANDS;
924 
925         monster *mons = create_monster(temp, false);
926 
927         // sometimes name band leader
928         if (mons && one_chance_in(3))
929             give_monster_proper_name(*mons);
930 
931         simple_god_message(
932             mons ? " sends forth an army of orcs."
933                  : " is still gathering forces against you.", god);
934     }
935     }
936 
937     return true;
938 }
939 
_okawaru_retribution()940 static bool _okawaru_retribution()
941 {
942     // warrior theme
943     const god_type god = GOD_OKAWARU;
944 
945     int how_many = 1 + (you.experience_level / 5);
946     int count = 0;
947 
948     for (; how_many > 0; --how_many)
949         count += _okawaru_random_servant();
950 
951     simple_god_message(count > 0 ? " sends forces against you!"
952                                  : "'s forces are busy with other wars.", god);
953 
954     return true;
955 }
956 
_sif_muna_retribution()957 static bool _sif_muna_retribution()
958 {
959     // magic/intelligence theme
960     const god_type god = GOD_SIF_MUNA;
961 
962     simple_god_message("'s wrath finds you.", god);
963 
964     switch (random2(10))
965     {
966     case 0:
967     case 1:
968     case 2:
969         lose_stat(STAT_INT, 1 + random2(you.intel() / 5));
970         break;
971 
972     case 3:
973     case 4:
974     case 5:
975         confuse_player(5 + random2(3));
976         break;
977 
978     case 6:
979     case 7:
980     case 8:
981         if (you.magic_points > 0)
982         {
983             drain_mp(you.magic_points);
984             canned_msg(MSG_MAGIC_DRAIN);
985         }
986         break;
987 
988     case 9:
989         // This will set all the extendable duration spells to
990         // a duration of one round, thus potentially exposing
991         // the player to real danger.
992         debuff_player();
993         break;
994     }
995 
996     return true;
997 }
998 
999 /**
1000  * Perform translocation-flavored Lugonu retribution.
1001  *
1002  * 25% banishment; 50% teleport near monsters.
1003  */
_lugonu_transloc_retribution()1004 static void _lugonu_transloc_retribution()
1005 {
1006     const god_type god = GOD_LUGONU;
1007 
1008     if (coinflip())
1009     {
1010         // Give extra opportunities for embarrassing teleports.
1011         simple_god_message("'s wrath scatters you!", god);
1012         you_teleport_now(false, true, "Space warps around you!");
1013     }
1014     else if (coinflip())
1015     {
1016         simple_god_message(" draws you home!", god);
1017         you.banish(nullptr, "Lugonu's touch", you.get_experience_level(), true);
1018     }
1019 }
1020 
1021 /**
1022  * Summon Lugonu's minions to punish the player.
1023  *
1024  * Possibly a major minion with pals, possibly just some riff-raff, depending
1025  * on level & chance.
1026  */
_lugonu_minion_retribution()1027 static void _lugonu_minion_retribution()
1028 {
1029     // abyssal servant theme
1030     const god_type god = GOD_LUGONU;
1031 
1032     // should we summon more & higher-tier lugonu minions?
1033     // linear chance, from 0% at xl 4 to 80% at xl 16
1034     const bool major = (you.experience_level > (4 + random2(12))
1035                         && !one_chance_in(5));
1036 
1037     // how many lesser minions should we try to summon?
1038     // if this is major wrath, summon a few minions; 0 below xl9, 0-3 at xl 27.
1039     // otherwise, summon exactly (!) 1 + xl/7 minions, maxing at 4 at xl 21.
1040     const int how_many = (major ? random2(you.experience_level / 9 + 1)
1041                                 : 1 + you.experience_level / 7);
1042 
1043     // did we successfully summon any minions? (potentially set true below)
1044     bool success = false;
1045 
1046     for (int i = 0; i < how_many; ++i)
1047     {
1048         // try to summon a few minor minions...
1049         // weight toward large abominations, and away from small ones, at
1050         // higher levels
1051         const monster_type to_summon =
1052             random_choose_weighted(
1053                 15 - (you.experience_level/2),  MONS_ABOMINATION_SMALL,
1054                 you.experience_level/2,         MONS_ABOMINATION_LARGE,
1055                 6,                              MONS_THRASHING_HORROR,
1056                 3,                              MONS_ANCIENT_ZYME
1057             );
1058 
1059         if (create_monster(_wrath_mon_data(to_summon, god), false))
1060             success = true;
1061     }
1062 
1063     if (major)
1064     {
1065         // try to summon one nasty monster.
1066         const monster_type to_summon = random_choose(MONS_TENTACLED_STARSPAWN,
1067                                                      MONS_WRETCHED_STAR,
1068                                                      MONS_STARCURSED_MASS);
1069 
1070         if (create_monster(_wrath_mon_data(to_summon, god), false))
1071             success = true;
1072     }
1073 
1074     simple_god_message(success ? " sends minions to punish you."
1075                                : "'s minions fail to arrive.", god);
1076 }
1077 
1078 /**
1079  * Call down the wrath of Lugonu upon the player!
1080  *
1081  * @return Whether to take further divine wrath actions afterward.
1082  */
_lugonu_retribution()1083 static bool _lugonu_retribution()
1084 {
1085     _lugonu_transloc_retribution();
1086     _lugonu_minion_retribution();
1087 
1088     return true;
1089 }
1090 
1091 
1092 
1093 /**
1094  * Choose a type of destruction with which to punish the player.
1095  *
1096  * @return A spell type to hurl at the player.
1097  */
_vehumet_wrath_type()1098 static spell_type _vehumet_wrath_type()
1099 {
1100     const int severity = min(random_range(1 + you.experience_level / 5,
1101                                           1 + you.experience_level / 3),
1102                              9);
1103     // Mostly player-castable conjurations with a couple of additions.
1104     switch (severity)
1105     {
1106         case 1:
1107             return random_choose(SPELL_MAGIC_DART,
1108                                  SPELL_STING,
1109                                  SPELL_SHOCK,
1110                                  SPELL_FLAME_TONGUE);
1111         case 2:
1112             return random_choose(SPELL_THROW_FLAME,
1113                                  SPELL_THROW_FROST);
1114         case 3:
1115             return random_choose(SPELL_MEPHITIC_CLOUD,
1116                                  SPELL_STONE_ARROW);
1117         case 4:
1118             return random_choose(SPELL_STICKY_FLAME,
1119                                  SPELL_THROW_ICICLE,
1120                                  SPELL_ENERGY_BOLT);
1121         case 5:
1122             return random_choose(SPELL_FIREBALL,
1123                                  SPELL_LIGHTNING_BOLT,
1124                                  SPELL_BOLT_OF_MAGMA,
1125                                  SPELL_VENOM_BOLT,
1126                                  SPELL_BOLT_OF_DRAINING,
1127                                  SPELL_QUICKSILVER_BOLT,
1128                                  SPELL_METAL_SPLINTERS);
1129         case 6:
1130             return random_choose(SPELL_BOLT_OF_FIRE,
1131                                  SPELL_BOLT_OF_COLD,
1132                                  SPELL_CORROSIVE_BOLT,
1133                                  SPELL_FREEZING_CLOUD,
1134                                  SPELL_POISONOUS_CLOUD,
1135                                  SPELL_POISON_ARROW,
1136                                  SPELL_IRON_SHOT,
1137                                  SPELL_CONJURE_BALL_LIGHTNING);
1138         case 7:
1139             return random_choose(SPELL_ORB_OF_ELECTRICITY,
1140                                  SPELL_FLASH_FREEZE);
1141         case 8:
1142             return SPELL_LEHUDIBS_CRYSTAL_SPEAR;
1143         case 9:
1144             return SPELL_FIRE_STORM;
1145         default:
1146             return SPELL_NO_SPELL;
1147     }
1148 }
1149 
1150 /**
1151  * Call down the wrath of Vehumpet upon the player!
1152  *
1153  * Conjuration theme.
1154  *
1155  * @return Whether to take further divine wrath actions afterward.
1156  */
_vehumet_retribution()1157 static bool _vehumet_retribution()
1158 {
1159     const god_type god = GOD_VEHUMET;
1160 
1161     monster* avatar = get_avatar(god);
1162     if (!avatar)
1163     {
1164         simple_god_message(" has no time to deal with you just now.", god);
1165         return false;
1166     }
1167 
1168     const spell_type spell = _vehumet_wrath_type();
1169     if (spell == SPELL_NO_SPELL)
1170     {
1171         simple_god_message(" has no time to deal with you just now.", god);
1172         _reset_avatar(*avatar);
1173         return false;
1174     }
1175 
1176     _spell_retribution(avatar, spell, god);
1177     _reset_avatar(*avatar);
1178     return true;
1179 }
1180 
_nemelex_retribution()1181 static bool _nemelex_retribution()
1182 {
1183     // card theme
1184     const god_type god = GOD_NEMELEX_XOBEH;
1185 
1186     simple_god_message(" makes you draw from the deck of Punishment.", god);
1187     draw_from_deck_of_punishment();
1188     return true;
1189 }
1190 
1191 /**
1192  * Let Jiyva throw a few malmutations the player's way.
1193  */
_jiyva_mutate_player()1194 static void _jiyva_mutate_player()
1195 {
1196     const god_type god = GOD_JIYVA;
1197     god_speaks(god, "You feel Jiyva alter your body.");
1198 
1199     const int mutations = 1 + random2(3);
1200     for (int i = 0; i < mutations; ++i)
1201         mutate(RANDOM_BAD_MUTATION, _god_wrath_name(god), true, false, true);
1202 }
1203 
_jiyva_remove_slime_mutation()1204 static void _jiyva_remove_slime_mutation()
1205 {
1206     bool slimy = false;
1207     for (int i = 0; i < NUM_MUTATIONS; ++i)
1208     {
1209         if (is_slime_mutation(static_cast<mutation_type>(i))
1210             && you.has_mutation(static_cast<mutation_type>(i)))
1211         {
1212             slimy = true;
1213         }
1214     }
1215 
1216     if (!slimy)
1217         return;
1218 
1219     const god_type god = GOD_JIYVA;
1220     simple_god_message("'s gift of slime is revoked.", god);
1221     delete_mutation(RANDOM_SLIME_MUTATION, _god_wrath_name(god),
1222                     true, false, true);
1223 }
1224 
1225 /**
1226  * Make Jiyva polymorph the player into a bad form.
1227  */
_jiyva_transform()1228 static void _jiyva_transform()
1229 {
1230     const god_type god = GOD_JIYVA;
1231     god_speaks(god, "Mutagenic energy floods into your body!");
1232 
1233     const transformation form = random_choose(transformation::bat,
1234                                               transformation::fungus,
1235                                               transformation::pig,
1236                                               transformation::tree,
1237                                               transformation::wisp);
1238 
1239     if (transform(random2(you.penance[god]) * 2, form, true))
1240         you.transform_uncancellable = true;
1241 }
1242 /**
1243  * Make Jiyva contaminate tha player.
1244  */
_jiyva_contaminate()1245 static void _jiyva_contaminate()
1246 {
1247     const god_type god = GOD_JIYVA;
1248     god_speaks(god, "Mutagenic energy floods into your body!");
1249     contaminate_player(random2(you.penance[god] * 500));
1250 }
1251 
_jiyva_summon_slimes()1252 static void _jiyva_summon_slimes()
1253 {
1254     const god_type god = GOD_JIYVA;
1255 
1256     const monster_type slimes[] =
1257     {
1258         MONS_FLOATING_EYE,
1259         MONS_EYE_OF_DEVASTATION,
1260         MONS_GREAT_ORB_OF_EYES,
1261         MONS_SHINING_EYE,
1262         MONS_GLOWING_ORANGE_BRAIN,
1263         MONS_JELLY,
1264         MONS_ROCKSLIME,
1265         MONS_QUICKSILVER_OOZE,
1266         MONS_ACID_BLOB,
1267         MONS_AZURE_JELLY,
1268         MONS_SLIME_CREATURE,
1269     };
1270 
1271     const int how_many = 1 + (you.experience_level / 10) + random2(3);
1272     bool success = false;
1273 
1274     for (int i = 0; i < how_many; i++)
1275     {
1276         const monster_type slime = RANDOM_ELEMENT(slimes);
1277 
1278         if (create_monster(_wrath_mon_data(slime, god), false))
1279             success = true;
1280     }
1281 
1282     god_speaks(god, success ? "Some slimes ooze up out of the ground!"
1283                             : "The ground quivers slightly.");
1284 }
1285 
1286 /**
1287  * Call down the wrath of Jiyva upon the player!
1288  *
1289  * Mutations and slime theme.
1290  *
1291  * @return Whether to take further divine wrath actions afterward. (true.)
1292  */
_jiyva_retribution()1293 static bool _jiyva_retribution()
1294 {
1295     const god_type god = GOD_JIYVA;
1296 
1297     if (you.can_safely_mutate() && one_chance_in(7))
1298         _jiyva_mutate_player();
1299     else if (one_chance_in(3) && !you.transform_uncancellable)
1300         _jiyva_transform();
1301     else if (!one_chance_in(3) || you_worship(god))
1302         _jiyva_contaminate();
1303     else
1304         _jiyva_summon_slimes();
1305 
1306     if (coinflip())
1307         _jiyva_remove_slime_mutation();
1308 
1309     return true;
1310 }
1311 
1312 /**
1313  * Let Fedhas call down the enmity of nature upon the player!
1314  * Equal chance corrosive bolt, primal wave (a throwback to rain),
1315  * or thorn volley
1316  */
_fedhas_nature_retribution()1317 static void _fedhas_nature_retribution()
1318 {
1319     const god_type god = GOD_FEDHAS;
1320 
1321     monster* avatar = get_avatar(god);
1322     // can't be const because mons_cast() doesn't accept const monster*
1323 
1324     if (avatar == nullptr)
1325     {
1326         simple_god_message(" has no time to deal with you just now.", god);
1327         return;
1328     }
1329 
1330     spell_type spell = random_choose(SPELL_CORROSIVE_BOLT,
1331                                      SPELL_PRIMAL_WAVE,
1332                                      SPELL_THORN_VOLLEY);
1333 
1334     _spell_retribution(avatar, spell, god, " invokes nature against you.");
1335     _reset_avatar(*avatar);
1336 }
1337 
1338 // Collect lists of points that are within LOS (under the given env map),
1339 // unoccupied, and not solid (walls/statues).
_collect_radius_points(vector<vector<coord_def>> & radius_points,const coord_def & origin,los_type los)1340 static void _collect_radius_points(vector<vector<coord_def> > &radius_points,
1341                                    const coord_def &origin, los_type los)
1342 {
1343     radius_points.clear();
1344     radius_points.resize(LOS_RADIUS);
1345 
1346     // Just want to associate a point with a distance here for convenience.
1347     typedef pair<coord_def, int> coord_dist;
1348 
1349     // Using a priority queue because squares don't make very good circles at
1350     // larger radii. We will visit points in order of increasing euclidean
1351     // distance from the origin (not path distance). We want a min queue
1352     // based on the distance, so we use greater_second as the comparator.
1353     priority_queue<coord_dist, vector<coord_dist>,
1354                    greater_second<coord_dist> > fringe;
1355 
1356     fringe.push(coord_dist(origin, 0));
1357 
1358     set<int> visited_indices;
1359 
1360     int current_r = 1;
1361     int current_thresh = current_r * (current_r + 1);
1362 
1363     int max_distance = LOS_RADIUS * LOS_RADIUS + 1;
1364 
1365     while (!fringe.empty())
1366     {
1367         coord_dist current = fringe.top();
1368         // We're done here once we hit a point that is farther away from the
1369         // origin than our maximum permissible radius.
1370         if (current.second > max_distance)
1371             break;
1372 
1373         fringe.pop();
1374 
1375         int idx = current.first.x + current.first.y * X_WIDTH;
1376         if (!visited_indices.insert(idx).second)
1377             continue;
1378 
1379         while (current.second > current_thresh)
1380         {
1381             current_r++;
1382             current_thresh = current_r * (current_r + 1);
1383         }
1384 
1385         // We don't include radius 0. This is also a good place to check if
1386         // the squares are already occupied since we want to search past
1387         // occupied squares but don't want to consider them valid targets.
1388         if (current.second && !actor_at(current.first))
1389             radius_points[current_r - 1].push_back(current.first);
1390 
1391         for (adjacent_iterator i(current.first); i; ++i)
1392         {
1393             coord_dist temp(*i, current.second);
1394 
1395             // If the grid is out of LOS, skip it.
1396             if (!cell_see_cell(origin, temp.first, los))
1397                 continue;
1398 
1399             coord_def local = temp.first - origin;
1400 
1401             temp.second = local.abs();
1402 
1403             idx = temp.first.x + temp.first.y * X_WIDTH;
1404 
1405             if (!visited_indices.count(idx)
1406                 && in_bounds(temp.first)
1407                 && !cell_is_solid(temp.first))
1408             {
1409                 fringe.push(temp);
1410             }
1411         }
1412 
1413     }
1414 }
1415 
1416 // Basically we want to break a circle into n_arcs equal sized arcs and find
1417 // out which arc the input point pos falls on.
_arc_decomposition(const coord_def & pos,int n_arcs)1418 static int _arc_decomposition(const coord_def & pos, int n_arcs)
1419 {
1420     float theta = atan2((float)pos.y, (float)pos.x);
1421 
1422     if (pos.x == 0 && pos.y != 0)
1423         theta = pos.y > 0 ? PI / 2 : -PI / 2;
1424 
1425     if (theta < 0)
1426         theta += 2 * PI;
1427 
1428     float arc_angle = 2 * PI / n_arcs;
1429 
1430     theta += arc_angle / 2.0f;
1431 
1432     if (theta >= 2 * PI)
1433         theta -= 2 * PI;
1434 
1435     return static_cast<int> (theta / arc_angle);
1436 }
1437 
_place_ring(vector<coord_def> & ring_points,const coord_def & origin,mgen_data prototype,int n_arcs,int arc_occupancy,int & seen_count)1438 static int _place_ring(vector<coord_def> &ring_points,
1439                        const coord_def &origin, mgen_data prototype,
1440                        int n_arcs, int arc_occupancy, int &seen_count)
1441 {
1442     shuffle_array(ring_points);
1443 
1444     int target_amount = ring_points.size();
1445     int spawned_count = 0;
1446     seen_count = 0;
1447 
1448     vector<int> arc_counts(n_arcs, arc_occupancy);
1449 
1450     for (unsigned i = 0;
1451          spawned_count < target_amount && i < ring_points.size();
1452          i++)
1453     {
1454         int direction = _arc_decomposition(ring_points.at(i)
1455                                            - origin, n_arcs);
1456 
1457         if (arc_counts[direction]-- <= 0)
1458             continue;
1459 
1460         prototype.pos = ring_points.at(i);
1461 
1462         if (create_monster(prototype, false))
1463         {
1464             spawned_count++;
1465             if (you.see_cell(ring_points.at(i)))
1466                 seen_count++;
1467         }
1468     }
1469 
1470     return spawned_count;
1471 }
1472 
1473 template<typename T>
less_second(const T & left,const T & right)1474 static bool less_second(const T & left, const T & right)
1475 {
1476     return left.second < right.second;
1477 }
1478 
1479 typedef pair<coord_def, int> point_distance;
1480 
1481 // Find the distance from origin to each of the targets, those results
1482 // are stored in distances (which is the same size as targets). Exclusion
1483 // is a set of points which are considered disconnected for the search.
_path_distance(const coord_def & origin,const vector<coord_def> & targets,set<int> exclusion,vector<int> & distances)1484 static void _path_distance(const coord_def& origin,
1485                            const vector<coord_def>& targets,
1486                            set<int> exclusion,
1487                            vector<int>& distances)
1488 {
1489     queue<point_distance> fringe;
1490     fringe.push(point_distance(origin,0));
1491     distances.clear();
1492     distances.resize(targets.size(), INT_MAX);
1493 
1494     while (!fringe.empty())
1495     {
1496         point_distance current = fringe.front();
1497         fringe.pop();
1498 
1499         // did we hit a target?
1500         for (unsigned i = 0; i < targets.size(); ++i)
1501         {
1502             if (current.first == targets[i])
1503             {
1504                 distances[i] = current.second;
1505                 break;
1506             }
1507         }
1508 
1509         for (adjacent_iterator adj_it(current.first); adj_it; ++adj_it)
1510         {
1511             int idx = adj_it->x + adj_it->y * X_WIDTH;
1512             if (you.see_cell(*adj_it)
1513                 && !feat_is_solid(env.grid(*adj_it))
1514                 && *adj_it != you.pos()
1515                 && exclusion.insert(idx).second)
1516             {
1517                 monster* temp = monster_at(*adj_it);
1518                 if (!temp || (temp->attitude == ATT_HOSTILE
1519                               && !temp->is_stationary()))
1520                 {
1521                     fringe.push(point_distance(*adj_it, current.second+1));
1522                 }
1523             }
1524         }
1525     }
1526 }
1527 
1528 // Find the minimum distance from each point of origin to one of the targets
1529 // The distance is stored in 'distances', which is the same size as origins.
_point_point_distance(const vector<coord_def> & origins,const vector<coord_def> & targets,vector<int> & distances)1530 static void _point_point_distance(const vector<coord_def>& origins,
1531                                   const vector<coord_def>& targets,
1532                                   vector<int>& distances)
1533 {
1534     distances.clear();
1535     distances.resize(origins.size(), INT_MAX);
1536 
1537     // Consider all points of origin as blocked (you can search outward
1538     // from one, but you can't form a path across a different one).
1539     set<int> base_exclusions;
1540     for (coord_def c : origins)
1541     {
1542         int idx = c.x + c.y * X_WIDTH;
1543         base_exclusions.insert(idx);
1544     }
1545 
1546     vector<int> current_distances;
1547     for (unsigned i = 0; i < origins.size(); ++i)
1548     {
1549         // Find the distance from the point of origin to each of the targets.
1550         _path_distance(origins[i], targets, base_exclusions,
1551                        current_distances);
1552 
1553         // Find the smallest of those distances
1554         int min_dist = current_distances[0];
1555         for (unsigned j = 1; j < current_distances.size(); ++j)
1556             if (current_distances[j] < min_dist)
1557                 min_dist = current_distances[j];
1558 
1559         distances[i] = min_dist;
1560     }
1561 }
1562 
1563 // So the idea is we want to decide which adjacent tiles are in the most
1564 // 'danger' We claim danger is proportional to the minimum distances from the
1565 // point to a (hostile) monster. This function carries out at most 7 searches
1566 // to calculate the distances in question.
_prioritise_adjacent(const coord_def & target,vector<coord_def> & candidates)1567 static bool _prioritise_adjacent(const coord_def &target,
1568                                  vector<coord_def>& candidates)
1569 {
1570     radius_iterator los_it(target, LOS_NO_TRANS, true);
1571 
1572     vector<coord_def> mons_positions;
1573     // collect hostile monster positions in LOS
1574     for (; los_it; ++los_it)
1575     {
1576         monster* hostile = monster_at(*los_it);
1577 
1578         if (hostile && hostile->attitude == ATT_HOSTILE
1579             && you.can_see(*hostile))
1580         {
1581             mons_positions.push_back(hostile->pos());
1582         }
1583     }
1584 
1585     if (mons_positions.empty())
1586     {
1587         shuffle_array(candidates);
1588         return true;
1589     }
1590 
1591     vector<int> distances;
1592 
1593     _point_point_distance(candidates, mons_positions, distances);
1594 
1595     vector<point_distance> possible_moves(candidates.size());
1596 
1597     for (unsigned i = 0; i < possible_moves.size(); ++i)
1598     {
1599         possible_moves[i].first  = candidates[i];
1600         possible_moves[i].second = distances[i];
1601     }
1602 
1603     sort(possible_moves.begin(), possible_moves.end(),
1604               less_second<point_distance>);
1605 
1606     for (unsigned i = 0; i < candidates.size(); ++i)
1607         candidates[i] = possible_moves[i].first;
1608 
1609     return true;
1610 }
1611 
1612 /**
1613  * Summon Fedhas's oklobs & mushrooms around the player.
1614  *
1615  * @return Whether to take further divine wrath actions afterward.
1616  */
_fedhas_summon_plants()1617 static bool _fedhas_summon_plants()
1618 {
1619     const god_type god = GOD_FEDHAS;
1620     bool success = false;
1621 
1622     // We are going to spawn some oklobs but first we need to find
1623     // out a little about the situation.
1624     vector<vector<coord_def> > radius_points;
1625     _collect_radius_points(radius_points, you.pos(), LOS_NO_TRANS);
1626 
1627     int max_idx = 3;
1628     unsigned max_points = radius_points[max_idx].size();
1629 
1630     for (unsigned i = max_idx + 1; i < radius_points.size(); i++)
1631     {
1632         if (radius_points[i].size() > max_points)
1633         {
1634             max_points = radius_points[i].size();
1635             max_idx = i;
1636         }
1637     }
1638 
1639     mgen_data temp = _wrath_mon_data(MONS_OKLOB_PLANT, god);
1640 
1641     // If we have a lot of space to work with we can do something
1642     // flashy.
1643     if (radius_points[max_idx].size() > 24)
1644     {
1645         int seen_count;
1646 
1647         temp.cls = MONS_PLANT;
1648 
1649         _place_ring(radius_points[0], you.pos(), temp, 1,
1650                 radius_points[0].size(), seen_count);
1651 
1652         if (seen_count > 0)
1653             success = true;
1654 
1655         temp.cls = MONS_OKLOB_PLANT;
1656 
1657         _place_ring(radius_points[max_idx], you.pos(), temp,
1658                 random_range(3, 8), 1, seen_count);
1659 
1660         if (seen_count > 0)
1661             success = true;
1662     }
1663     // Otherwise we do something with the nearest neighbors
1664     // (assuming the player isn't already surrounded).
1665     else if (!radius_points[0].empty())
1666     {
1667         unsigned target_count = random_range(2, 8);
1668         if (target_count < radius_points[0].size())
1669             _prioritise_adjacent(you.pos(), radius_points[0]);
1670         else
1671             target_count = radius_points[0].size();
1672 
1673         for (unsigned i = radius_points[0].size() - target_count;
1674              i < radius_points[0].size(); ++i)
1675         {
1676             temp.pos = radius_points[0].at(i);
1677             temp.cls = coinflip() ? MONS_WANDERING_MUSHROOM
1678                                   : MONS_OKLOB_PLANT;
1679 
1680             if (create_monster(temp, false))
1681                 success = true;
1682         }
1683     }
1684 
1685     if (success)
1686     {
1687         god_speaks(god, "Plants grow around you in an ominous manner.");
1688         return false;
1689     }
1690 
1691     return true;
1692 }
1693 
_fedhas_corpse_spores(beh_type attitude)1694 static int _fedhas_corpse_spores(beh_type attitude)
1695 {
1696     vector<stack_iterator> positions;
1697     int count = _count_corpses_in_los(&positions);
1698     ASSERT(attitude != BEH_FRIENDLY || count > 0);
1699 
1700     if (count == 0)
1701         return count;
1702 
1703     for (const stack_iterator &si : positions)
1704     {
1705         count++;
1706 
1707         if (monster *plant = create_monster(mgen_data(MONS_BALLISTOMYCETE_SPORE,
1708                                                attitude,
1709                                                si->pos,
1710                                                MHITNOT,
1711                                                MG_FORCE_PLACE,
1712                                                GOD_FEDHAS)
1713                                             .set_summoned(&you, 0, 0)))
1714         {
1715             plant->flags |= MF_NO_REWARD;
1716 
1717             if (attitude == BEH_FRIENDLY)
1718             {
1719                 plant->flags |= MF_ATT_CHANGE_ATTEMPT;
1720 
1721                 mons_make_god_gift(*plant, GOD_FEDHAS);
1722 
1723                 plant->behaviour = BEH_WANDER;
1724                 plant->foe = MHITNOT;
1725             }
1726         }
1727 
1728         if (mons_skeleton(si->mon_type))
1729             turn_corpse_into_skeleton(*si);
1730         else
1731         {
1732             item_was_destroyed(*si);
1733             destroy_item(si->index());
1734         }
1735     }
1736 
1737     viewwindow(false);
1738     update_screen();
1739 
1740     return count;
1741 }
1742 
1743 /**
1744  * Call down the wrath of Fedhas upon the player!
1745  *
1746  * Plants and plant/nature themed attacks.
1747  *
1748  * @return Whether to take further divine wrath actions afterward.
1749  */
_fedhas_retribution()1750 static bool _fedhas_retribution()
1751 {
1752     const god_type god = GOD_FEDHAS;
1753 
1754     // We have 3 forms of retribution, but players under penance will be
1755     // spared the 'you are now surrounded by oklob plants, please die' one.
1756     const int retribution_options = you_worship(god) ? 2 : 3;
1757 
1758     switch (random2(retribution_options))
1759     {
1760     case 0:
1761         // Try and spawn some hostile ballistomycete spores, if none are created
1762         // fall through to the elemental miscast effects.
1763         if (_fedhas_corpse_spores(BEH_HOSTILE))
1764         {
1765             simple_god_message(" produces spores.", god);
1766             return true;
1767         }
1768 
1769     case 1:
1770     default:
1771         _fedhas_nature_retribution();
1772         return true;
1773 
1774     case 2:
1775         return _fedhas_summon_plants();
1776     }
1777 }
1778 
_dithmenos_retribution()1779 static bool _dithmenos_retribution()
1780 {
1781     // shadow theme
1782     const god_type god = GOD_DITHMENOS;
1783 
1784     switch (random2(4))
1785     {
1786     case 0:
1787     {
1788         int count = 0;
1789         int how_many = 3 + random2avg(div_rand_round(you.experience_level, 3),
1790                                       2);
1791         const int tier = div_rand_round(you.experience_level, 9);
1792         while (how_many-- > 0)
1793         {
1794             if (_dithmenos_random_shadow(count, tier))
1795                 count++;
1796         }
1797         simple_god_message(count ? " calls forth shadows to punish you."
1798                                  : " fails to incite the shadows against you.",
1799                            god);
1800         break;
1801     }
1802     case 1:
1803     {
1804         int count = 0;
1805         int how_many = 2 + random2avg(div_rand_round(you.experience_level, 4),
1806                                       4);
1807         for (int i = 0; i < how_many; ++i)
1808         {
1809             if (create_monster(
1810                     mgen_data(
1811                         RANDOM_MOBILE_MONSTER, BEH_HOSTILE, you.pos(), MHITYOU,
1812                               MG_NONE, god)
1813                             .set_place(level_id(BRANCH_DUNGEON,
1814                                                 min(27,
1815                                                     you.experience_level + 5)))
1816                             .set_summoned(nullptr, 4, MON_SUMM_WRATH)
1817                             .set_non_actor_summoner(_god_wrath_name(god))))
1818             {
1819                 count++;
1820             }
1821         }
1822         simple_god_message(count ? " weaves monsters from the shadows."
1823                                  : " fails to weave monsters from the shadows.",
1824                            god);
1825         break;
1826     }
1827     case 2:
1828     {
1829         // This is possibly kind of underwhelming?
1830         god_speaks(god, "You feel overwhelmed by the shadows around you.");
1831         you.put_to_sleep(nullptr, 30 + random2(20));
1832         break;
1833     }
1834     case 3:
1835         simple_god_message(" tears the shadows away from you.", god);
1836         you.sentinel_mark();
1837         break;
1838     }
1839     return true;
1840 }
1841 
1842 static const vector<pop_entry> pop_qazlal_wrath =
1843 {
1844   {  0, 12, 25, SEMI, MONS_AIR_ELEMENTAL },
1845   {  4, 12, 50, FLAT, MONS_WIND_DRAKE },
1846   { 10, 22, 50, SEMI, MONS_SPARK_WASP },
1847   { 18, 27, 50, RISE, MONS_STORM_DRAGON },
1848 
1849   {  0, 12, 25, SEMI, MONS_FIRE_ELEMENTAL },
1850   {  4, 12, 50, FLAT, MONS_FIRE_CRAB },
1851   {  8, 16, 30, FLAT, MONS_LINDWURM },
1852   { 12, 27, 50, SEMI, MONS_FIRE_DRAGON },
1853 
1854   {  0, 12, 25, SEMI, MONS_WATER_ELEMENTAL },
1855   {  2, 10, 50, FLAT, MONS_RIME_DRAKE },
1856   { 12, 27, 50, SEMI, MONS_ICE_DRAGON },
1857   { 20, 27, 30, RISE, MONS_SHARD_SHRIKE },
1858 
1859   {  0, 12, 25, SEMI, MONS_EARTH_ELEMENTAL },
1860   {  2, 10, 50, FLAT, MONS_BASILISK },
1861   {  4, 14, 30, FLAT, MONS_BOULDER_BEETLE },
1862   { 18, 27, 50, RISE, MONS_IRON_DRAGON },
1863 };
1864 
1865 /**
1866  * Summon elemental creatures to destroy the player!
1867  */
_qazlal_summon_elementals()1868 static void _qazlal_summon_elementals()
1869 {
1870     const god_type god = GOD_QAZLAL;
1871 
1872     const int how_many = 1 + div_rand_round(you.experience_level, 7);
1873     bool success = false;
1874 
1875     for (int i = 0; i < how_many; i++)
1876     {
1877         monster_type mon = pick_monster_from(pop_qazlal_wrath,
1878                                              you.experience_level);
1879 
1880         if (create_monster(_wrath_mon_data(mon, god), false))
1881             success = true;
1882     }
1883 
1884     if (success)
1885         simple_god_message(" incites the elements against you!", god);
1886     else
1887         simple_god_message(" fails to incite the elements against you.", god);
1888 }
1889 
1890 /**
1891  * Give the player temporary elemental-vulnerability mutations.
1892  */
_qazlal_elemental_vulnerability()1893 static void _qazlal_elemental_vulnerability()
1894 {
1895     const god_type god = GOD_QAZLAL;
1896 
1897     if (mutate(RANDOM_QAZLAL_MUTATION, _god_wrath_name(god), false,
1898                false, true, false, MUTCLASS_TEMPORARY))
1899     {
1900         simple_god_message(" strips away your elemental protection.",
1901                            god);
1902     }
1903     else
1904     {
1905         simple_god_message(" fails to strip away your elemental protection.",
1906                            god);
1907     }
1908 }
1909 
1910 /**
1911  * Call down the wrath of Qazlal upon the player!
1912  *
1913  * Disaster/elemental theme.
1914  *
1915  * @return Whether to take further divine wrath actions afterward.
1916  */
_qazlal_retribution()1917 static bool _qazlal_retribution()
1918 {
1919     if (coinflip())
1920     {
1921         simple_god_message(" causes a mighty clap of thunder!",
1922                            GOD_QAZLAL);
1923         noisy(25, you.pos());
1924     }
1925 
1926     if (coinflip())
1927         _qazlal_summon_elementals();
1928     else
1929         _qazlal_elemental_vulnerability();
1930 
1931     return true;
1932 }
1933 
_choose_hostile_monster(const monster & mon)1934 static bool _choose_hostile_monster(const monster& mon)
1935 {
1936     return mon.attitude == ATT_HOSTILE;
1937 }
1938 
_wu_jian_summon_weapons()1939 static int _wu_jian_summon_weapons()
1940 {
1941     god_type god = GOD_WU_JIAN;
1942     const int num = 3 + random2(3);
1943     int created = 0;
1944 
1945     for (int i = 0; i < num; ++i)
1946     {
1947         const int subtype = random_choose(WPN_DIRE_FLAIL, WPN_QUARTERSTAFF,
1948                                           WPN_BROAD_AXE, WPN_GREAT_SWORD,
1949                                           WPN_RAPIER, WPN_GLAIVE);
1950         const int ego = random_choose(SPWPN_VORPAL, SPWPN_FLAMING,
1951                                       SPWPN_FREEZING, SPWPN_ELECTROCUTION,
1952                                       SPWPN_SPEED);
1953 
1954         if (monster *mon =
1955             create_monster(_wrath_mon_data(MONS_DANCING_WEAPON, god)))
1956         {
1957             ASSERT(mon->weapon() != nullptr);
1958             item_def& wpn(*mon->weapon());
1959 
1960             set_item_ego_type(wpn, OBJ_WEAPONS, ego);
1961 
1962             wpn.plus = random2(5);
1963             wpn.sub_type = subtype;
1964 
1965             set_ident_flags(wpn, ISFLAG_KNOW_TYPE);
1966 
1967             item_colour(wpn);
1968 
1969             ghost_demon newstats;
1970             newstats.init_dancing_weapon(wpn, you.experience_level * 50 / 9);
1971 
1972             mon->set_ghost(newstats);
1973             mon->ghost_demon_init();
1974 
1975             created++;
1976         }
1977     }
1978 
1979     return created;
1980 }
1981 
_wu_jian_retribution()1982 static bool _wu_jian_retribution()
1983 {
1984     god_type god = GOD_WU_JIAN;
1985 
1986     if (_wu_jian_summon_weapons())
1987     {
1988         switch (random2(4))
1989         {
1990         case 0:
1991             wu_jian_sifu_message(" says: Die by a thousand cuts!");
1992             you.set_duration(DUR_BARBS, random_range(5, 10));
1993             break;
1994         case 1:
1995             wu_jian_sifu_message(" whispers: Nowhere to run...");
1996             you.set_duration(DUR_SLOW, random_range(5, 10));
1997             break;
1998         case 2:
1999             wu_jian_sifu_message(" whispers: These will loosen your tongue!");
2000             you.increase_duration(DUR_SILENCE, 5 + random2(11), 50);
2001             invalidate_agrid(true);
2002             break;
2003         case 3:
2004             wu_jian_sifu_message(" says: Suffer, mortal!");
2005             you.corrode_equipment(_god_wrath_name(god).c_str(), 2);
2006             break;
2007         }
2008     }
2009     else
2010         simple_god_message("'s divine weapons fail to arrive.", god);
2011 
2012     return true;
2013 }
2014 
_uskayaw_retribution()2015 static bool _uskayaw_retribution()
2016 {
2017     const god_type god = GOD_USKAYAW;
2018 
2019     // check if we have monsters around
2020     monster* mon = nullptr;
2021     mon = choose_random_nearby_monster(0, _choose_hostile_monster);
2022 
2023     switch (random2(5))
2024     {
2025     case 0:
2026     case 1:
2027         if (mon && mon->can_go_berserk())
2028         {
2029             simple_god_message(make_stringf(" drives %s into a dance frenzy!",
2030                                      mon->name(DESC_THE).c_str()).c_str(), god);
2031             mon->go_berserk(true);
2032             return true;
2033         }
2034         // else we intentionally fall through
2035 
2036     case 2:
2037     case 3:
2038         if (mon)
2039         {
2040             simple_god_message(" booms out, \"Time for someone else to take a solo\"",
2041                                     god);
2042             paralyse_player(_god_wrath_name(god));
2043             dec_penance(god, 1);
2044             return false;
2045         }
2046         // else we intentionally fall through
2047 
2048     case 4:
2049         simple_god_message(" booms out: \"Revellers, it's time to dance!\"", god);
2050         noisy(35, you.pos());
2051         break;
2052     }
2053     return true;
2054 }
2055 
divine_retribution(god_type god,bool no_bonus,bool force)2056 bool divine_retribution(god_type god, bool no_bonus, bool force)
2057 {
2058     ASSERT(god != GOD_NO_GOD);
2059 
2060     if (is_unavailable_god(god))
2061         return false;
2062 
2063     // Good gods don't use divine retribution on their followers, and
2064     // gods don't use divine retribution on followers of gods they don't
2065     // hate.
2066     if (!force && ((god == you.religion && is_good_god(god))
2067         || (god != you.religion && !god_hates_your_god(god))))
2068     {
2069         return false;
2070     }
2071 
2072     god_acting gdact(god, true);
2073 
2074     bool do_more    = true;
2075     switch (god)
2076     {
2077     // One in ten chance that Xom might do something good...
2078     case GOD_XOM:
2079         xom_acts(abs(you.piety - HALF_MAX_PIETY),
2080                  frombool(one_chance_in(10)));
2081         break;
2082     case GOD_SHINING_ONE:   do_more = _tso_retribution(); break;
2083     case GOD_ZIN:           do_more = _zin_retribution(); break;
2084     case GOD_MAKHLEB:       do_more = _makhleb_retribution(); break;
2085     case GOD_KIKUBAAQUDGHA: do_more = _kikubaaqudgha_retribution(); break;
2086     case GOD_YREDELEMNUL:   do_more = _yredelemnul_retribution(); break;
2087     case GOD_TROG:          do_more = _trog_retribution(); break;
2088     case GOD_BEOGH:         do_more = _beogh_retribution(); break;
2089     case GOD_OKAWARU:       do_more = _okawaru_retribution(); break;
2090     case GOD_LUGONU:        do_more = _lugonu_retribution(); break;
2091     case GOD_VEHUMET:       do_more = _vehumet_retribution(); break;
2092     case GOD_NEMELEX_XOBEH: do_more = _nemelex_retribution(); break;
2093     case GOD_SIF_MUNA:      do_more = _sif_muna_retribution(); break;
2094     case GOD_JIYVA:         do_more = _jiyva_retribution(); break;
2095     case GOD_FEDHAS:        do_more = _fedhas_retribution(); break;
2096     case GOD_CHEIBRIADOS:   do_more = _cheibriados_retribution(); break;
2097     case GOD_DITHMENOS:     do_more = _dithmenos_retribution(); break;
2098     case GOD_QAZLAL:        do_more = _qazlal_retribution(); break;
2099     case GOD_USKAYAW:       do_more = _uskayaw_retribution(); break;
2100     case GOD_WU_JIAN:       do_more = _wu_jian_retribution(); break;
2101 
2102     case GOD_ASHENZARI:
2103     case GOD_ELYVILON:
2104     case GOD_GOZAG:
2105     case GOD_RU:
2106     case GOD_HEPLIAKLQANA:
2107 #if TAG_MAJOR_VERSION == 34
2108     case GOD_PAKELLAS:
2109 #endif
2110         // No reduction with time.
2111         return false;
2112 
2113     default:
2114 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_RELIGION)
2115         mprf(MSGCH_DIAGNOSTICS, "No retribution defined for %s.",
2116              god_name(god).c_str());
2117 #endif
2118         return false;
2119     }
2120 
2121     if (no_bonus)
2122         return true;
2123 
2124     // Sometimes divine experiences are overwhelming...
2125     if (do_more && one_chance_in(5) && you.experience_level < random2(37))
2126     {
2127         if (coinflip())
2128         {
2129             if (!you.confused())
2130             {
2131                 mprf(MSGCH_WARN, "The divine experience confuses you!");
2132                 confuse_player(5 + random2(3));
2133             }
2134         }
2135         else
2136         {
2137             if (you.duration[DUR_SLOW] < 180 * BASELINE_DELAY)
2138             {
2139                 mprf(MSGCH_WARN, "The divine experience drains your vigour!");
2140 
2141                 slow_player(random2(20));
2142             }
2143         }
2144     }
2145 
2146     // Just the thought of retribution mollifies the god by at least a
2147     // point...the punishment might have reduced penance further.
2148     dec_penance(god, 1 + random2(3));
2149 
2150     return true;
2151 }
2152 
_tso_blasts_cleansing_flame(const char * message)2153 static void _tso_blasts_cleansing_flame(const char *message)
2154 {
2155     // If there's a message, display it before firing.
2156     if (message)
2157         god_speaks(GOD_SHINING_ONE, message);
2158 
2159     simple_god_message(" blasts you with cleansing flame!",
2160                        GOD_SHINING_ONE);
2161 
2162     // damage is 2d(pow), *3/2 for undead and demonspawn
2163     cleansing_flame(5 + (you.experience_level * 7) / 12,
2164                     cleansing_flame_source::tso, you.pos());
2165 }
2166 
_god_smites_you(god_type god,const char * message,kill_method_type death_type)2167 static void _god_smites_you(god_type god, const char *message,
2168                             kill_method_type death_type)
2169 {
2170     ASSERT(god != GOD_NO_GOD);
2171 
2172     if (death_type == NUM_KILLBY)
2173     {
2174         switch (god)
2175         {
2176             case GOD_BEOGH:     death_type = KILLED_BY_BEOGH_SMITING; break;
2177             case GOD_SHINING_ONE: death_type = KILLED_BY_TSO_SMITING; break;
2178             default:            death_type = KILLED_BY_DIVINE_WRATH;  break;
2179         }
2180     }
2181 
2182     string aux;
2183 
2184     if (death_type != KILLED_BY_BEOGH_SMITING
2185         && death_type != KILLED_BY_TSO_SMITING)
2186     {
2187         aux = "smitten by " + god_name(god);
2188     }
2189 
2190     // If there's a message, display it before smiting.
2191     if (message)
2192         god_speaks(god, message);
2193 
2194     int divine_hurt = 10 + random2(10);
2195 
2196     for (int i = 0; i < 5; ++i)
2197         divine_hurt += random2(you.experience_level);
2198 
2199     simple_god_message(" smites you!", god);
2200     ouch(divine_hurt, death_type, MID_NOBODY, aux.c_str());
2201 }
2202 
reduce_xp_penance(god_type god,int amount)2203 void reduce_xp_penance(god_type god, int amount)
2204 {
2205     if (!you.penance[god] || !you.exp_docked_total[god])
2206         return;
2207 
2208     int lost = min(amount / 2, you.exp_docked[god]);
2209     you.exp_docked[god] -= lost;
2210 
2211     int new_pen = (((int64_t)you.exp_docked[god] * 50)
2212                    + you.exp_docked_total[god] - 1)
2213                 / you.exp_docked_total[god];
2214     if (new_pen < you.penance[god])
2215         dec_penance(god, you.penance[god] - new_pen);
2216 }
2217 
gozag_incite(monster * mon)2218 void gozag_incite(monster *mon)
2219 {
2220     ASSERT(!mon->wont_attack());
2221 
2222     behaviour_event(mon, ME_ALERT, &you);
2223 
2224     bool success = false;
2225 
2226     if (mon->needs_berserk(true, true))
2227     {
2228         mon->go_berserk(true);
2229         success = true;
2230     }
2231     else if (!mon->has_ench(ENCH_HASTE))
2232     {
2233         enchant_actor_with_flavour(mon, mon, BEAM_HASTE);
2234         success = true;
2235     }
2236 
2237     if (success)
2238     {
2239         mon->add_ench(ENCH_GOZAG_INCITE);
2240         view_update_at(mon->pos());
2241     }
2242 }
2243