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