1 /**
2 * @file
3 * @brief Misc religion related functions.
4 **/
5
6 #include "AppHdr.h"
7
8 #include "religion.h"
9
10 #include <algorithm>
11 #include <cmath>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 #include <functional>
16 #include <sstream>
17
18 #include "ability.h"
19 #include "acquire.h"
20 #include "act-iter.h"
21 #include "areas.h"
22 #include "attitude-change.h"
23 #include "branch.h"
24 #include "chardump.h"
25 #include "coordit.h"
26 #include "dactions.h"
27 #include "database.h"
28 #include "decks.h"
29 #include "delay.h"
30 #include "describe-god.h"
31 #include "dgn-event.h"
32 #include "dlua.h"
33 #include "english.h"
34 #include "env.h"
35 #include "god-abil.h"
36 #include "god-companions.h"
37 #include "god-conduct.h"
38 #include "god-item.h"
39 #include "god-passive.h"
40 #include "god-prayer.h"
41 #include "god-wrath.h"
42 #include "hints.h"
43 #include "hiscores.h"
44 #include "invent.h"
45 #include "item-name.h"
46 #include "item-prop.h"
47 #include "item-status-flag-type.h"
48 #include "items.h"
49 #include "level-state-type.h"
50 #include "libutil.h"
51 #include "makeitem.h"
52 #include "message.h"
53 #include "mon-gear.h" // give_shield
54 #include "mon-place.h"
55 #include "mutation.h"
56 #include "nearby-danger.h"
57 #include "notes.h"
58 #include "output.h"
59 #include "player-equip.h"
60 #include "player-stats.h"
61 #include "prompt.h"
62 #include "randbook.h"
63 #include "shopping.h"
64 #include "skills.h"
65 #include "spl-book.h"
66 #include "sprint.h"
67 #include "state.h"
68 #include "stringutil.h"
69 #include "tag-version.h"
70 #include "terrain.h"
71 #include "transform.h"
72 #include "view.h"
73
74 #ifdef DEBUG_RELIGION
75 # define DEBUG_DIAGNOSTICS
76 # define DEBUG_GIFTS
77 # define DEBUG_SACRIFICE
78 # define DEBUG_PIETY
79 #endif
80
81 #define PIETY_HYSTERESIS_LIMIT 1
82
83 static weapon_type _hepliaklqana_weapon_type(monster_type mc, int HD);
84 static brand_type _hepliaklqana_weapon_brand(monster_type mc, int HD);
85 static armour_type _hepliaklqana_shield_type(monster_type mc, int HD);
86 static special_armour_type _hepliaklqana_shield_ego(int HD);
87
88 const vector<god_power> god_powers[NUM_GODS] =
89 {
90 // no god
91 { },
92
93 // Zin
94 { { 1, ABIL_ZIN_RECITE, "recite Zin's Axioms of Law" },
95 { 2, ABIL_ZIN_VITALISATION, "call upon Zin for vitalisation" },
96 { 3, ABIL_ZIN_IMPRISON, "call upon Zin to imprison the lawless" },
97 { 5, ABIL_ZIN_SANCTUARY, "call upon Zin to create a sanctuary" },
98 { 6, "Zin will now cleanse your potions of mutation.",
99 "Zin will no longer cleanse your potions of mutation.",
100 "Zin will cleanse your potions of mutation." },
101 {-1, ABIL_ZIN_DONATE_GOLD, "donate money to Zin" },
102 },
103
104 // TSO
105 { { 1, "You and your allies can now gain power from killing the unholy and evil.",
106 "You and your allies can no longer gain power from killing the unholy and evil.",
107 "You and your allies can gain power from killing the unholy and evil." },
108 { 2, ABIL_TSO_DIVINE_SHIELD, "call upon the Shining One for a divine shield" },
109 { 4, ABIL_TSO_CLEANSING_FLAME, "channel blasts of cleansing flame", },
110 { 5, ABIL_TSO_SUMMON_DIVINE_WARRIOR, "summon a divine warrior" },
111 { 7, ABIL_TSO_BLESS_WEAPON,
112 "The Shining One will bless your weapon with holy wrath... once.",
113 "The Shining One is no longer ready to bless your weapon." },
114 },
115
116 // Kikubaaqudgha
117 { { 1, ABIL_KIKU_RECEIVE_CORPSES, "receive cadavers from Kikubaaqudgha" },
118 { 2, "Kikubaaqudgha is now protecting you from necromantic miscasts and death curses.",
119 "Kikubaaqudgha will no longer protect you from necromantic miscasts or death curses.",
120 "Kikubaaqudgha protects you from necromantic miscasts and death curses." },
121 { 4, "Kikubaaqudgha is now protecting you from unholy torment.",
122 "Kikubaaqudgha will no longer protect you from unholy torment.",
123 "Kikubaaqudgha protects you from unholy torment." },
124 { 5, ABIL_KIKU_TORMENT, "invoke torment by sacrificing a corpse" },
125 { 7, ABIL_KIKU_BLESS_WEAPON,
126 "Kikubaaqudgha will grant you forbidden knowledge or bloody your weapon with pain... once.",
127 "Kikubaaqudgha is no longer ready to enhance your necromancy." },
128 { 7, ABIL_KIKU_GIFT_CAPSTONE_SPELLS,
129 "Kikubaaqudgha will grant you forbidden knowledge.",
130 "Kikubaaqudgha is no longer ready to enhance your necromancy." },
131 },
132
133 // Yredelemnul
134 { { 1, ABIL_YRED_ANIMATE_REMAINS, "animate remains" },
135 { 2, ABIL_YRED_RECALL_UNDEAD_SLAVES, "recall your undead slaves" },
136 { 2, ABIL_YRED_INJURY_MIRROR, "mirror injuries on your foes" },
137 { 3, ABIL_YRED_ANIMATE_DEAD, "animate legions of the dead" },
138 { 3, "Yredelemnul will now gift you servants as you gain piety.",
139 "Yredelemnul will no longer gift you servants.",
140 "Yredelemnul will gift you servants as you gain piety." },
141 { 4, ABIL_YRED_DRAIN_LIFE, "drain ambient life force" },
142 { 5, ABIL_YRED_ENSLAVE_SOUL, "enslave living souls" },
143 },
144
145 // Xom
146 { },
147
148 // Vehumet
149 { { 1, "gain magical power from killing" },
150 { 3, "Vehumet is now aiding your destructive spells.",
151 "Vehumet will no longer aid your destructive spells.",
152 "Vehumet aids your destructive spells." },
153 { 4, "Vehumet is now extending the range of your destructive spells.",
154 "Vehumet will no longer extend the range of your destructive spells.",
155 "Vehumet extends the range of your destructive spells." },
156 },
157
158 // Okawaru
159 { { 1, ABIL_OKAWARU_HEROISM, "gain great but temporary skills" },
160 { 3, "Okawaru will now gift you ammunition as you gain piety.",
161 "Okawaru will no longer gift you ammunition.",
162 "Okawaru will gift you ammunition as you gain piety." },
163 { 5, ABIL_OKAWARU_FINESSE, "speed up your combat" },
164 { 5, "Okawaru will now gift you equipment as you gain piety.",
165 "Okawaru will no longer gift you equipment.",
166 "Okawaru will gift you equipment as you gain piety." },
167 },
168
169 // Makhleb
170 { { 1, "gain health from killing" },
171 { 2, ABIL_MAKHLEB_MINOR_DESTRUCTION,
172 "harness Makhleb's destructive might" },
173 { 3, ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB,
174 "summon a lesser servant of Makhleb" },
175 { 4, ABIL_MAKHLEB_MAJOR_DESTRUCTION,
176 "hurl Makhleb's greater destruction" },
177 { 5, ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB,
178 "summon a greater servant of Makhleb" },
179 },
180
181 // Sif Muna
182 { { 1, ABIL_SIF_MUNA_CHANNEL_ENERGY,
183 "call upon Sif Muna for magical energy" },
184 { 3, ABIL_SIF_MUNA_FORGET_SPELL,
185 "freely open your mind to new spells",
186 "forget spells at will" },
187 { 4, ABIL_SIF_MUNA_DIVINE_EXEGESIS,
188 "call upon Sif Muna to cast any spell from your library" },
189 { 5, "Sif Muna will now gift you books as you gain piety.",
190 "Sif Muna will no longer gift you books.",
191 "Sif Muna will gift you books as you gain piety." },
192 },
193
194 // Trog
195 {
196 { 1, ABIL_TROG_BERSERK, "go berserk at will" },
197 { 2, ABIL_TROG_HAND,
198 "call upon Trog for regeneration and willpower" },
199 { 4, ABIL_TROG_BROTHERS_IN_ARMS, "call in reinforcements" },
200 { 5, "Trog will now gift you melee weapons as you gain piety.",
201 "Trog will no longer gift you weapons.",
202 "Trog will gift you melee weapons as you gain piety." },
203 },
204
205 // Nemelex
206 {
207 { 0, "draw from decks of power" },
208 { 1, "Nemelex will now gift you decks of power as you gain piety.",
209 "Nemelex will no longer gift you decks.",
210 "Nemelex will gift you decks of power as you gain piety." },
211 { 3, ABIL_NEMELEX_TRIPLE_DRAW, "choose one out of three cards" },
212 { 4, ABIL_NEMELEX_DEAL_FOUR, "deal four cards at a time" },
213 { 5, ABIL_NEMELEX_STACK_FIVE, "stack five cards from your decks",
214 "stack cards" },
215 },
216
217 // Elyvilon
218 { { 1, ABIL_ELYVILON_LESSER_HEALING, "provide lesser healing for yourself" },
219 { 2, ABIL_ELYVILON_HEAL_OTHER, "heal and attempt to pacify others" },
220 { 3, ABIL_ELYVILON_PURIFICATION, "purify yourself" },
221 { 4, ABIL_ELYVILON_GREATER_HEALING, "provide greater healing for yourself" },
222 { 5, ABIL_ELYVILON_DIVINE_VIGOUR, "call upon Elyvilon for divine vigour" },
223 { 1, ABIL_ELYVILON_LIFESAVING, "call on Elyvilon to save your life" },
224 },
225
226 // Lugonu
227 { { 1, ABIL_LUGONU_ABYSS_EXIT,
228 "depart the Abyss",
229 "depart the Abyss at will" },
230 { 2, ABIL_LUGONU_BEND_SPACE, "bend space around yourself" },
231 { 3, ABIL_LUGONU_BANISH, "banish your foes" },
232 { 4, ABIL_LUGONU_CORRUPT, "corrupt the fabric of space" },
233 { 5, ABIL_LUGONU_ABYSS_ENTER, "gate yourself to the Abyss" },
234 { 7, ABIL_LUGONU_BLESS_WEAPON,
235 "Lugonu will corrupt your weapon with distortion... once.",
236 "Lugonu is no longer ready to corrupt your weapon." },
237 },
238
239 // Beogh
240 { { 2, ABIL_BEOGH_SMITING, "smite your foes" },
241 { 3, "gain orcish followers" },
242 { 4, ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS, "recall your orcish followers" },
243 { 5, "walk on water" },
244 { 5, ABIL_BEOGH_GIFT_ITEM, "give items to your followers" },
245 { 6, ABIL_BEOGH_RESURRECTION, "revive fallen orcs" },
246 },
247
248 // Jiyva
249 { { 1, ABIL_JIYVA_CALL_JELLY, "request a jelly" },
250 { 3, "Jiyva will now mutate your body and modify your attributes as you gain piety.",
251 "Jiyva will no longer mutate your body and modify your attributes.",
252 "Jiyva will mutate your body and modify your attributes as you gain piety." },
253 { 3, "Jiyva is now protecting you from corrosive effects.",
254 "Jiyva will no longer protect you from corrosive effects.",
255 "Jiyva protects you from corrosive effects." },
256 { 4, ABIL_JIYVA_SLIMIFY, "turn your foes to slime" },
257 { 5, "You may now expel jellies when seriously injured.",
258 "You will no longer expel jellies when injured.",
259 "You may expel jellies when seriously injured." },
260 { 5, ABIL_JIYVA_CURE_BAD_MUTATION,
261 "call upon Jiyva to remove your harmful mutations" },
262 },
263
264 // Fedhas
265 {
266 { 2, ABIL_FEDHAS_WALL_OF_BRIARS, "encircle yourself with summoned briar patches"},
267 { 3, ABIL_FEDHAS_GROW_BALLISTOMYCETE, "grow a ballistomycete" },
268 { 4, ABIL_FEDHAS_OVERGROW, "transform dungeon walls and trees into plant allies"},
269 { 5, ABIL_FEDHAS_GROW_OKLOB, "grow an oklob plant" },
270 },
271
272 // Cheibriados
273 { { 0, ABIL_CHEIBRIADOS_TIME_BEND, "bend time to slow others" },
274 { 1, "Cheibriados is now slowing the effects of poison on you.",
275 "Cheibriados will no longer slow the effects of poison on you.",
276 "Cheibriados slows the effects of poison on you." },
277 { 3, ABIL_CHEIBRIADOS_DISTORTION, "warp the flow of time around you" },
278 { 4, ABIL_CHEIBRIADOS_SLOUCH, "inflict damage on those overly hasty" },
279 { 5, ABIL_CHEIBRIADOS_TIME_STEP, "step out of the flow of time" },
280 },
281
282 // Ashenzari
283 { { 0, "Ashenzari warns you of distant threats and treasures.\n"
284 "Ashenzari reveals the structure of the dungeon to you.\n"
285 "Ashenzari shows you where magical portals lie.\n"
286 "Ashenzari prevents you from stumbling into unseen traps.\n"
287 "Ashenzari identifies your possessions." },
288 { 2, "Ashenzari will now reveal the unseen.",
289 "Ashenzari will no longer reveal the unseen.",
290 "Ashenzari reveals the unseen." },
291 { 3, "Ashenzari will now keep your mind clear.",
292 "Ashenzari will no longer keep your mind clear.",
293 "Ashenzari keeps your mind clear." },
294 { 4, "Ashenzari will now grant you astral sight.",
295 "Ashenzari will no longer grant you astral sight.",
296 "Ashenzari grants you astral sight." },
297 },
298
299 // Dithmenos
300 { { 2, ABIL_DITHMENOS_SHADOW_STEP,
301 "step into the shadows of nearby creatures" },
302 { 3, "You will now sometimes bleed smoke when heavily injured by enemies.",
303 "You will no longer bleed smoke.",
304 "You sometimes bleed smoke when heavily injured by enemies." },
305 { 4, "Your shadow now sometimes tangibly mimics your actions.",
306 "Your shadow no longer tangibly mimics your actions.",
307 "Your shadow sometimes tangibly mimics your actions." },
308 { 5, ABIL_DITHMENOS_SHADOW_FORM,
309 "transform into a swirling mass of shadows" },
310 },
311
312 // Gozag
313 { { 0, ABIL_GOZAG_POTION_PETITION, "petition Gozag for potion effects" },
314 { 0, ABIL_GOZAG_CALL_MERCHANT,
315 "fund merchants seeking to open stores in the dungeon" },
316 { 0, ABIL_GOZAG_BRIBE_BRANCH,
317 "bribe branches to halt enemies' attacks and recruit allies" },
318 },
319
320 // Qazlal
321 {
322 { 0, "Qazlal grants you and your divine allies immunity to clouds." },
323 { 1, "You are now surrounded by a storm.",
324 "Your storm dissipates completely.",
325 "You are surrounded by a storm." },
326 { 2, ABIL_QAZLAL_UPHEAVAL, "call upon nature to destroy your foes" },
327 { 3, ABIL_QAZLAL_ELEMENTAL_FORCE, "give life to nearby clouds" },
328 { 4, "The storm surrounding you is now powerful enough to repel missiles.",
329 "The storm surrounding you is now too weak to repel missiles.",
330 "The storm surrounding you is powerful enough to repel missiles." },
331 { 4, "You will now adapt resistances upon receiving elemental damage.",
332 "You will no longer adapt resistances upon receiving elemental damage.",
333 "You adapt resistances upon receiving elemental damage." },
334 { 5, ABIL_QAZLAL_DISASTER_AREA,
335 "call upon nature's wrath in a wide area around you" },
336 },
337
338 // Ru
339 { { 1, "You now exude an aura of power that intimidates your foes.",
340 "You no longer exude an aura of power that intimidates your foes.",
341 "You now exude an aura of power that intimidates your foes." },
342 { 2, "Your aura of power can now strike those that harm you.",
343 "Your aura of power no longer strikes those that harm you.",
344 "Your aura of power can strike those that harm you." },
345 { 3, ABIL_RU_DRAW_OUT_POWER, "heal your body and restore your magic" },
346 { 4, ABIL_RU_POWER_LEAP, "gather your power into a mighty leap" },
347 { 5, ABIL_RU_APOCALYPSE, "wreak a terrible wrath on your foes" },
348 },
349
350 #if TAG_MAJOR_VERSION == 34
351 // Pakellas
352 {
353 { 0, "gain magical power from killing" },
354 },
355 #endif
356
357 // Uskayaw
358 {
359 { 1, ABIL_USKAYAW_STOMP, "stomp with the beat" },
360 { 2, ABIL_USKAYAW_LINE_PASS, "pass through a line of other dancers" },
361 { 3, "Uskayaw will force your foes to helplessly watch your dance.",
362 "Uskayaw will no longer force your foes to helplessly watch your dance."},
363 { 4, "Uskayaw will force your foes to share their pain.",
364 "Uskayaw will no longer force your foes to share their pain."},
365 { 5, ABIL_USKAYAW_GRAND_FINALE, "merge with and destroy a victim" },
366 },
367
368 // Hepliaklqana
369 { { 1, ABIL_HEPLIAKLQANA_RECALL, "recall your ancestor" },
370 { 1, ABIL_HEPLIAKLQANA_IDENTITY, "remember your ancestor's identity" },
371 { 3, ABIL_HEPLIAKLQANA_TRANSFERENCE, "swap creatures with your ancestor" },
372 { 4, ABIL_HEPLIAKLQANA_IDEALISE, "heal and protect your ancestor" },
373 { 5, "drain nearby creatures when transferring your ancestor"},
374 },
375
376 // Wu Jian
377 { { 0, "perform damaging attacks by moving towards foes",
378 "perform lunging strikes" },
379 { 1, "lightly attack monsters by moving around them",
380 "perform spinning attacks" },
381 { 2, ABIL_WU_JIAN_WALLJUMP,
382 "perform airborne attacks" },
383 { 3, ABIL_WU_JIAN_SERPENTS_LASH, "briefly move at supernatural speeds",
384 "move at supernatural speeds" },
385 { 5, ABIL_WU_JIAN_HEAVENLY_STORM,
386 "summon a storm of heavenly clouds to empower your attacks",
387 "summon a storm of heavenly clouds" },
388 },
389 };
390
get_god_powers(god_type god)391 vector<god_power> get_god_powers(god_type god)
392 {
393 vector<god_power> ret;
394 for (const auto& power : god_powers[god])
395 {
396 // hack :( don't show fake hp restore
397 if (god == GOD_VEHUMET && power.rank == 1
398 && you.has_mutation(MUT_HP_CASTING))
399 {
400 continue;
401 }
402 if (!(power.abil != ABIL_NON_ABILITY
403 && fixup_ability(power.abil) == ABIL_NON_ABILITY))
404 {
405 ret.push_back(power);
406 }
407 }
408 return ret;
409 }
410
411 /**
412 * Print a description of getting/losing this power.
413 *
414 * @param gaining If true, use this->gain; otherwise, use this->loss.
415 * @param fmt A string containing "%s" that will be used as a format
416 * string with our string as parameter; it is not used if
417 * our string begins with a capital letter. IF THIS DOES
418 * NOT CONTAIN "%s", OR CONTAINS OTHER FORMAT SPECIFIERS,
419 * BEHAVIOUR IS UNDEFINED.
420 * @return a string suitable for being read by the user.
421 */
display(bool gaining,const char * fmt) const422 void god_power::display(bool gaining, const char* fmt) const
423 {
424 // hack: don't mention the necronomicon alone unless it wasn't
425 // already mentioned by the other message
426 if (abil == ABIL_KIKU_GIFT_CAPSTONE_SPELLS
427 && !you.has_mutation(MUT_NO_GRASPING))
428 {
429 return;
430 }
431 const char* str = gaining ? gain : loss;
432 if (isupper(str[0]))
433 god_speaks(you.religion, str);
434 else
435 god_speaks(you.religion, make_stringf(fmt, str).c_str());
436 }
437
438 static void _place_delayed_monsters();
439
is_evil_god(god_type god)440 bool is_evil_god(god_type god)
441 {
442 return god == GOD_KIKUBAAQUDGHA
443 || god == GOD_MAKHLEB
444 || god == GOD_YREDELEMNUL
445 || god == GOD_BEOGH
446 || god == GOD_LUGONU
447 || god == GOD_DITHMENOS;
448 }
449
is_good_god(god_type god)450 bool is_good_god(god_type god)
451 {
452 return god == GOD_ZIN
453 || god == GOD_SHINING_ONE
454 || god == GOD_ELYVILON;
455 }
456
is_chaotic_god(god_type god)457 bool is_chaotic_god(god_type god)
458 {
459 return god == GOD_XOM
460 || god == GOD_MAKHLEB
461 || god == GOD_LUGONU
462 || god == GOD_JIYVA;
463 }
464
is_unknown_god(god_type god)465 bool is_unknown_god(god_type god)
466 {
467 return god == GOD_NAMELESS;
468 }
469
470 // Not appearing in new games, but still extant.
_is_disabled_god(god_type god)471 static bool _is_disabled_god(god_type god)
472 {
473 switch (god)
474 {
475 #if TAG_MAJOR_VERSION == 34
476 // Disabled, pending a rework.
477 case GOD_PAKELLAS:
478 return true;
479 #endif
480
481 default:
482 return false;
483 }
484 }
485
is_unavailable_god(god_type god)486 bool is_unavailable_god(god_type god)
487 {
488 if (_is_disabled_god(god))
489 return true;
490
491 if (god == GOD_JIYVA && jiyva_is_dead())
492 return true;
493
494 return false;
495 }
496
god_has_name(god_type god)497 bool god_has_name(god_type god)
498 {
499 return god != GOD_NO_GOD && god != GOD_NAMELESS;
500 }
501
random_god()502 god_type random_god()
503 {
504 god_type god;
505
506 do
507 {
508 god = static_cast<god_type>(random2(NUM_GODS - 1) + 1);
509 }
510 while (is_unavailable_god(god));
511
512 return god;
513 }
514
515
god_iterator()516 god_iterator::god_iterator() :
517 i(0) { } // might be ok to start with GOD_ZIN instead?
518
operator bool() const519 god_iterator::operator bool() const
520 {
521 return i < NUM_GODS;
522 }
523
operator *() const524 god_type god_iterator::operator*() const
525 {
526 if (i < NUM_GODS)
527 return (god_type)i;
528 else
529 return GOD_NO_GOD;
530 }
531
operator ->() const532 god_type god_iterator::operator->() const
533 {
534 return **this;
535 }
536
operator ++()537 god_iterator& god_iterator::operator++()
538 {
539 ++i;
540 return *this;
541 }
542
operator ++(int)543 god_iterator god_iterator::operator++(int)
544 {
545 god_iterator copy = *this;
546 ++(*this);
547 return copy;
548 }
549
550
active_penance(god_type god)551 bool active_penance(god_type god)
552 {
553 // Good gods only have active wrath when they hate your current god.
554 return player_under_penance(god)
555 && !is_unavailable_god(god)
556 && god != GOD_ASHENZARI
557 && god != GOD_GOZAG
558 && god != GOD_RU
559 && god != GOD_HEPLIAKLQANA
560 #if TAG_MAJOR_VERSION == 34
561 && god != GOD_PAKELLAS
562 #endif
563 && god != GOD_ELYVILON
564 && (god == you.religion && !is_good_god(god)
565 || god_hates_your_god(god, you.religion));
566 }
567
568 // True for gods whose wrath is passive and expires with XP gain.
xp_penance(god_type god)569 bool xp_penance(god_type god)
570 {
571 return player_under_penance(god)
572 && !is_unavailable_god(god)
573 && (god == GOD_ASHENZARI
574 || god == GOD_GOZAG
575 || god == GOD_HEPLIAKLQANA
576 #if TAG_MAJOR_VERSION == 34
577 || god == GOD_PAKELLAS
578 #endif
579 || god == GOD_ELYVILON)
580 && god_hates_your_god(god, you.religion);
581 }
582
dec_penance(god_type god,int val)583 void dec_penance(god_type god, int val)
584 {
585 if (val <= 0 || you.penance[god] <= 0)
586 return;
587
588 #ifdef DEBUG_PIETY
589 mprf(MSGCH_DIAGNOSTICS, "Decreasing penance by %d", val);
590 #endif
591 if (you.penance[god] <= val)
592 {
593 const bool had_halo = have_passive(passive_t::halo);
594 const bool had_umbra = have_passive(passive_t::umbra);
595
596 you.penance[god] = 0;
597
598 mark_milestone("god.mollify",
599 "mollified " + god_name(god) + ".");
600
601 const bool dead_jiyva = (god == GOD_JIYVA && jiyva_is_dead());
602
603 simple_god_message(
604 make_stringf(" seems mollified%s.",
605 dead_jiyva ? ", and vanishes" : "").c_str(),
606 god);
607
608 if (dead_jiyva)
609 add_daction(DACT_REMOVE_JIYVA_ALTARS);
610
611 take_note(Note(NOTE_MOLLIFY_GOD, god));
612
613 if (you_worship(god))
614 {
615 // Redraw piety display and, in case the best skill is Invocations,
616 // redraw the god title.
617 you.redraw_title = true;
618
619 // TSO's halo is once more available.
620 if (!had_halo && have_passive(passive_t::halo))
621 {
622 mprf(MSGCH_GOD, "Your divine halo returns!");
623 invalidate_agrid(true);
624 }
625 if (!had_umbra && have_passive(passive_t::umbra))
626 {
627 mprf(MSGCH_GOD, "Your aura of darkness returns!");
628 invalidate_agrid(true);
629 }
630 if (have_passive(passive_t::sinv))
631 {
632 mprf(MSGCH_GOD, "Your vision regains its divine sight.");
633 autotoggle_autopickup(false);
634 }
635 if (have_passive(passive_t::stat_boost))
636 {
637 simple_god_message(" restores the support of your attributes.");
638 redraw_screen();
639 update_screen();
640 notify_stat_change();
641 }
642 if (have_passive(passive_t::storm_shield))
643 {
644 mprf(MSGCH_GOD, "A storm instantly forms around you!");
645 you.redraw_armour_class = true; // also handles shields
646 }
647 // When you've worked through all your penance, you get
648 // another chance to make hostile slimes strict neutral.
649
650 if (have_passive(passive_t::neutral_slimes))
651 add_daction(DACT_SLIME_NEW_ATTEMPT);
652
653 if (have_passive(passive_t::friendly_plants)
654 && env.forest_awoken_until)
655 {
656 // XXX: add a dact here & on-join to handle offlevel
657 // awakened forests?
658 for (monster_iterator mi; mi; ++mi)
659 mi->del_ench(ENCH_AWAKEN_FOREST);
660 }
661 }
662 else
663 {
664 #if TAG_MAJOR_VERSION == 34
665 if (god == GOD_PAKELLAS)
666 {
667 // Penance just ended w/o worshipping Pakellas;
668 // notify the player that MP regeneration will start again.
669 mprf(MSGCH_GOD, god, "You begin regenerating magic.");
670 }
671 else
672 #endif
673 if (god == GOD_HEPLIAKLQANA)
674 {
675 calc_hp(); // frailty ends
676 mprf(MSGCH_GOD, god, "Your full life essence returns.");
677 }
678 }
679 }
680 else
681 {
682 you.penance[god] -= val;
683 return;
684 }
685
686 // We only get this far if we just mollified a god.
687 // If we just mollified a god, see if we have any angry gods left.
688 // If we don't, clear the stored wrath / XP counter.
689 god_iterator it;
690 for (; it; ++it)
691 {
692 if (active_penance(*it))
693 break;
694 }
695
696 if (it)
697 return;
698
699 you.attribute[ATTR_GOD_WRATH_COUNT] = 0;
700 you.attribute[ATTR_GOD_WRATH_XP] = 0;
701 }
702
dec_penance(int val)703 void dec_penance(int val)
704 {
705 dec_penance(you.religion, val);
706 }
707
708 // TODO: find out what this is duplicating & deduplicate it
_need_water_walking()709 static bool _need_water_walking()
710 {
711 return you.ground_level() && !you.has_mutation(MUT_MERTAIL)
712 && env.grid(you.pos()) == DNGN_DEEP_WATER;
713 }
714
_grant_temporary_waterwalk()715 static void _grant_temporary_waterwalk()
716 {
717 mprf("Your water-walking will last only until you reach solid ground.");
718 you.props[TEMP_WATERWALK_KEY] = true;
719 }
720
jiyva_is_dead()721 bool jiyva_is_dead()
722 {
723 return you.royal_jelly_dead
724 && !you_worship(GOD_JIYVA) && !you.penance[GOD_JIYVA];
725 }
726
set_penance_xp_timeout()727 void set_penance_xp_timeout()
728 {
729 if (you.attribute[ATTR_GOD_WRATH_XP] > 0)
730 return;
731
732 // TODO: make this more random?
733 you.attribute[ATTR_GOD_WRATH_XP] +=
734 max(div_rand_round(exp_needed(you.experience_level + 1)
735 - exp_needed(you.experience_level),
736 200),
737 1);
738 }
739
_inc_penance(god_type god,int val)740 static void _inc_penance(god_type god, int val)
741 {
742 if (val <= 0)
743 return;
744
745 if (!player_under_penance(god))
746 {
747 god_acting gdact(god, true);
748
749 take_note(Note(NOTE_PENANCE, god));
750
751 const bool had_halo = have_passive(passive_t::halo);
752 const bool had_umbra = have_passive(passive_t::umbra);
753
754 you.penance[god] += val;
755 you.penance[god] = min((uint8_t)MAX_PENANCE, you.penance[god]);
756
757 if (had_halo && !have_passive(passive_t::halo))
758 {
759 mprf(MSGCH_GOD, god, "Your divine halo fades away.");
760 invalidate_agrid();
761 }
762 if (had_umbra && !have_passive(passive_t::umbra))
763 {
764 mprf(MSGCH_GOD, god, "Your aura of darkness fades away.");
765 invalidate_agrid();
766 }
767
768 if (will_have_passive(passive_t::water_walk)
769 && _need_water_walking() && !have_passive(passive_t::water_walk))
770 {
771 _grant_temporary_waterwalk();
772 }
773
774 if (will_have_passive(passive_t::stat_boost))
775 {
776 redraw_screen();
777 update_screen();
778 notify_stat_change();
779 }
780
781 if (god == GOD_TROG)
782 {
783 if (you.duration[DUR_TROGS_HAND])
784 trog_remove_trogs_hand();
785
786 make_god_gifts_disappear();
787 }
788 else if (god == GOD_ZIN)
789 {
790 if (you.duration[DUR_DIVINE_STAMINA])
791 zin_remove_divine_stamina();
792 if (env.sanctuary_time)
793 remove_sanctuary();
794 }
795 else if (god == GOD_SHINING_ONE)
796 {
797 if (you.duration[DUR_DIVINE_SHIELD])
798 tso_remove_divine_shield();
799
800 make_god_gifts_disappear();
801 }
802 else if (god == GOD_ELYVILON)
803 {
804 if (you.duration[DUR_DIVINE_VIGOUR])
805 elyvilon_remove_divine_vigour();
806 }
807 else if (god == GOD_JIYVA)
808 {
809 if (you.duration[DUR_SLIMIFY])
810 you.duration[DUR_SLIMIFY] = 0;
811 }
812 else if (god == GOD_QAZLAL)
813 {
814 // Can't use have_passive(passive_t::storm_shield) because we
815 // just gained penance.
816 if (you.piety >= piety_breakpoint(0))
817 {
818 mprf(MSGCH_GOD, god, "The storm surrounding you dissipates.");
819 you.redraw_armour_class = true;
820 }
821 if (you.duration[DUR_QAZLAL_FIRE_RES])
822 {
823 mprf(MSGCH_DURATION, "Your resistance to fire fades away.");
824 you.duration[DUR_QAZLAL_FIRE_RES] = 0;
825 }
826 if (you.duration[DUR_QAZLAL_COLD_RES])
827 {
828 mprf(MSGCH_DURATION, "Your resistance to cold fades away.");
829 you.duration[DUR_QAZLAL_COLD_RES] = 0;
830 }
831 if (you.duration[DUR_QAZLAL_ELEC_RES])
832 {
833 mprf(MSGCH_DURATION,
834 "Your resistance to electricity fades away.");
835 you.duration[DUR_QAZLAL_ELEC_RES] = 0;
836 }
837 if (you.duration[DUR_QAZLAL_AC])
838 {
839 mprf(MSGCH_DURATION,
840 "Your resistance to physical damage fades away.");
841 you.duration[DUR_QAZLAL_AC] = 0;
842 you.redraw_armour_class = true;
843 }
844 }
845 else if (god == GOD_SIF_MUNA)
846 {
847 if (you.duration[DUR_CHANNEL_ENERGY])
848 you.duration[DUR_CHANNEL_ENERGY] = 0;
849 #if TAG_MAJOR_VERSION == 34
850 if (you.attribute[ATTR_DIVINE_ENERGY])
851 you.attribute[ATTR_DIVINE_ENERGY] = 0;
852 #endif
853 }
854 else if (god == GOD_OKAWARU)
855 {
856 if (you.duration[DUR_HEROISM])
857 okawaru_remove_heroism();
858 if (you.duration[DUR_FINESSE])
859 okawaru_remove_finesse();
860 }
861
862 if (you_worship(god))
863 {
864 // Redraw piety display and, in case the best skill is Invocations,
865 // redraw the god title.
866 you.redraw_title = true;
867 }
868 }
869 else
870 {
871 you.penance[god] += val;
872 you.penance[god] = min((uint8_t)MAX_PENANCE, you.penance[god]);
873 }
874
875 set_penance_xp_timeout();
876 }
877
_inc_penance(int val)878 static void _inc_penance(int val)
879 {
880 _inc_penance(you.religion, val);
881 }
882
_set_penance(god_type god,int val)883 static void _set_penance(god_type god, int val)
884 {
885 you.penance[god] = val;
886 }
887
_set_wrath_penance(god_type god)888 static void _set_wrath_penance(god_type god)
889 {
890 _set_penance(god, initial_wrath_penance_for(god));
891 }
892
_inc_gift_timeout(int val)893 static void _inc_gift_timeout(int val)
894 {
895 if (200 - you.gift_timeout < val)
896 you.gift_timeout = 200;
897 else
898 you.gift_timeout += val;
899 }
900
901 // These are sorted in order of power.
902 static monster_type _yred_servants[] =
903 {
904 MONS_MUMMY, MONS_WIGHT, MONS_FLYING_SKULL, MONS_WRAITH,
905 MONS_VAMPIRE, MONS_PHANTASMAL_WARRIOR, MONS_SKELETAL_WARRIOR,
906 MONS_FLAYED_GHOST, MONS_VAMPIRE_KNIGHT, MONS_GHOUL, MONS_BONE_DRAGON,
907 MONS_PROFANE_SERVITOR
908 };
909
910 #define MIN_YRED_SERVANT_THRESHOLD 3
911 #define MAX_YRED_SERVANT_THRESHOLD ARRAYSZ(_yred_servants)
912
_yred_high_level_servant(monster_type type)913 static bool _yred_high_level_servant(monster_type type)
914 {
915 return type == MONS_BONE_DRAGON
916 || type == MONS_PROFANE_SERVITOR;
917 }
918
yred_random_servants(unsigned int threshold,bool force_hostile)919 int yred_random_servants(unsigned int threshold, bool force_hostile)
920 {
921 if (threshold == 0)
922 {
923 if (force_hostile)
924 {
925 // This implies wrath - scale the threshold with XL.
926 threshold =
927 MIN_YRED_SERVANT_THRESHOLD
928 + (MAX_YRED_SERVANT_THRESHOLD - MIN_YRED_SERVANT_THRESHOLD)
929 * you.experience_level / 27;
930 }
931 else
932 threshold = ARRAYSZ(_yred_servants);
933 }
934 else
935 {
936 threshold = min(static_cast<unsigned int>(ARRAYSZ(_yred_servants)),
937 threshold);
938 }
939
940 const unsigned int servant = random2(threshold);
941
942 // Skip some of the weakest servants, once the threshold is high.
943 if ((servant + 2) * 2 < threshold)
944 return -1;
945
946 monster_type mon_type = _yred_servants[servant];
947
948 // Cap some of the strongest servants.
949 if (!force_hostile && _yred_high_level_servant(mon_type))
950 {
951 int current_high_level = 0;
952 for (auto &entry : companion_list)
953 {
954 monster* mons = monster_by_mid(entry.first);
955 if (!mons)
956 mons = &entry.second.mons.mons;
957 if (_yred_high_level_servant(mons->type))
958 current_high_level++;
959 }
960
961 if (current_high_level >= 3)
962 return -1;
963 }
964
965 int how_many = (mon_type == MONS_FLYING_SKULL) ? 2 + random2(4)
966 : 1;
967
968 mgen_data mg(mon_type, !force_hostile ? BEH_FRIENDLY : BEH_HOSTILE,
969 you.pos(), MHITYOU);
970 mg.set_summoned(!force_hostile ? &you : 0, 0, 0, GOD_YREDELEMNUL);
971
972 if (force_hostile)
973 mg.non_actor_summoner = "the anger of Yredelemnul";
974
975 int created = 0;
976 if (force_hostile)
977 {
978 mg.extra_flags |= (MF_NO_REWARD | MF_HARD_RESET);
979
980 for (; how_many > 0; --how_many)
981 {
982 if (create_monster(mg))
983 created++;
984 }
985 }
986 else
987 {
988 for (; how_many > 0; --how_many)
989 delayed_monster(mg);
990 }
991
992 return created;
993 }
994
_want_missile_gift()995 static bool _want_missile_gift()
996 {
997 skill_type sk = best_skill(SK_SLINGS, SK_THROWING);
998 // Default to throwing if all missile skills are at zero.
999 if (you.skills[sk] == 0)
1000 sk = SK_THROWING;
1001 return you.piety >= piety_breakpoint(2)
1002 && random2(you.piety) > 70
1003 && one_chance_in(8)
1004 && x_chance_in_y(1 + you.skills[sk], 12);
1005 }
1006
_want_nemelex_gift()1007 static bool _want_nemelex_gift()
1008 {
1009 if (you.piety < piety_breakpoint(0))
1010 return false;
1011 const int piety_over_one_star = you.piety - piety_breakpoint(0);
1012
1013 // Nemelex will give at least one gift early.
1014 if (!you.num_total_gifts[GOD_NEMELEX_XOBEH]
1015 && x_chance_in_y(piety_over_one_star + 1, piety_breakpoint(1)))
1016 {
1017 return true;
1018 }
1019
1020 return one_chance_in(3) && x_chance_in_y(piety_over_one_star + 1, MAX_PIETY);
1021 }
1022
_give_nemelex_gift(bool forced=false)1023 static bool _give_nemelex_gift(bool forced = false)
1024 {
1025 if (!forced && !_want_nemelex_gift())
1026 return false;
1027
1028 if (gift_cards())
1029 {
1030 simple_god_message(" deals you some cards!");
1031 mprf(MSGCH_GOD, "You now have %s.", deck_summary().c_str());
1032 }
1033 else
1034 simple_god_message(" goes to deal, but finds you have enough cards.");
1035 _inc_gift_timeout(5 + random2avg(9, 2));
1036 you.num_current_gifts[you.religion]++;
1037 you.num_total_gifts[you.religion]++;
1038 take_note(Note(NOTE_GOD_GIFT, you.religion));
1039 return true;
1040 }
1041
1042 #if TAG_MAJOR_VERSION == 34
1043 /**
1044 * From the given list of items, return a random unseen item, if there are any.
1045 * Otherwise, just return any of them at random.
1046 *
1047 * If we cared, we could make this a template function to return more specific
1048 * types than 'int'. (That's probably not important, though.)
1049 *
1050 * @param item_types A list of item types to choose from.
1051 * @param seen_func How to tell whether the item was seen.
1052 * @return A random item type; e.g. WAND_ACID.
1053 */
_preferably_unseen_item(const vector<int> & item_types,function<bool (int)> seen_func)1054 static int _preferably_unseen_item(const vector<int> &item_types,
1055 function<bool(int)> seen_func)
1056 {
1057 ASSERT(item_types.size());
1058 vector<int> unseen;
1059 for (auto item : item_types)
1060 if (!seen_func(item))
1061 unseen.emplace_back(item);
1062
1063 if (unseen.size())
1064 return unseen[random2(unseen.size())];
1065 return item_types[random2(item_types.size())];
1066 }
1067 #endif
1068
_delayed_gift_callback(const mgen_data &,monster * & mon,int placed)1069 static void _delayed_gift_callback(const mgen_data &/*mg*/, monster *&mon,
1070 int placed)
1071 {
1072 if (placed <= 0)
1073 return;
1074 ASSERT(mon);
1075
1076 // Make sure monsters are shown.
1077 viewwindow();
1078 update_screen();
1079 more();
1080 _inc_gift_timeout(4 + random2avg(7, 2));
1081 you.num_current_gifts[you.religion]++;
1082 you.num_total_gifts[you.religion]++;
1083 string gift;
1084 if (placed == 1)
1085 gift = mon->name(DESC_A);
1086 else
1087 {
1088 gift = make_stringf("%d %s", placed,
1089 pluralise(mon->name(DESC_PLAIN)).c_str());
1090 }
1091
1092 take_note(Note(NOTE_GOD_GIFT, you.religion, 0, gift));
1093 }
1094
_jiyva_mutate()1095 static bool _jiyva_mutate()
1096 {
1097 simple_god_message(" alters your body.");
1098
1099 const int rand = random2(100);
1100
1101 if (rand < 5)
1102 return delete_mutation(RANDOM_SLIME_MUTATION, "Jiyva's grace", true, false, true);
1103 else if (rand < 30)
1104 return delete_mutation(RANDOM_NON_SLIME_MUTATION, "Jiyva's grace", true, false, true);
1105 else if (rand < 55)
1106 return mutate(RANDOM_MUTATION, "Jiyva's grace", true, false, true);
1107 else if (rand < 75)
1108 return mutate(RANDOM_SLIME_MUTATION, "Jiyva's grace", true, false, true);
1109 else
1110 return mutate(RANDOM_GOOD_MUTATION, "Jiyva's grace", true, false, true);
1111 }
1112
vehumet_is_offering(spell_type spell)1113 bool vehumet_is_offering(spell_type spell)
1114 {
1115 return you.vehumet_gifts.count(spell);
1116 }
1117
vehumet_accept_gift(spell_type spell)1118 void vehumet_accept_gift(spell_type spell)
1119 {
1120 if (vehumet_is_offering(spell))
1121 {
1122 you.vehumet_gifts.erase(spell);
1123 you.duration[DUR_VEHUMET_GIFT] = 0;
1124 }
1125 }
1126
_add_to_old_gifts(spell_type spell)1127 static void _add_to_old_gifts(spell_type spell)
1128 {
1129 you.old_vehumet_gifts.insert(spell);
1130 }
1131
_is_old_gift(spell_type spell)1132 static bool _is_old_gift(spell_type spell)
1133 {
1134 return you.old_vehumet_gifts.count(spell);
1135 }
1136
_vehumet_eligible_gift_spells(set<spell_type> excluded_spells)1137 static set<spell_type> _vehumet_eligible_gift_spells(set<spell_type> excluded_spells)
1138 {
1139 set<spell_type> eligible_spells;
1140
1141 const int gifts = you.num_total_gifts[you.religion];
1142 if (gifts >= NUM_VEHUMET_GIFTS)
1143 return eligible_spells;
1144
1145 const int min_lev[] = {1,1,2,3,3,4,4,5,5,5,5,6,8};
1146 const int max_lev[] = {1,2,3,4,5,7,7,7,7,7,7,8,9};
1147 COMPILE_CHECK(ARRAYSZ(min_lev) == NUM_VEHUMET_GIFTS);
1148 COMPILE_CHECK(ARRAYSZ(max_lev) == NUM_VEHUMET_GIFTS);
1149 int min_level = min_lev[gifts];
1150 int max_level = max_lev[gifts];
1151
1152 if (min_level > you.experience_level)
1153 return eligible_spells;
1154
1155 set<spell_type> backup_spells;
1156 for (int i = 0; i < NUM_SPELLS; ++i)
1157 {
1158 spell_type spell = static_cast<spell_type>(i);
1159 if (!is_valid_spell(spell))
1160 continue;
1161
1162 if (excluded_spells.count(spell))
1163 continue;
1164
1165 if (vehumet_supports_spell(spell)
1166 && !you.has_spell(spell)
1167 && !you.spell_library[spell]
1168 && is_player_book_spell(spell)
1169 && spell_difficulty(spell) <= max_level
1170 && spell_difficulty(spell) >= min_level)
1171 {
1172 if (!_is_old_gift(spell))
1173 eligible_spells.insert(spell);
1174 else
1175 backup_spells.insert(spell);
1176 }
1177 }
1178 // Don't get stuck just because all spells have been seen/offered.
1179 if (eligible_spells.empty())
1180 {
1181 if (backup_spells.empty())
1182 {
1183 // This is quite improbable to happen, but in this case just
1184 // skip the gift and increment the gift counter.
1185 if (gifts <= 12)
1186 {
1187 you.num_current_gifts[you.religion]++;
1188 you.num_total_gifts[you.religion]++;
1189 }
1190 }
1191 return backup_spells;
1192 }
1193 return eligible_spells;
1194 }
1195
_vehumet_weighting(spell_type spell)1196 static int _vehumet_weighting(spell_type spell)
1197 {
1198 int bias = 100 + elemental_preference(spell, 10);
1199 return bias;
1200 }
1201
_vehumet_find_spell_gift(set<spell_type> excluded_spells)1202 static spell_type _vehumet_find_spell_gift(set<spell_type> excluded_spells)
1203 {
1204 set<spell_type> eligible_spells = _vehumet_eligible_gift_spells(excluded_spells);
1205 spell_type spell = SPELL_NO_SPELL;
1206 int total_weight = 0;
1207 int this_weight = 0;
1208 for (auto elig : eligible_spells)
1209 {
1210 this_weight = _vehumet_weighting(elig);
1211 total_weight += this_weight;
1212 if (x_chance_in_y(this_weight, total_weight))
1213 spell = elig;
1214 }
1215 return spell;
1216 }
1217
_vehumet_get_spell_gifts()1218 static set<spell_type> _vehumet_get_spell_gifts()
1219 {
1220 set<spell_type> offers;
1221 unsigned int num_offers = you.num_total_gifts[you.religion] == 12 ? 3 : 1;
1222 while (offers.size() < num_offers)
1223 {
1224 spell_type offer = _vehumet_find_spell_gift(offers);
1225 if (offer == SPELL_NO_SPELL)
1226 break;
1227 offers.insert(offer);
1228 }
1229 return offers;
1230 }
1231
1232 #if TAG_MAJOR_VERSION == 34
1233 /// Has the player ID'd the given type of wand?
_seen_wand(int wand)1234 static bool _seen_wand(int wand)
1235 {
1236 return get_ident_type(OBJ_WANDS, wand);
1237 }
1238
_pakellas_low_wand()1239 static int _pakellas_low_wand()
1240 {
1241 static const vector<int> low_wands = {
1242 WAND_FLAME,
1243 WAND_POLYMORPH,
1244 };
1245
1246 return _preferably_unseen_item(low_wands, _seen_wand);
1247 }
1248
_pakellas_high_wand()1249 static int _pakellas_high_wand()
1250 {
1251 vector<int> high_wands = {
1252 WAND_PARALYSIS,
1253 WAND_ICEBLAST,
1254 WAND_ACID,
1255 };
1256 if (!you.get_mutation_level(MUT_NO_LOVE))
1257 high_wands.emplace_back(WAND_CHARMING);
1258
1259 return _preferably_unseen_item(high_wands, _seen_wand);
1260 }
1261
_pakellas_low_misc()1262 static int _pakellas_low_misc()
1263 {
1264 // Limited uses, so any of these are fine even if they've been seen before.
1265 return random_choose(MISC_BOX_OF_BEASTS,
1266 MISC_PHANTOM_MIRROR);
1267 }
1268
_pakellas_high_misc()1269 static int _pakellas_high_misc()
1270 {
1271 static const vector<int> high_miscs = {
1272 MISC_PHIAL_OF_FLOODS,
1273 MISC_LIGHTNING_ROD,
1274 };
1275
1276 return _preferably_unseen_item(high_miscs, [](int misc) {
1277 return you.seen_misc[misc];
1278 });
1279 }
1280
_give_pakellas_gift()1281 static bool _give_pakellas_gift()
1282 {
1283 // Break early if giving a gift now means it would be lost.
1284 if (feat_eliminates_items(env.grid(you.pos())))
1285 return false;
1286
1287 bool success = false;
1288 object_class_type basetype = OBJ_UNASSIGNED;
1289 int subtype = -1;
1290
1291 if (you.piety >= piety_breakpoint(0)
1292 && you.num_total_gifts[GOD_PAKELLAS] == 0)
1293 {
1294 basetype = OBJ_WANDS;
1295 subtype = _pakellas_low_wand();
1296 }
1297 else if (you.piety >= piety_breakpoint(1)
1298 && you.num_total_gifts[GOD_PAKELLAS] == 1)
1299 {
1300 // All the evoker options here are summon-based, so give another
1301 // low-level wand instead under Sacrifice Love.
1302 if (you.get_mutation_level(MUT_NO_LOVE))
1303 {
1304 basetype = OBJ_WANDS;
1305 subtype = _pakellas_low_wand();
1306 }
1307 else
1308 {
1309 basetype = OBJ_MISCELLANY;
1310 subtype = _pakellas_low_misc();
1311 }
1312 }
1313 else if (you.piety >= piety_breakpoint(2)
1314 && you.num_total_gifts[GOD_PAKELLAS] == 2)
1315 {
1316 basetype = OBJ_WANDS;
1317 subtype = _pakellas_high_wand();
1318 }
1319 else if (you.piety >= piety_breakpoint(3)
1320 && you.num_total_gifts[GOD_PAKELLAS] == 3)
1321 {
1322 basetype = OBJ_MISCELLANY;
1323 subtype = _pakellas_high_misc();
1324 }
1325 else if (you.piety >= piety_breakpoint(4)
1326 && you.num_total_gifts[GOD_PAKELLAS] == 4)
1327 {
1328 basetype = random_choose(OBJ_WANDS, OBJ_MISCELLANY);
1329 subtype = (basetype == OBJ_WANDS) ? _pakellas_high_wand()
1330 : _pakellas_high_misc();
1331 }
1332
1333 if (basetype == OBJ_UNASSIGNED)
1334 return false;
1335 else
1336 {
1337 ASSERT(subtype >= 0);
1338 int thing_created = items(true, basetype, subtype, 1, 0,
1339 you.religion);
1340
1341 if (thing_created == NON_ITEM)
1342 return false;
1343
1344 move_item_to_grid(&thing_created, you.pos(), true);
1345
1346 if (thing_created != NON_ITEM)
1347 success = true;
1348 }
1349
1350 if (success)
1351 {
1352 simple_god_message(" grants you a gift!");
1353 // included in default force_more_message
1354
1355 you.num_current_gifts[you.religion]++;
1356 you.num_total_gifts[you.religion]++;
1357 take_note(Note(NOTE_GOD_GIFT, you.religion));
1358
1359 return true;
1360 }
1361
1362 return false;
1363 }
1364 #endif
1365
_give_trog_oka_gift(bool forced)1366 static bool _give_trog_oka_gift(bool forced)
1367 {
1368 // Break early if giving a gift now means it would be lost.
1369 if (feat_eliminates_items(env.grid(you.pos())))
1370 return false;
1371
1372 // No use for anything below. (No guarantees this will work right if these
1373 // mutations can ever appear separately.)
1374 if (you.has_mutation(MUT_NO_GRASPING) && you.has_mutation(MUT_NO_ARMOUR))
1375 return false;
1376
1377 const bool want_equipment = forced
1378 || (you.piety >= piety_breakpoint(4)
1379 && random2(you.piety) > 120
1380 && one_chance_in(4));
1381 // Oka can gift missiles, but if equipment is successful, we choose
1382 // equipment unless the gift was forced by wizard mode. In that case,
1383 // missiles, weapons, and armour all get equal weight below.
1384 const bool want_missiles = you_worship(GOD_OKAWARU)
1385 && (forced
1386 || !want_equipment && _want_missile_gift());
1387 object_class_type gift_type;
1388
1389 if (you_worship(GOD_TROG) && want_equipment)
1390 gift_type = OBJ_WEAPONS;
1391 else if (you_worship(GOD_OKAWARU) && (want_equipment || want_missiles))
1392 {
1393 gift_type = random_choose_weighted(
1394 want_equipment, OBJ_WEAPONS,
1395 want_equipment, OBJ_ARMOUR,
1396 want_missiles, OBJ_MISSILES);
1397 }
1398 else
1399 return false;
1400
1401 switch (gift_type)
1402 {
1403 case OBJ_MISSILES:
1404 simple_god_message(" grants you ammunition!");
1405 break;
1406 case OBJ_WEAPONS:
1407 simple_god_message(" grants you a weapon!");
1408 break;
1409 case OBJ_ARMOUR:
1410 simple_god_message(" grants you armour!");
1411 break;
1412 default:
1413 simple_god_message(" grants you bugs!");
1414 break;
1415 }
1416
1417 const bool success =
1418 acquirement_create_item(gift_type, you.religion,
1419 false, you.pos()) != NON_ITEM;
1420 if (!success)
1421 {
1422 mpr("...but nothing appears.");
1423 return false;
1424 }
1425 switch (gift_type)
1426 {
1427 case OBJ_MISSILES:
1428 _inc_gift_timeout(4 + roll_dice(2, 4));
1429 break;
1430 case OBJ_ARMOUR:
1431 if (you_worship(GOD_OKAWARU) && gift_type == OBJ_ARMOUR)
1432 _inc_gift_timeout(30 + random2avg(15, 2));
1433 // intentionally fallthrough to OBJ_WEAPONS
1434 case OBJ_WEAPONS:
1435 _inc_gift_timeout(30 + random2avg(19, 2));
1436 break;
1437 default:
1438 break;
1439 }
1440 you.num_current_gifts[you.religion]++;
1441 you.num_total_gifts[you.religion]++;
1442 take_note(Note(NOTE_GOD_GIFT, you.religion));
1443 return true;
1444 }
1445
_give_yred_gift(bool forced)1446 static bool _give_yred_gift(bool forced)
1447 {
1448 bool success = false;
1449 if (forced || (random2(you.piety) >= piety_breakpoint(2)
1450 && one_chance_in(4)))
1451 {
1452 unsigned int threshold = MIN_YRED_SERVANT_THRESHOLD
1453 + you.num_current_gifts[you.religion] / 2;
1454 threshold = max(threshold,
1455 static_cast<unsigned int>(MIN_YRED_SERVANT_THRESHOLD));
1456 threshold = min(threshold,
1457 static_cast<unsigned int>(MAX_YRED_SERVANT_THRESHOLD));
1458
1459 if (yred_random_servants(threshold) != -1)
1460 {
1461 delayed_monster_done(" grants you @servant@!",
1462 _delayed_gift_callback);
1463 success = true;
1464 }
1465 }
1466 return success;
1467 }
1468
_gift_jiyva_gift(bool forced)1469 static bool _gift_jiyva_gift(bool forced)
1470 {
1471 if (forced || you.piety >= piety_breakpoint(2)
1472 && random2(you.piety) > 50
1473 && one_chance_in(4) && !you.gift_timeout
1474 && you.can_safely_mutate())
1475 {
1476 if (_jiyva_mutate())
1477 {
1478 _inc_gift_timeout(15 + roll_dice(2, 4));
1479 you.num_current_gifts[you.religion]++;
1480 you.num_total_gifts[you.religion]++;
1481 return true;
1482 }
1483 else
1484 mpr("You feel as though nothing has changed.");
1485 }
1486 return false;
1487 }
1488
_handle_uskayaw_ability_unlocks()1489 static bool _handle_uskayaw_ability_unlocks()
1490 {
1491 bool success = false;
1492 // Uskayaw's triggered abilities trigger if you set the timer to -1.
1493 // We do this so that we trigger at the end of the round instead of
1494 // at the time we deal damage.
1495 if (you.piety == piety_breakpoint(2)
1496 && you.props[USKAYAW_AUDIENCE_TIMER].get_int() == 0)
1497 {
1498 you.props[USKAYAW_AUDIENCE_TIMER] = -1;
1499 success = true;
1500 }
1501 else if (you.piety == piety_breakpoint(3)
1502 && you.props[USKAYAW_BOND_TIMER].get_int() == 0)
1503 {
1504 you.props[USKAYAW_BOND_TIMER] = -1;
1505 success = true;
1506 }
1507 return success;
1508 }
1509
_give_sif_gift(bool forced)1510 static bool _give_sif_gift(bool forced)
1511 {
1512 // Smokeless fire and books don't get along.
1513 if (you.has_mutation(MUT_INNATE_CASTER))
1514 return false;
1515
1516 // Break early if giving a gift now means it would be lost.
1517 if (feat_eliminates_items(env.grid(you.pos())))
1518 return false;
1519
1520 if (!forced && (you.piety < piety_breakpoint(4)
1521 || random2(you.piety) < 101 || coinflip()))
1522 {
1523 return false;
1524 }
1525
1526 // Sif Muna special: Keep quiet if acquirement fails
1527 // because the player already has seen all spells.
1528 int item_index = acquirement_create_item(OBJ_BOOKS, you.religion,
1529 true, you.pos());
1530 if (item_index == NON_ITEM)
1531 return false;
1532
1533 simple_god_message(" grants you a gift!");
1534 // included in default force_more_message
1535
1536 you.num_current_gifts[you.religion]++;
1537 you.num_total_gifts[you.religion]++;
1538 const int n_spells = spells_in_book(env.item[item_index]).size();
1539 _inc_gift_timeout(10 + n_spells * 6 + random2avg(19, 2));
1540 take_note(Note(NOTE_GOD_GIFT, you.religion));
1541
1542 return true;
1543 }
1544
_give_kiku_gift(bool forced)1545 static bool _give_kiku_gift(bool forced)
1546 {
1547 // Djinn can't receive spell gifts.
1548 if (you.has_mutation(MUT_INNATE_CASTER))
1549 return false;
1550
1551 const bool first_gift = !you.num_total_gifts[you.religion];
1552
1553 // Kikubaaqudgha gives two sets of spells in a quick succession.
1554 if (!forced && (you.piety < piety_breakpoint(0)
1555 || !first_gift && you.piety < piety_breakpoint(2)
1556 || you.num_total_gifts[you.religion] > 1))
1557 {
1558 return false;
1559 }
1560
1561 vector<spell_type> chosen_spells;
1562
1563 // Each set should guarantee the player at least one corpse-using spell, to
1564 // complement Receive Corpses.
1565 if (first_gift)
1566 {
1567 chosen_spells.push_back(SPELL_PAIN);
1568 if (you.can_bleed(false))
1569 {
1570 chosen_spells.push_back(SPELL_SUBLIMATION_OF_BLOOD);
1571 chosen_spells.push_back(random_choose(SPELL_CORPSE_ROT,
1572 SPELL_ANIMATE_SKELETON));
1573 }
1574 else
1575 {
1576 chosen_spells.push_back(SPELL_CORPSE_ROT);
1577 chosen_spells.push_back(SPELL_ANIMATE_SKELETON);
1578 }
1579 chosen_spells.push_back(SPELL_VAMPIRIC_DRAINING);
1580 }
1581 else
1582 {
1583 chosen_spells.push_back(random_choose(SPELL_ANIMATE_DEAD,
1584 SPELL_SIMULACRUM));
1585 chosen_spells.push_back((you.has_mutation(MUT_NO_GRASPING)
1586 || coinflip()) ? SPELL_BORGNJORS_VILE_CLUTCH
1587 : SPELL_EXCRUCIATING_WOUNDS);
1588 chosen_spells.push_back(random_choose(SPELL_AGONY,
1589 SPELL_DEATH_CHANNEL));
1590
1591 spell_type extra_spell;
1592 do
1593 {
1594 extra_spell = random_choose(SPELL_ANIMATE_DEAD,
1595 SPELL_AGONY,
1596 SPELL_BORGNJORS_VILE_CLUTCH,
1597 SPELL_EXCRUCIATING_WOUNDS,
1598 SPELL_SIMULACRUM,
1599 SPELL_DEATH_CHANNEL);
1600 if (you.has_mutation(MUT_NO_GRASPING)
1601 && extra_spell == SPELL_EXCRUCIATING_WOUNDS)
1602 {
1603 extra_spell = SPELL_NO_SPELL;
1604 }
1605
1606 if (find(begin(chosen_spells), end(chosen_spells), extra_spell)
1607 != end(chosen_spells))
1608 {
1609 extra_spell = SPELL_NO_SPELL;
1610 }
1611 }
1612 while (extra_spell == SPELL_NO_SPELL);
1613
1614 chosen_spells.push_back(extra_spell);
1615 chosen_spells.push_back(SPELL_DISPEL_UNDEAD);
1616 }
1617
1618 simple_god_message(" grants you a gift!");
1619 // included in default force_more_message
1620 library_add_spells(chosen_spells);
1621
1622 you.num_current_gifts[you.religion]++;
1623 you.num_total_gifts[you.religion]++;
1624 take_note(Note(NOTE_GOD_GIFT, you.religion));
1625
1626 return true;
1627 }
1628
_handle_veh_gift(bool forced)1629 static bool _handle_veh_gift(bool forced)
1630 {
1631 bool success = false;
1632 const int gifts = you.num_total_gifts[you.religion];
1633 if (forced || !you.duration[DUR_VEHUMET_GIFT]
1634 && !you.has_mutation(MUT_INNATE_CASTER)
1635 && (you.piety >= piety_breakpoint(0) && gifts == 0
1636 || you.piety >= piety_breakpoint(0) + random2(6) + 18 * gifts && gifts <= 5
1637 || you.piety >= piety_breakpoint(4) && gifts <= 11 && one_chance_in(20)
1638 || you.piety >= piety_breakpoint(5) && gifts <= 12 && one_chance_in(20)))
1639 {
1640 set<spell_type> offers = _vehumet_get_spell_gifts();
1641 if (!offers.empty())
1642 {
1643 you.vehumet_gifts = offers;
1644 string prompt = " offers you knowledge of ";
1645 for (auto it = offers.begin(); it != offers.end(); ++it)
1646 {
1647 if (it != offers.begin())
1648 {
1649 if (offers.size() > 2)
1650 prompt += ",";
1651 prompt += " ";
1652 auto next = it;
1653 next++;
1654 if (next == offers.end())
1655 prompt += "and ";
1656 }
1657 prompt += spell_title(*it);
1658 _add_to_old_gifts(*it);
1659 take_note(Note(NOTE_OFFERED_SPELL, *it));
1660 }
1661 prompt += ".";
1662 if (gifts >= NUM_VEHUMET_GIFTS - 1)
1663 {
1664 prompt += " These spells will remain available"
1665 " as long as you worship Vehumet.";
1666 }
1667
1668 you.duration[DUR_VEHUMET_GIFT] = (100 + random2avg(100, 2)) * BASELINE_DELAY;
1669 if (gifts >= 5)
1670 _inc_gift_timeout(30 + random2avg(30, 2));
1671 you.num_current_gifts[you.religion]++;
1672 you.num_total_gifts[you.religion]++;
1673
1674 simple_god_message(prompt.c_str());
1675 // included in default force_more_message
1676
1677 success = true;
1678 }
1679 }
1680 return success;
1681 }
1682
mons_make_god_gift(monster & mon,god_type god)1683 void mons_make_god_gift(monster& mon, god_type god)
1684 {
1685 const god_type acting_god =
1686 (crawl_state.is_god_acting()) ? crawl_state.which_god_acting()
1687 : GOD_NO_GOD;
1688
1689 if (god == GOD_NO_GOD && acting_god == GOD_NO_GOD)
1690 return;
1691
1692 if (god == GOD_NO_GOD)
1693 god = acting_god;
1694
1695 if (mon.flags & MF_GOD_GIFT)
1696 {
1697 dprf("Monster '%s' was already a gift of god '%s', now god '%s'.",
1698 mon.name(DESC_PLAIN, true).c_str(),
1699 god_name(mon.god).c_str(),
1700 god_name(god).c_str());
1701 }
1702
1703 mon.god = god;
1704 mon.flags |= MF_GOD_GIFT;
1705 }
1706
mons_is_god_gift(const monster & mon,god_type god)1707 bool mons_is_god_gift(const monster& mon, god_type god)
1708 {
1709 return (mon.flags & MF_GOD_GIFT) && mon.god == god;
1710 }
1711
is_yred_undead_slave(const monster & mon)1712 bool is_yred_undead_slave(const monster& mon)
1713 {
1714 return mon.alive() && mon.holiness() & MH_UNDEAD
1715 && mon.attitude == ATT_FRIENDLY
1716 && mons_is_god_gift(mon, GOD_YREDELEMNUL);
1717 }
1718
is_orcish_follower(const monster & mon)1719 bool is_orcish_follower(const monster& mon)
1720 {
1721 return mon.alive() && mon.attitude == ATT_FRIENDLY
1722 && mons_is_god_gift(mon, GOD_BEOGH);
1723 }
1724
is_fellow_slime(const monster & mon)1725 bool is_fellow_slime(const monster& mon)
1726 {
1727 return mon.alive() && mons_is_slime(mon)
1728 && mon.attitude == ATT_STRICT_NEUTRAL
1729 && mons_is_god_gift(mon, GOD_JIYVA);
1730 }
1731
_is_plant_follower(const monster * mon)1732 static bool _is_plant_follower(const monster* mon)
1733 {
1734 return mon->alive() && mons_is_plant(*mon)
1735 && mon->attitude == ATT_FRIENDLY;
1736 }
1737
_has_jelly()1738 static bool _has_jelly()
1739 {
1740 ASSERT(you_worship(GOD_JIYVA));
1741
1742 for (monster_iterator mi; mi; ++mi)
1743 if (mons_is_god_gift(**mi, GOD_JIYVA))
1744 return true;
1745 return false;
1746 }
1747
is_follower(const monster & mon)1748 bool is_follower(const monster& mon)
1749 {
1750 if (you_worship(GOD_YREDELEMNUL))
1751 return is_yred_undead_slave(mon);
1752 else if (will_have_passive(passive_t::convert_orcs))
1753 return is_orcish_follower(mon);
1754 else if (you_worship(GOD_JIYVA))
1755 return is_fellow_slime(mon);
1756 else if (you_worship(GOD_FEDHAS))
1757 return _is_plant_follower(&mon);
1758 else
1759 {
1760 return mon.alive() && mon.attitude == ATT_FRIENDLY
1761 && !mons_is_conjured(mon.type);
1762 }
1763 }
1764
1765 /**
1766 * What's the name of the ally Hepliaklqana granted the player?
1767 *
1768 * @return The ally's name.
1769 */
hepliaklqana_ally_name()1770 string hepliaklqana_ally_name()
1771 {
1772 return you.props[HEPLIAKLQANA_ALLY_NAME_KEY].get_string();
1773 }
1774
1775 /**
1776 * How much HD should the ally granted by Hepliaklqana have?
1777 *
1778 * @return The player's xl * 2/3.
1779 */
_hepliaklqana_ally_hd()1780 static int _hepliaklqana_ally_hd()
1781 {
1782 if (!crawl_state.need_save) // on main menu or otherwise don't have 'you'
1783 return 27; // v0v
1784 // round up
1785 return (you.experience_level - 1) * 2 / 3 + 1;
1786 }
1787
1788 /**
1789 * How much max HP should the ally granted by Hepliaklqana have?
1790 *
1791 * @return 5/hd from 1-11 HD, 10/hd from 12-18.
1792 * (That is, 5 HP at 1 HD, 120 at 18.)
1793 */
hepliaklqana_ally_hp()1794 int hepliaklqana_ally_hp()
1795 {
1796 const int HD = _hepliaklqana_ally_hd();
1797 return HD * 5 + max(0, (HD - 12) * 5);
1798 }
1799
1800 /**
1801 * Choose an antique name for a Hepliaklqana-granted ancestor.
1802 *
1803 * @param gender The ancestor's gender.
1804 * @return An appropriate name; e.g. Hrodulf, Citali, Aat.
1805 */
_make_ancestor_name(gender_type gender)1806 static string _make_ancestor_name(gender_type gender)
1807 {
1808 const string gender_name = gender == GENDER_MALE ? " male " :
1809 gender == GENDER_FEMALE ? " female " : " ";
1810 const string suffix = gender_name + "name";
1811 const string name = getRandNameString("ancestor", suffix);
1812 return name.empty() ? make_name() : name;
1813 }
1814
1815 /// Setup when gaining a Hepliaklqana ancestor.
_setup_hepliaklqana_ancestor()1816 static void _setup_hepliaklqana_ancestor()
1817 {
1818 // initial setup.
1819 if (!you.props.exists(HEPLIAKLQANA_ALLY_NAME_KEY))
1820 {
1821 const gender_type gender = random_choose(GENDER_NEUTRAL,
1822 GENDER_MALE,
1823 GENDER_FEMALE);
1824
1825 you.props[HEPLIAKLQANA_ALLY_NAME_KEY] = _make_ancestor_name(gender);
1826 you.props[HEPLIAKLQANA_ALLY_GENDER_KEY] = gender;
1827 }
1828 }
1829
1830 /**
1831 * Creates a mgen_data with the information needed to create the ancestor
1832 * granted by Hepliaklqana.
1833 *
1834 * XXX: should this be populating a mgen_data passed by reference, rather than
1835 * returning one on the stack?
1836 *
1837 * @return The mgen_data that creates a hepliaklqana ancestor.
1838 */
hepliaklqana_ancestor_gen_data()1839 mgen_data hepliaklqana_ancestor_gen_data()
1840 {
1841 _setup_hepliaklqana_ancestor();
1842 const monster_type type = you.props.exists(HEPLIAKLQANA_ALLY_TYPE_KEY) ?
1843 (monster_type)you.props[HEPLIAKLQANA_ALLY_TYPE_KEY].get_int() :
1844 MONS_ANCESTOR;
1845 mgen_data mg(type, BEH_FRIENDLY, you.pos(), MHITYOU, MG_AUTOFOE);
1846 mg.set_summoned(&you, 0, 0, GOD_HEPLIAKLQANA);
1847 mg.hd = _hepliaklqana_ally_hd();
1848 mg.hp = hepliaklqana_ally_hp();
1849 mg.extra_flags |= MF_NO_REWARD;
1850 mg.mname = hepliaklqana_ally_name();
1851 mg.props[MON_GENDER_KEY]
1852 = you.props[HEPLIAKLQANA_ALLY_GENDER_KEY].get_int();
1853 return mg;
1854 }
1855
1856 /// Print a message for an ancestor's *something* being gained.
_regain_memory(const monster & ancestor,string memory)1857 static void _regain_memory(const monster &ancestor, string memory)
1858 {
1859 mprf("%s regains the memory of %s %s.",
1860 ancestor.name(DESC_YOUR, true).c_str(),
1861 ancestor.pronoun(PRONOUN_POSSESSIVE, true).c_str(),
1862 memory.c_str());
1863 }
1864
_item_ego_name(object_class_type base_type,int brand)1865 static string _item_ego_name(object_class_type base_type, int brand)
1866 {
1867 switch (base_type)
1868 {
1869 case OBJ_WEAPONS:
1870 {
1871 // 'remembers... draining' reads better than 'drain', but 'flame'
1872 // reads better than 'flaming'
1873 const bool terse = brand == SPWPN_FLAMING
1874 || brand == SPWPN_ANTIMAGIC;
1875 return brand_type_name((brand_type) brand, terse);
1876 }
1877 case OBJ_ARMOUR:
1878 // XXX: hack
1879 return "reflection";
1880 default:
1881 die("unsupported object type");
1882 }
1883 }
1884
1885 /// Print a message for an ancestor's item being gained/type upgraded.
_regain_item_memory(const monster & ancestor,object_class_type base_type,int sub_type,int brand)1886 static void _regain_item_memory(const monster &ancestor,
1887 object_class_type base_type,
1888 int sub_type,
1889 int brand)
1890 {
1891 const string base_name = item_base_name(base_type, sub_type);
1892 if (!brand)
1893 {
1894 _regain_memory(ancestor, base_name);
1895 return;
1896 }
1897
1898 const string ego_name = _item_ego_name(base_type, brand);
1899 const string item_name
1900 = make_stringf("%s of %s",
1901 item_base_name(base_type, sub_type).c_str(),
1902 ego_name.c_str());
1903 _regain_memory(ancestor, item_name);
1904 }
1905
1906 /**
1907 * Update the ancestor's stats after the player levels up. Upgrade HD and HP,
1908 * and give appropriate messaging for that and any other notable upgrades
1909 * (spells, resists, etc).
1910 *
1911 * @param quiet_force Whether to squash messages & force upgrades,
1912 * even if the HD is unchanged.
1913 */
upgrade_hepliaklqana_ancestor(bool quiet_force)1914 void upgrade_hepliaklqana_ancestor(bool quiet_force)
1915 {
1916 monster* ancestor = hepliaklqana_ancestor_mon();
1917 if (!ancestor || !ancestor->alive())
1918 return;
1919
1920 // housekeeping
1921 ancestor->mname = hepliaklqana_ally_name();
1922 ancestor->props[MON_GENDER_KEY]
1923 = you.props[HEPLIAKLQANA_ALLY_GENDER_KEY].get_int();
1924
1925 const int old_hd = ancestor->get_experience_level();
1926 const int hd = _hepliaklqana_ally_hd();
1927 ancestor->set_hit_dice(hd);
1928 if (old_hd == hd && !quiet_force)
1929 return; // assume nothing changes except at different HD
1930
1931 const int old_mhp = ancestor->max_hit_points;
1932 ancestor->max_hit_points = hepliaklqana_ally_hp();
1933 ancestor->hit_points =
1934 div_rand_round(ancestor->hit_points * ancestor->max_hit_points,
1935 old_mhp);
1936
1937 if (!quiet_force)
1938 {
1939 mprf("%s remembers more of %s old skill.",
1940 ancestor->name(DESC_YOUR, true).c_str(),
1941 ancestor->pronoun(PRONOUN_POSSESSIVE, true).c_str());
1942 }
1943
1944 set_ancestor_spells(*ancestor, !quiet_force);
1945
1946 const bool ancestor_offlevel = companion_is_elsewhere(ancestor->mid);
1947 if (ancestor_offlevel)
1948 add_daction(DACT_UPGRADE_ANCESTOR);
1949
1950 // assumption: ancestors can lose weapons (very rarely - tukima's),
1951 // and it's weird for them to just reappear, so only upgrade existing ones
1952 if (ancestor->weapon())
1953 {
1954 if (!ancestor_offlevel)
1955 upgrade_hepliaklqana_weapon(ancestor->type, *ancestor->weapon());
1956
1957 const weapon_type wpn = _hepliaklqana_weapon_type(ancestor->type, hd);
1958 const brand_type brand = _hepliaklqana_weapon_brand(ancestor->type, hd);
1959 if (wpn != _hepliaklqana_weapon_type(ancestor->type, old_hd)
1960 && !quiet_force)
1961 {
1962 _regain_item_memory(*ancestor, OBJ_WEAPONS, wpn, brand);
1963 }
1964 else if (brand != _hepliaklqana_weapon_brand(ancestor->type, old_hd)
1965 && !quiet_force)
1966 {
1967 mprf("%s remembers %s %s %s.",
1968 ancestor->name(DESC_YOUR, true).c_str(),
1969 ancestor->pronoun(PRONOUN_POSSESSIVE, true).c_str(),
1970 apostrophise(item_base_name(OBJ_WEAPONS, wpn)).c_str(),
1971 brand_type_name(brand, brand != SPWPN_DRAINING));
1972 }
1973 }
1974 // but shields can't be lost, and *can* be gained (knight at hd 5)
1975 // so give them out as appropriate
1976 if (!ancestor_offlevel)
1977 {
1978 if (ancestor->shield())
1979 upgrade_hepliaklqana_shield(*ancestor, *ancestor->shield());
1980 else
1981 give_shield(ancestor);
1982 }
1983
1984 const armour_type shld = _hepliaklqana_shield_type(ancestor->type, hd);
1985 if (shld != _hepliaklqana_shield_type(ancestor->type, old_hd)
1986 && !quiet_force)
1987 {
1988 // doesn't currently support egos varying separately from shield types
1989 _regain_item_memory(*ancestor, OBJ_ARMOUR, shld,
1990 _hepliaklqana_shield_ego(hd));
1991 }
1992
1993 if (quiet_force)
1994 return;
1995 }
1996
1997 /**
1998 * What type of weapon should an ancestor of the given HD have?
1999 *
2000 * @param mc The type of ancestor in question.
2001 * @param HD The HD of the ancestor in question.
2002 * @return An appropriate weapon_type.
2003 */
_hepliaklqana_weapon_type(monster_type mc,int HD)2004 static weapon_type _hepliaklqana_weapon_type(monster_type mc, int HD)
2005 {
2006 switch (mc)
2007 {
2008 case MONS_ANCESTOR_HEXER:
2009 return HD < 16 ? WPN_DAGGER : WPN_QUICK_BLADE;
2010 case MONS_ANCESTOR_KNIGHT:
2011 return HD < 10 ? WPN_FLAIL : WPN_BROAD_AXE;
2012 case MONS_ANCESTOR_BATTLEMAGE:
2013 return HD < 13 ? WPN_QUARTERSTAFF : WPN_LAJATANG;
2014 default:
2015 return NUM_WEAPONS; // should never happen
2016 }
2017 }
2018
2019 /**
2020 * What brand should an ancestor of the given HD's weapon have, if any?
2021 *
2022 * @param mc The type of ancestor in question.
2023 * @param HD The HD of the ancestor in question.
2024 * @return An appropriate weapon_type.
2025 */
_hepliaklqana_weapon_brand(monster_type mc,int HD)2026 static brand_type _hepliaklqana_weapon_brand(monster_type mc, int HD)
2027 {
2028 switch (mc)
2029 {
2030 case MONS_ANCESTOR_HEXER:
2031 return HD < 16 ? SPWPN_DRAINING :
2032 SPWPN_ANTIMAGIC;
2033 case MONS_ANCESTOR_KNIGHT:
2034 return HD < 10 ? SPWPN_NORMAL :
2035 HD < 16 ? SPWPN_FLAMING :
2036 SPWPN_SPEED;
2037 case MONS_ANCESTOR_BATTLEMAGE:
2038 return HD < 13 ? SPWPN_NORMAL :
2039 SPWPN_FREEZING;
2040 default:
2041 return SPWPN_NORMAL;
2042 }
2043 }
2044
2045 /**
2046 * Setup an ancestor's weapon after their class is chosen, when the player
2047 * levels up, or after they're resummoned (or initially created for wrath).
2048 *
2049 * @param[in] mtyp The ancestor for whom the weapon is intended.
2050 * @param[out] item The item to be configured.
2051 * @param notify Whether messages should be printed when something
2052 * changes. (Weapon type or brand.)
2053 */
upgrade_hepliaklqana_weapon(monster_type mtyp,item_def & item)2054 void upgrade_hepliaklqana_weapon(monster_type mtyp, item_def &item)
2055 {
2056 ASSERT(mons_is_hepliaklqana_ancestor(mtyp));
2057 if (mtyp == MONS_ANCESTOR)
2058 return; // bare-handed!
2059
2060 item.base_type = OBJ_WEAPONS;
2061 item.sub_type = _hepliaklqana_weapon_type(mtyp,
2062 _hepliaklqana_ally_hd());
2063 item.brand = _hepliaklqana_weapon_brand(mtyp,
2064 _hepliaklqana_ally_hd());
2065 item.plus = 0;
2066 item.flags |= ISFLAG_KNOW_TYPE | ISFLAG_SUMMONED;
2067 }
2068
2069 /**
2070 * What kind of shield should an ancestor of the given HD be given?
2071 *
2072 * @param mc The type of ancestor in question.
2073 * @param HD The HD (XL) of the ancestor in question.
2074 * @return An appropriate type of shield, or NUM_ARMOURS.
2075 */
_hepliaklqana_shield_type(monster_type mc,int HD)2076 static armour_type _hepliaklqana_shield_type(monster_type mc, int HD)
2077 {
2078 if (mc != MONS_ANCESTOR_KNIGHT)
2079 return NUM_ARMOURS;
2080 if (HD < 13)
2081 return ARM_KITE_SHIELD;
2082 return ARM_TOWER_SHIELD;
2083 }
2084
_hepliaklqana_shield_ego(int HD)2085 static special_armour_type _hepliaklqana_shield_ego(int HD)
2086 {
2087 return HD < 13 ? SPARM_NORMAL : SPARM_REFLECTION;
2088 }
2089
2090 /**
2091 * Setup an ancestor's weapon after their class is chosen, when the player
2092 * levels up, or after they're resummoned (or initially created for wrath).
2093 *
2094 * @param[in] ancestor The ancestor for whom the weapon is intended.
2095 * @param[out] item The item to be configured.
2096 * @return True iff the ancestor should have a weapon.
2097 */
upgrade_hepliaklqana_shield(const monster & ancestor,item_def & item)2098 void upgrade_hepliaklqana_shield(const monster &ancestor, item_def &item)
2099 {
2100 ASSERT(mons_is_hepliaklqana_ancestor(ancestor.type));
2101 const int HD = ancestor.get_experience_level();
2102 const armour_type shield_type = _hepliaklqana_shield_type(ancestor.type,
2103 HD);
2104 if (shield_type == NUM_ARMOURS)
2105 return; // no shield yet!
2106
2107 item.base_type = OBJ_ARMOUR;
2108 item.sub_type = shield_type;
2109 item.brand = _hepliaklqana_shield_ego(HD);
2110 item.plus = 0;
2111 item.flags |= ISFLAG_KNOW_TYPE | ISFLAG_SUMMONED;
2112 item.quantity = 1;
2113 }
2114
2115 ///////////////////////////////
do_god_gift(bool forced)2116 bool do_god_gift(bool forced)
2117 {
2118 ASSERT(!you_worship(GOD_NO_GOD));
2119
2120 god_acting gdact;
2121
2122 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_GIFTS)
2123 int old_num_current_gifts = you.num_current_gifts[you.religion];
2124 int old_num_total_gifts = you.num_total_gifts[you.religion];
2125 #endif
2126
2127 bool success = false;
2128
2129 // Consider a gift if we don't have a timeout and aren't under penance
2130 if (forced || !player_under_penance() && !you.gift_timeout)
2131 {
2132 // Remember to check for water/lava.
2133 switch (you.religion)
2134 {
2135 default:
2136 break;
2137
2138 case GOD_NEMELEX_XOBEH:
2139 success = _give_nemelex_gift(forced);
2140 break;
2141
2142 #if TAG_MAJOR_VERSION == 34
2143 case GOD_PAKELLAS:
2144 success = _give_pakellas_gift();
2145 break;
2146 #endif
2147
2148 case GOD_OKAWARU:
2149 case GOD_TROG:
2150 success = _give_trog_oka_gift(forced);
2151 break;
2152
2153 case GOD_YREDELEMNUL:
2154 success = _give_yred_gift(forced);
2155 break;
2156
2157 case GOD_JIYVA:
2158 success = _gift_jiyva_gift(forced);
2159 break;
2160
2161 case GOD_USKAYAW:
2162 success = _handle_uskayaw_ability_unlocks();
2163 break;
2164
2165 case GOD_KIKUBAAQUDGHA:
2166 success = _give_kiku_gift(forced);
2167 break;
2168
2169 case GOD_SIF_MUNA:
2170 success = _give_sif_gift(forced);
2171 break;
2172
2173 case GOD_VEHUMET:
2174 success = _handle_veh_gift(forced);
2175 break;
2176 } // switch (you.religion)
2177 } // End of gift giving.
2178
2179 if (success)
2180 stop_running(false);
2181
2182 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_GIFTS)
2183 if (old_num_current_gifts < you.num_current_gifts[you.religion])
2184 {
2185 mprf(MSGCH_DIAGNOSTICS, "Current number of gifts from this god: %d",
2186 you.num_current_gifts[you.religion]);
2187 }
2188 if (old_num_total_gifts < you.num_total_gifts[you.religion])
2189 {
2190 mprf(MSGCH_DIAGNOSTICS, "Total number of gifts from this god: %d",
2191 you.num_total_gifts[you.religion]);
2192 }
2193 #endif
2194 return success;
2195 }
2196
god_name(god_type which_god,bool long_name)2197 string god_name(god_type which_god, bool long_name)
2198 {
2199 if (which_god == GOD_JIYVA)
2200 {
2201 return god_name_jiyva(long_name) +
2202 (long_name? " the Shapeless" : "");
2203 }
2204
2205 if (long_name)
2206 {
2207 const string shortname = god_name(which_god, false);
2208 const string longname = getMiscString(shortname + " lastname");
2209 return longname.empty()? shortname : longname;
2210 }
2211
2212 switch (which_god)
2213 {
2214 case GOD_NO_GOD: return "No God";
2215 case GOD_RANDOM: return "random";
2216 case GOD_NAMELESS: return "nameless";
2217 case GOD_ZIN: return "Zin";
2218 case GOD_SHINING_ONE: return "the Shining One";
2219 case GOD_KIKUBAAQUDGHA: return "Kikubaaqudgha";
2220 case GOD_YREDELEMNUL: return "Yredelemnul";
2221 case GOD_VEHUMET: return "Vehumet";
2222 case GOD_OKAWARU: return "Okawaru";
2223 case GOD_MAKHLEB: return "Makhleb";
2224 case GOD_SIF_MUNA: return "Sif Muna";
2225 case GOD_TROG: return "Trog";
2226 case GOD_NEMELEX_XOBEH: return "Nemelex Xobeh";
2227 case GOD_ELYVILON: return "Elyvilon";
2228 case GOD_LUGONU: return "Lugonu";
2229 case GOD_BEOGH: return "Beogh";
2230 case GOD_FEDHAS: return "Fedhas";
2231 case GOD_CHEIBRIADOS: return "Cheibriados";
2232 case GOD_XOM: return "Xom";
2233 case GOD_ASHENZARI: return "Ashenzari";
2234 case GOD_DITHMENOS: return "Dithmenos";
2235 case GOD_GOZAG: return "Gozag";
2236 case GOD_QAZLAL: return "Qazlal";
2237 case GOD_RU: return "Ru";
2238 #if TAG_MAJOR_VERSION == 34
2239 case GOD_PAKELLAS: return "Pakellas";
2240 #endif
2241 case GOD_USKAYAW: return "Uskayaw";
2242 case GOD_HEPLIAKLQANA: return "Hepliaklqana";
2243 case GOD_WU_JIAN: return "Wu Jian";
2244 case GOD_JIYVA: // This is handled at the beginning of the function
2245 case GOD_ECUMENICAL: return "an unknown god";
2246 case NUM_GODS: return "Buggy";
2247 }
2248 return "";
2249 }
2250
god_name_jiyva(bool second_name)2251 string god_name_jiyva(bool second_name)
2252 {
2253 string name = "Jiyva";
2254 if (second_name)
2255 name += " " + you.jiyva_second_name;
2256
2257 return name;
2258 }
2259
wu_jian_random_sifu_name()2260 string wu_jian_random_sifu_name()
2261 {
2262 switch (random2(7))
2263 {
2264 case 0: return "Yunchang";
2265 case 1: return "Lu Zhishen";
2266 case 2: return "Xiang Ba";
2267 case 3: return "Ma Yunglu";
2268 case 4: return "Hu Sanniang";
2269 case 5: return "Gene Jian Bin";
2270 case 6: return "Cai Fang";
2271 default: return "Bug";
2272 }
2273 }
2274
str_to_god(const string & _name,bool exact)2275 god_type str_to_god(const string &_name, bool exact)
2276 {
2277 string target(_name);
2278 trim_string(target);
2279 lowercase(target);
2280
2281 if (target.empty())
2282 return GOD_NO_GOD;
2283
2284 int num_partials = 0;
2285 god_type partial = GOD_NO_GOD;
2286 for (god_iterator it; it; ++it)
2287 {
2288 god_type god = *it;
2289 string name = lowercase_string(god_name(god, false));
2290
2291 if (name == target)
2292 return god;
2293
2294 if (!exact && name.find(target) != string::npos)
2295 {
2296 // Return nothing for ambiguous partial names.
2297 num_partials++;
2298 if (num_partials > 1)
2299 return GOD_NO_GOD;
2300 partial = god;
2301 }
2302 }
2303
2304 if (!exact && num_partials == 1)
2305 return partial;
2306
2307 return GOD_NO_GOD;
2308 }
2309
god_speaks(god_type god,const char * mesg)2310 void god_speaks(god_type god, const char *mesg)
2311 {
2312 ASSERT(!crawl_state.game_is_arena());
2313
2314 int orig_mon = env.mgrid(you.pos());
2315
2316 monster fake_mon;
2317 fake_mon.type = MONS_PROGRAM_BUG;
2318 fake_mon.mid = MID_NOBODY;
2319 fake_mon.hit_points = 1;
2320 fake_mon.god = god;
2321 fake_mon.set_position(you.pos());
2322 fake_mon.foe = MHITYOU;
2323 fake_mon.mname = "FAKE GOD MONSTER";
2324
2325 mprf(MSGCH_GOD, god, "%s", do_mon_str_replacements(mesg, fake_mon).c_str());
2326
2327 fake_mon.reset();
2328 env.mgrid(you.pos()) = orig_mon;
2329 }
2330
religion_turn_start()2331 void religion_turn_start()
2332 {
2333 if (you.turn_is_over)
2334 religion_turn_end();
2335
2336 crawl_state.clear_god_acting();
2337 }
2338
religion_turn_end()2339 void religion_turn_end()
2340 {
2341 ASSERT(you.turn_is_over);
2342 _place_delayed_monsters();
2343 }
2344
2345 /** Punish the character for some divine transgression.
2346 *
2347 * @param piety_loss The amount of penance imposed; may be scaled.
2348 * @param penance The amount of penance imposed; may be scaled.
2349 */
dock_piety(int piety_loss,int penance)2350 void dock_piety(int piety_loss, int penance)
2351 {
2352 static int last_piety_lecture = -1;
2353 static int last_penance_lecture = -1;
2354
2355 if (piety_loss <= 0 && penance <= 0)
2356 return;
2357
2358 piety_loss = piety_scale(piety_loss);
2359 penance = piety_scale(penance);
2360
2361 if (piety_loss)
2362 {
2363 if (last_piety_lecture != you.num_turns)
2364 {
2365 // output guilt message:
2366 mprf("You feel%sguilty.",
2367 (piety_loss == 1) ? " a little " :
2368 (piety_loss < 5) ? " " :
2369 (piety_loss < 10) ? " very "
2370 : " extremely ");
2371 }
2372
2373 last_piety_lecture = you.num_turns;
2374 lose_piety(piety_loss);
2375 }
2376
2377 if (you.piety < 1)
2378 excommunication();
2379 else if (penance) // only if still in religion
2380 {
2381 if (last_penance_lecture != you.num_turns)
2382 {
2383 god_speaks(you.religion,
2384 "\"You will pay for your transgression, mortal!\"");
2385 }
2386 last_penance_lecture = you.num_turns;
2387 _inc_penance(penance);
2388 }
2389 }
2390
2391 // Scales a piety number, applying modifiers (faith).
piety_scale(int piety)2392 int piety_scale(int piety)
2393 {
2394 return piety + (you.faith() * div_rand_round(piety, 4));
2395 }
2396
2397 /** Gain or lose piety to reach a certain value.
2398 *
2399 * If the player cannot gain piety (because they worship Xom, Gozag, or
2400 * no god), their piety will be unchanged.
2401 *
2402 * @param piety The new piety value.
2403 * @pre piety is between 0 and MAX_PIETY, inclusive.
2404 */
set_piety(int piety)2405 void set_piety(int piety)
2406 {
2407 ASSERT(piety >= 0);
2408 ASSERT(piety <= MAX_PIETY);
2409
2410 // Ru max piety is 6*
2411 if (you_worship(GOD_RU) && piety > piety_breakpoint(5))
2412 piety = piety_breakpoint(5);
2413
2414 // We have to set the exact piety value this way, because diff may
2415 // be decreased to account for things like penance and gift timeout.
2416 int diff;
2417 do
2418 {
2419 diff = piety - you.piety;
2420 if (diff > 0)
2421 {
2422 if (!gain_piety(diff, 1, false))
2423 break;
2424 }
2425 else if (diff < 0)
2426 lose_piety(-diff);
2427 }
2428 while (diff != 0);
2429 }
2430
_gain_piety_point()2431 static void _gain_piety_point()
2432 {
2433 // check to see if we owe anything first
2434 if (player_under_penance(you.religion))
2435 {
2436 dec_penance(1);
2437 return;
2438 }
2439 else if (you.gift_timeout > 0)
2440 {
2441 you.gift_timeout--;
2442
2443 // Slow down piety gain to account for the fact that gifts
2444 // no longer have a piety cost for getting them.
2445 // Jiyva is an exception because there's usually a time-out and
2446 // the gifts aren't that precious.
2447 if (!one_chance_in(4) && !you_worship(GOD_JIYVA)
2448 && !you_worship(GOD_NEMELEX_XOBEH))
2449 {
2450 #ifdef DEBUG_PIETY
2451 mprf(MSGCH_DIAGNOSTICS, "Piety slowdown due to gift timeout.");
2452 #endif
2453 return;
2454 }
2455 }
2456
2457 // slow down gain at upper levels of piety
2458 if (!you_worship(GOD_RU))
2459 {
2460 if (you.piety >= MAX_PIETY
2461 || you.piety >= piety_breakpoint(5) && one_chance_in(3)
2462 || you.piety >= piety_breakpoint(3) && one_chance_in(3))
2463 {
2464 do_god_gift();
2465 return;
2466 }
2467 }
2468 else
2469 {
2470 // Ru piety doesn't modulate or taper and Ru doesn't give gifts.
2471 // Ru max piety is 160 (6*)
2472 if (you.piety >= piety_breakpoint(5))
2473 return;
2474 }
2475
2476 int old_piety = you.piety;
2477 // Apply hysteresis.
2478 // piety_hysteresis is the amount of _loss_ stored up, so this
2479 // may look backwards.
2480 if (you.piety_hysteresis)
2481 you.piety_hysteresis--;
2482 else if (you.piety < MAX_PIETY)
2483 you.piety++;
2484
2485 if (piety_rank() > piety_rank(old_piety))
2486 {
2487 // Redraw piety display and, in case the best skill is Invocations,
2488 // redraw the god title.
2489 you.redraw_title = true;
2490
2491 const int rank = piety_rank();
2492 take_note(Note(NOTE_PIETY_RANK, you.religion, rank));
2493
2494 // For messaging reasons, we want to get our ancestor before
2495 // we get the associated recall / rename powers.
2496 if (rank == rank_for_passive(passive_t::frail))
2497 {
2498 calc_hp(); // adjust for frailty
2499 // In exchange for your hp, you get an ancestor!
2500 const mgen_data mg = hepliaklqana_ancestor_gen_data();
2501 delayed_monster(mg);
2502 simple_god_message(make_stringf(" forms a fragment of your life essence"
2503 " into the memory of your ancestor, %s!",
2504 mg.mname.c_str()).c_str());
2505 }
2506
2507 for (const auto& power : get_god_powers(you.religion))
2508 {
2509
2510 if (power.rank == rank
2511 || power.rank == 7 && can_do_capstone_ability(you.religion))
2512 {
2513 power.display(true, "You can now %s.");
2514 #ifdef USE_TILE_LOCAL
2515 tiles.layout_statcol();
2516 redraw_screen();
2517 update_screen();
2518 #endif
2519 learned_something_new(HINT_NEW_ABILITY_GOD);
2520 // Preserve the old hotkey
2521 if (power.abil == ABIL_YRED_ANIMATE_DEAD)
2522 {
2523 replace(begin(you.ability_letter_table),
2524 end(you.ability_letter_table),
2525 ABIL_YRED_ANIMATE_REMAINS, ABIL_YRED_ANIMATE_DEAD);
2526 }
2527 }
2528 }
2529 if (rank == rank_for_passive(passive_t::halo))
2530 mprf(MSGCH_GOD, "A divine halo surrounds you!");
2531 if (rank == rank_for_passive(passive_t::umbra))
2532 mprf(MSGCH_GOD, "You are shrouded in an aura of darkness!");
2533 if (rank == rank_for_passive(passive_t::sinv))
2534 autotoggle_autopickup(false);
2535 if (rank == rank_for_passive(passive_t::clarity))
2536 {
2537 // Inconsistent with donning amulets, but matches the
2538 // message better and is not abusable.
2539 you.duration[DUR_CONF] = 0;
2540 }
2541 if (rank >= rank_for_passive(passive_t::identify_items))
2542 auto_id_inventory();
2543
2544 // TODO: add one-time ability check in have_passive
2545 if (have_passive(passive_t::unlock_slime_vaults) && can_do_capstone_ability(you.religion))
2546 {
2547 simple_god_message(" will now unseal the treasures of the "
2548 "Slime Pits.");
2549 dlua.callfn("dgn_set_persistent_var", "sb",
2550 "fix_slime_vaults", true);
2551 // If we're on Slime:$, pretend we just entered the level
2552 // in order to bring down the vault walls.
2553 if (level_id::current() == level_id(BRANCH_SLIME, brdepth[BRANCH_SLIME]))
2554 dungeon_events.fire_event(DET_ENTERED_LEVEL);
2555
2556 you.one_time_ability_used.set(you.religion);
2557 }
2558 if (you_worship(GOD_HEPLIAKLQANA)
2559 && rank == 2 && !you.props.exists(HEPLIAKLQANA_ALLY_TYPE_KEY))
2560 {
2561 god_speaks(you.religion,
2562 "You may now remember your ancestor's life.");
2563 }
2564 }
2565
2566 // The player's symbol depends on Beogh piety.
2567 if (you_worship(GOD_BEOGH))
2568 update_player_symbol();
2569
2570 if (have_passive(passive_t::stat_boost)
2571 && chei_stat_boost(old_piety) < chei_stat_boost())
2572 {
2573 string msg = " raises the support of your attributes";
2574 if (have_passive(passive_t::slowed))
2575 msg += " as your movement slows";
2576 msg += ".";
2577 simple_god_message(msg.c_str());
2578 notify_stat_change();
2579 }
2580
2581 if (you_worship(GOD_QAZLAL)
2582 && qazlal_sh_boost(old_piety) != qazlal_sh_boost())
2583 {
2584 you.redraw_armour_class = true;
2585 }
2586
2587 if (have_passive(passive_t::halo) || have_passive(passive_t::umbra))
2588 {
2589 // Piety change affects halo / umbra radius.
2590 invalidate_agrid(true);
2591 }
2592
2593 do_god_gift();
2594 }
2595
2596 /**
2597 * Gain an amount of piety.
2598 *
2599 * @param original_gain The numerator of the nominal piety gain.
2600 * @param denominator The denominator of the nominal piety gain.
2601 * @param should_scale_piety Should the piety gain be scaled by faith/Sprint?
2602 * @return True if something happened, or if another call with the same
2603 * arguments might cause something to happen (because of random number
2604 * rolls).
2605 */
gain_piety(int original_gain,int denominator,bool should_scale_piety)2606 bool gain_piety(int original_gain, int denominator, bool should_scale_piety)
2607 {
2608 if (original_gain <= 0)
2609 return false;
2610
2611 // Xom uses piety differently; Gozag doesn't at all.
2612 if (you_worship(GOD_NO_GOD)
2613 || you_worship(GOD_XOM)
2614 || you_worship(GOD_GOZAG))
2615 {
2616 return false;
2617 }
2618
2619 int pgn = should_scale_piety ? piety_scale(original_gain) : original_gain;
2620
2621 if (crawl_state.game_is_sprint() && should_scale_piety)
2622 pgn = sprint_modify_piety(pgn);
2623
2624 pgn = div_rand_round(pgn, denominator);
2625 while (pgn-- > 0)
2626 _gain_piety_point();
2627 if (you.piety > you.piety_max[you.religion])
2628 {
2629 if (you.piety >= piety_breakpoint(5)
2630 && you.piety_max[you.religion] < piety_breakpoint(5))
2631 {
2632 mark_milestone("god.maxpiety", "became the Champion of "
2633 + god_name(you.religion) + ".");
2634 }
2635 you.piety_max[you.religion] = you.piety;
2636 }
2637 return true;
2638 }
2639
2640 /** Reduce piety and handle side-effects.
2641 *
2642 * Appropriate for cases where the player has not sinned, but must lose piety
2643 * anyway, such as costs for abilities.
2644 *
2645 * @param pgn The precise amount of piety lost.
2646 */
lose_piety(int pgn)2647 void lose_piety(int pgn)
2648 {
2649 if (pgn <= 0)
2650 return;
2651
2652 const int old_piety = you.piety;
2653
2654 // Apply hysteresis.
2655 const int old_hysteresis = you.piety_hysteresis;
2656 you.piety_hysteresis = min<int>(PIETY_HYSTERESIS_LIMIT,
2657 you.piety_hysteresis + pgn);
2658 const int pgn_borrowed = (you.piety_hysteresis - old_hysteresis);
2659 pgn -= pgn_borrowed;
2660 #ifdef DEBUG_PIETY
2661 mprf(MSGCH_DIAGNOSTICS,
2662 "Piety decreasing by %d (and %d added to hysteresis)",
2663 pgn, pgn_borrowed);
2664 #endif
2665
2666 if (you.piety - pgn < 0)
2667 you.piety = 0;
2668 else
2669 you.piety -= pgn;
2670
2671 // Don't bother printing out these messages if you're under
2672 // penance, you wouldn't notice since all these abilities
2673 // are withheld.
2674 if (!player_under_penance()
2675 && piety_rank(old_piety) > piety_rank())
2676 {
2677 // Redraw piety display and, in case the best skill is Invocations,
2678 // redraw the god title.
2679 you.redraw_title = true;
2680
2681 const int old_rank = piety_rank(old_piety);
2682
2683 for (const auto& power : get_god_powers(you.religion))
2684 {
2685 if (power.rank == old_rank
2686 || power.rank == 7 && old_rank == 6
2687 && !you.one_time_ability_used[you.religion])
2688 {
2689 power.display(false, "You can no longer %s.");
2690 // Preserve the old hotkey
2691 if (power.abil == ABIL_YRED_ANIMATE_DEAD)
2692 {
2693 replace(begin(you.ability_letter_table),
2694 end(you.ability_letter_table),
2695 ABIL_YRED_ANIMATE_DEAD, ABIL_YRED_ANIMATE_REMAINS);
2696 }
2697 #if TAG_MAJOR_VERSION == 34
2698 // Deactivate the toggle
2699 if (power.abil == ABIL_SIF_MUNA_DIVINE_ENERGY)
2700 you.attribute[ATTR_DIVINE_ENERGY] = 0;
2701 #endif
2702 }
2703 }
2704 #ifdef USE_TILE_LOCAL
2705 tiles.layout_statcol();
2706 redraw_screen();
2707 update_screen();
2708 #endif
2709
2710 if (will_have_passive(passive_t::frail) && !have_passive(passive_t::frail))
2711 {
2712 // hep: just lost 1*
2713 // remove companion (gained at same tier as frail)
2714 add_daction(DACT_ALLY_HEPLIAKLQANA);
2715 remove_all_companions(GOD_HEPLIAKLQANA);
2716 calc_hp(); // adjust for frailty
2717 }
2718 }
2719
2720 if (you.piety > 0 && you.piety <= 5)
2721 learned_something_new(HINT_GOD_DISPLEASED);
2722
2723 if (will_have_passive(passive_t::water_walk) && _need_water_walking()
2724 && !have_passive(passive_t::water_walk))
2725 {
2726 _grant_temporary_waterwalk();
2727 }
2728 if (will_have_passive(passive_t::stat_boost)
2729 && chei_stat_boost(old_piety) > chei_stat_boost())
2730 {
2731 string msg = " lowers the support of your attributes";
2732 if (will_have_passive(passive_t::slowed))
2733 msg += " as your movement quickens";
2734 msg += ".";
2735 simple_god_message(msg.c_str());
2736 notify_stat_change();
2737 }
2738
2739 if (you_worship(GOD_QAZLAL)
2740 && qazlal_sh_boost(old_piety) != qazlal_sh_boost())
2741 {
2742 you.redraw_armour_class = true;
2743 }
2744
2745 if (will_have_passive(passive_t::halo)
2746 || will_have_passive(passive_t::umbra))
2747 {
2748 // Piety change affects halo / umbra radius.
2749 invalidate_agrid(true);
2750 }
2751 }
2752
2753 // Fedhas worshipers are on the hook for most plants and fungi
2754 //
2755 // If fedhas worshipers kill a protected monster they lose piety,
2756 // if they attack a friendly one they get penance,
2757 // if a friendly one dies they lose piety.
_fedhas_protects_species(monster_type mc)2758 static bool _fedhas_protects_species(monster_type mc)
2759 {
2760 return mons_class_is_plant(mc)
2761 && mons_class_holiness(mc) & MH_PLANT;
2762 }
2763
2764 /// Whether fedhas would protect `target` from harm if called on to do so.
fedhas_protects(const monster * target)2765 bool fedhas_protects(const monster *target)
2766 {
2767 return target && _fedhas_protects_species(mons_base_type(*target));
2768 }
2769
2770 /**
2771 * Does some god protect monster `target` from harm triggered by `agent`?
2772 * @param agent The source of the damage. If nullptr, the damage has no source.
2773 * (Currently, no god does protect in this case.)
2774 * @param target A monster that is the target of the damage.
2775 * @param quiet If false, do messaging to indicate that target has escaped
2776 * damage.
2777 * @return Whether target should escape damage.
2778 */
god_protects(const actor * agent,const monster * target,bool quiet)2779 bool god_protects(const actor *agent, const monster *target, bool quiet)
2780 {
2781 // The alignment check is to allow a penanced player to continue to fight
2782 // hostiles that would otherwise be protected, in case what they angered can
2783 // fight back
2784
2785 const bool aligned = agent && target
2786 && ((agent->is_player()
2787 ? target->friendly()
2788 : mons_atts_aligned(target->attitude,
2789 agent->as_monster()->attitude))
2790 || target->neutral());
2791 // XX does it matter whether this just checks fedhas vs.
2792 // the shoot_through_plants passive
2793 if (aligned
2794 && ((agent->is_player() || agent->as_monster()->friendly())
2795 && have_passive(passive_t::shoot_through_plants)
2796 || agent->is_monster() && agent->deity() == GOD_FEDHAS) // purely theoretical?
2797 && fedhas_protects(target))
2798 {
2799 if (!quiet && you.can_see(*target))
2800 {
2801 simple_god_message(
2802 make_stringf(" protects %s plant from harm.",
2803 agent->is_player() ? "your" : "a").c_str(),
2804 GOD_FEDHAS);
2805 }
2806 return true;
2807 }
2808
2809 if (agent && target && agent->is_player()
2810 && mons_is_hepliaklqana_ancestor(target->type))
2811 {
2812 // TODO: this message does not work very well for all sorts of attacks
2813 // should this be a god message?
2814 if (!quiet && you.can_see(*target))
2815 mprf("%s avoids your attack.", target->name(DESC_THE).c_str());
2816 return true;
2817 }
2818 return false;
2819 }
2820
2821 /**
2822 * Does some god protect monster `target` from harm triggered by the player?
2823 * @param target A monster that is the target of the damage.
2824 * @param quiet If false, do messaging to indicate that target has escaped
2825 * damage.
2826 * @return Whether target should escape damage.
2827 */
god_protects(const monster * target,bool quiet)2828 bool god_protects(const monster *target, bool quiet)
2829 {
2830 return god_protects(&you, target, quiet);
2831 }
2832
2833 /// Whether Fedhas would set `target` to a neutral attitude
fedhas_neutralises(const monster & target)2834 bool fedhas_neutralises(const monster& target)
2835 {
2836 return mons_is_plant(target)
2837 && target.holiness() & MH_PLANT
2838 && target.type != MONS_SNAPLASHER_VINE
2839 && target.type != MONS_SNAPLASHER_VINE_SEGMENT;
2840 }
2841
_god_hates_your_god_reaction(god_type god,god_type your_god)2842 static string _god_hates_your_god_reaction(god_type god, god_type your_god)
2843 {
2844 if (god_hates_your_god(god, your_god))
2845 {
2846 // Non-good gods always hate your current god.
2847 if (!is_good_god(god))
2848 return "";
2849
2850 // Zin hates chaotic gods.
2851 if (god == GOD_ZIN && is_chaotic_god(your_god))
2852 return " for chaos";
2853
2854 if (is_evil_god(your_god))
2855 return " for evil";
2856 }
2857
2858 return "";
2859 }
2860
2861 /**
2862 * When you abandon this god, how much penance do you gain? (How long does the
2863 * wrath last?
2864 *
2865 * @param god The god in question.
2866 * @return The initial penance for the given god's wrath.
2867 */
initial_wrath_penance_for(god_type god)2868 int initial_wrath_penance_for(god_type god)
2869 {
2870 // TODO: transform to data (tables)
2871 switch (god)
2872 {
2873 case GOD_ASHENZARI:
2874 case GOD_BEOGH:
2875 case GOD_ELYVILON:
2876 case GOD_GOZAG:
2877 case GOD_HEPLIAKLQANA:
2878 case GOD_LUGONU:
2879 case GOD_NEMELEX_XOBEH:
2880 case GOD_TROG:
2881 case GOD_XOM:
2882 return 50;
2883 case GOD_FEDHAS:
2884 case GOD_KIKUBAAQUDGHA:
2885 case GOD_JIYVA:
2886 case GOD_SHINING_ONE:
2887 case GOD_SIF_MUNA:
2888 case GOD_YREDELEMNUL:
2889 return 30;
2890 case GOD_CHEIBRIADOS:
2891 case GOD_DITHMENOS:
2892 case GOD_MAKHLEB:
2893 #if TAG_MAJOR_VERSION == 34
2894 case GOD_PAKELLAS:
2895 #endif
2896 case GOD_QAZLAL:
2897 case GOD_VEHUMET:
2898 case GOD_ZIN:
2899 default:
2900 return 25;
2901 case GOD_RU:
2902 return 0;
2903 }
2904 }
2905
_ash_uncurse()2906 static void _ash_uncurse()
2907 {
2908 bool uncursed = false;
2909 // iterate backwards so we shatter a ring on the macabre finger
2910 // necklace before the amulet
2911 for (int eq_typ = NUM_EQUIP - 1; eq_typ >= EQ_FIRST_EQUIP; eq_typ--)
2912 {
2913 const int slot = you.equip[eq_typ];
2914 if (slot == -1)
2915 continue;
2916 if (!uncursed)
2917 {
2918 mprf(MSGCH_GOD, GOD_ASHENZARI, "Your curses shatter.");
2919 uncursed = true;
2920 }
2921 unequip_item(static_cast<equipment_type>(eq_typ));
2922 }
2923 }
2924
excom_xp_docked()2925 int excom_xp_docked()
2926 {
2927 return exp_needed(min<int>(you.max_level, 27) + 1)
2928 - exp_needed(min<int>(you.max_level, 27));
2929 }
2930
excommunication(bool voluntary,god_type new_god)2931 void excommunication(bool voluntary, god_type new_god)
2932 {
2933 const god_type old_god = you.religion;
2934 ASSERT(old_god != new_god);
2935 ASSERT(old_god != GOD_NO_GOD);
2936
2937 const bool had_halo = have_passive(passive_t::halo);
2938 const bool had_umbra = have_passive(passive_t::umbra);
2939 const bool had_water_walk = have_passive(passive_t::water_walk);
2940 const bool had_stat_boost = have_passive(passive_t::stat_boost);
2941 const int old_piety = you.piety;
2942
2943 god_acting gdact(old_god, true);
2944
2945 take_note(Note(NOTE_LOSE_GOD, old_god));
2946
2947 you.duration[DUR_PIETY_POOL] = 0; // your loss
2948 you.duration[DUR_RECITE] = 0;
2949 you.piety = 0;
2950 you.piety_hysteresis = 0;
2951
2952 // so that the player isn't punished for "switching" between good gods via aX
2953 if (is_good_god(old_god) && voluntary)
2954 {
2955 you.saved_good_god_piety = old_piety;
2956 you.previous_good_god = old_god;
2957 }
2958 else
2959 {
2960 you.saved_good_god_piety = 0;
2961 you.previous_good_god = GOD_NO_GOD;
2962 }
2963
2964 you.num_current_gifts[old_god] = 0;
2965
2966 you.religion = GOD_NO_GOD;
2967
2968 you.redraw_title = true;
2969
2970 // Renouncing may have changed the conducts on our wielded or
2971 // quivered weapons, so refresh the display.
2972 you.wield_change = true;
2973 quiver::set_needs_redraw();
2974
2975 mpr("You have lost your religion!");
2976 // included in default force_more_message
2977
2978 if (old_god == GOD_BEOGH)
2979 {
2980 // The player's symbol depends on Beogh worship.
2981 update_player_symbol();
2982 }
2983
2984 mark_milestone("god.renounce", "abandoned " + god_name(old_god) + ".");
2985 #ifdef DGL_WHEREIS
2986 whereis_record();
2987 #endif
2988
2989 if (god_hates_your_god(old_god, new_god))
2990 {
2991 simple_god_message(
2992 make_stringf(" does not appreciate desertion%s!",
2993 _god_hates_your_god_reaction(old_god, new_god).c_str()).c_str(),
2994 old_god);
2995 }
2996
2997 if (had_halo)
2998 {
2999 mprf(MSGCH_GOD, old_god, "Your divine halo fades away.");
3000 invalidate_agrid(true);
3001 }
3002 if (had_umbra)
3003 {
3004 mprf(MSGCH_GOD, old_god, "Your aura of darkness fades away.");
3005 invalidate_agrid(true);
3006 }
3007 // You might have lost water walking at a bad time...
3008 if (had_water_walk && _need_water_walking())
3009 _grant_temporary_waterwalk();
3010 if (had_stat_boost)
3011 {
3012 redraw_screen();
3013 update_screen();
3014 notify_stat_change();
3015 }
3016
3017 switch (old_god)
3018 {
3019 case GOD_KIKUBAAQUDGHA:
3020 mprf(MSGCH_GOD, old_god, "You sense decay."); // in the state of Denmark
3021 add_daction(DACT_ROT_CORPSES);
3022 break;
3023
3024 case GOD_YREDELEMNUL:
3025 you.duration[DUR_MIRROR_DAMAGE] = 0;
3026 if (query_daction_counter(DACT_ALLY_YRED_SLAVE))
3027 {
3028 simple_god_message(" reclaims all of your granted undead slaves!",
3029 old_god);
3030 add_daction(DACT_ALLY_YRED_SLAVE);
3031 remove_all_companions(GOD_YREDELEMNUL);
3032 }
3033 break;
3034
3035 case GOD_VEHUMET:
3036 you.vehumet_gifts.clear();
3037 you.duration[DUR_VEHUMET_GIFT] = 0;
3038 break;
3039
3040 case GOD_MAKHLEB:
3041 make_god_gifts_disappear();
3042 break;
3043
3044 case GOD_TROG:
3045 if (you.duration[DUR_TROGS_HAND])
3046 trog_remove_trogs_hand();
3047 make_god_gifts_disappear();
3048 break;
3049
3050 case GOD_BEOGH:
3051 if (query_daction_counter(DACT_ALLY_BEOGH))
3052 {
3053 simple_god_message("'s voice booms out, \"Who do you think you "
3054 "are?\"", old_god);
3055 mprf(MSGCH_MONSTER_ENCHANT, "All of your followers decide to abandon you.");
3056 add_daction(DACT_ALLY_BEOGH);
3057 remove_all_companions(GOD_BEOGH);
3058 }
3059
3060 env.level_state |= LSTATE_BEOGH;
3061 break;
3062
3063 case GOD_SIF_MUNA:
3064 if (you.duration[DUR_CHANNEL_ENERGY])
3065 you.duration[DUR_CHANNEL_ENERGY] = 0;
3066 #if TAG_MAJOR_VERSION == 34
3067 if (you.attribute[ATTR_DIVINE_ENERGY])
3068 you.attribute[ATTR_DIVINE_ENERGY] = 0;
3069 #endif
3070 break;
3071
3072 case GOD_NEMELEX_XOBEH:
3073 reset_cards();
3074 mprf(MSGCH_GOD, old_god, "Your access to %s's decks is revoked.",
3075 god_name(old_god).c_str());
3076 break;
3077
3078 case GOD_SHINING_ONE:
3079 if (you.duration[DUR_DIVINE_SHIELD])
3080 tso_remove_divine_shield();
3081
3082 make_god_gifts_disappear();
3083 break;
3084
3085 case GOD_ZIN:
3086 if (you.duration[DUR_DIVINE_STAMINA])
3087 zin_remove_divine_stamina();
3088
3089 if (env.sanctuary_time)
3090 remove_sanctuary();
3091 break;
3092
3093 case GOD_ELYVILON:
3094 you.duration[DUR_LIFESAVING] = 0;
3095 if (you.duration[DUR_DIVINE_VIGOUR])
3096 elyvilon_remove_divine_vigour();
3097 you.exp_docked[old_god] = excom_xp_docked();
3098 you.exp_docked_total[old_god] = you.exp_docked[old_god];
3099 break;
3100
3101 case GOD_JIYVA:
3102 if (you.duration[DUR_SLIMIFY])
3103 you.duration[DUR_SLIMIFY] = 0;
3104
3105 if (query_daction_counter(DACT_ALLY_SLIME))
3106 {
3107 mprf(MSGCH_MONSTER_ENCHANT, "All of your fellow slimes turn on you.");
3108 add_daction(DACT_ALLY_SLIME);
3109 }
3110 break;
3111
3112 case GOD_FEDHAS:
3113 if (query_daction_counter(DACT_ALLY_PLANT))
3114 {
3115 mprf(MSGCH_MONSTER_ENCHANT, "The plants of the dungeon turn on you.");
3116 add_daction(DACT_ALLY_PLANT);
3117 }
3118 break;
3119
3120 case GOD_ASHENZARI:
3121 you.exp_docked[old_god] = excom_xp_docked();
3122 you.exp_docked_total[old_god] = you.exp_docked[old_god];
3123 _ash_uncurse();
3124 break;
3125
3126 case GOD_DITHMENOS:
3127 if (you.form == transformation::shadow)
3128 untransform();
3129 break;
3130
3131 case GOD_GOZAG:
3132 if (you.attribute[ATTR_GOZAG_SHOPS_CURRENT])
3133 {
3134 mprf(MSGCH_GOD, old_god, "Your funded stores close, unable to pay "
3135 "their debts without your funds.");
3136 you.attribute[ATTR_GOZAG_SHOPS_CURRENT] = 0;
3137 }
3138 you.duration[DUR_GOZAG_GOLD_AURA] = 0;
3139 for (branch_iterator it; it; ++it)
3140 branch_bribe[it->id] = 0;
3141 add_daction(DACT_BRIBE_TIMEOUT);
3142 add_daction(DACT_REMOVE_GOZAG_SHOPS);
3143 shopping_list.remove_dead_shops();
3144 you.exp_docked[old_god] = excom_xp_docked();
3145 you.exp_docked_total[old_god] = you.exp_docked[old_god];
3146 break;
3147
3148 case GOD_QAZLAL:
3149 if (old_piety >= piety_breakpoint(0))
3150 {
3151 mprf(MSGCH_GOD, old_god, "Your storm instantly dissipates.");
3152 you.redraw_armour_class = true;
3153 }
3154 if (you.duration[DUR_QAZLAL_FIRE_RES])
3155 {
3156 mprf(MSGCH_DURATION, "Your resistance to fire fades away.");
3157 you.duration[DUR_QAZLAL_FIRE_RES] = 0;
3158 }
3159 if (you.duration[DUR_QAZLAL_COLD_RES])
3160 {
3161 mprf(MSGCH_DURATION, "Your resistance to cold fades away.");
3162 you.duration[DUR_QAZLAL_COLD_RES] = 0;
3163 }
3164 if (you.duration[DUR_QAZLAL_ELEC_RES])
3165 {
3166 mprf(MSGCH_DURATION,
3167 "Your resistance to electricity fades away.");
3168 you.duration[DUR_QAZLAL_ELEC_RES] = 0;
3169 }
3170 if (you.duration[DUR_QAZLAL_AC])
3171 {
3172 mprf(MSGCH_DURATION,
3173 "Your resistance to physical damage fades away.");
3174 you.duration[DUR_QAZLAL_AC] = 0;
3175 you.redraw_armour_class = true;
3176 }
3177 break;
3178
3179 #if TAG_MAJOR_VERSION == 34
3180 case GOD_PAKELLAS:
3181 simple_god_message(" continues to block your magic from regenerating.",
3182 old_god);
3183 you.exp_docked[old_god] = excom_xp_docked();
3184 you.exp_docked_total[old_god] = you.exp_docked[old_god];
3185 break;
3186 #endif
3187
3188 case GOD_CHEIBRIADOS:
3189 simple_god_message(" continues to slow your movements.", old_god);
3190 break;
3191
3192 case GOD_HEPLIAKLQANA:
3193 add_daction(DACT_ALLY_HEPLIAKLQANA);
3194 remove_all_companions(GOD_HEPLIAKLQANA);
3195
3196 you.exp_docked[old_god] = excom_xp_docked();
3197 you.exp_docked_total[old_god] = you.exp_docked[old_god];
3198 break;
3199
3200 case GOD_WU_JIAN:
3201 you.attribute[ATTR_SERPENTS_LASH] = 0;
3202 if (you.props.exists(WU_JIAN_HEAVENLY_STORM_KEY))
3203 wu_jian_end_heavenly_storm();
3204 break;
3205
3206 case GOD_OKAWARU:
3207 if (you.duration[DUR_HEROISM])
3208 okawaru_remove_heroism();
3209 if (you.duration[DUR_FINESSE])
3210 okawaru_remove_finesse();
3211 break;
3212
3213 default:
3214 break;
3215 }
3216
3217 _set_wrath_penance(old_god);
3218
3219 #ifdef USE_TILE_LOCAL
3220 tiles.layout_statcol();
3221 redraw_screen();
3222 update_screen();
3223 #endif
3224
3225 // Evil hack.
3226 learned_something_new(HINT_EXCOMMUNICATE,
3227 coord_def((int)new_god, old_piety));
3228
3229 for (ability_type abil : get_god_abilities())
3230 you.skills_to_hide.insert(abil_skill(abil));
3231
3232 update_can_currently_train();
3233 reset_training();
3234
3235 // Perhaps we abandoned Trog with everything but Spellcasting maxed out.
3236 check_selected_skills();
3237 }
3238
nemelex_death_message()3239 void nemelex_death_message()
3240 {
3241 const int rank = min(random2(you.piety) / 30, 2);
3242
3243 static const char *messages[NUM_PIETY_GAIN] =
3244 {
3245 "<lightgrey>Your body disappears without a glow.</lightgrey>",
3246 "Your body glows slightly and disappears.",
3247 "<white>Your body glows with a rainbow of weird colours and disappears.</white>",
3248 };
3249
3250 static const char *glowing_messages[NUM_PIETY_GAIN] =
3251 {
3252 "<lightgrey>Your body disappears without additional glow.</lightgrey>",
3253 "Your body glows slightly brighter and disappears.",
3254 "<white>Your body glows with a rainbow of weird colours and disappears.</white>",
3255 };
3256
3257 mpr((you.backlit() ? glowing_messages : messages)[rank]);
3258 }
3259
god_hates_attacking_friend(god_type god,const monster & fr)3260 bool god_hates_attacking_friend(god_type god, const monster& fr)
3261 {
3262 if (fr.kill_alignment() != KC_FRIENDLY)
3263 return false;
3264
3265 monster_type species = fr.mons_species();
3266
3267 if (mons_is_object(species))
3268 return false;
3269 switch (god)
3270 {
3271 case GOD_ZIN:
3272 case GOD_SHINING_ONE:
3273 case GOD_ELYVILON:
3274 return true;
3275 case GOD_BEOGH: // added penance to avoid killings for loot
3276 return mons_genus(species) == MONS_ORC;
3277 case GOD_JIYVA:
3278 return mons_class_is_slime(species);
3279 case GOD_FEDHAS:
3280 return _fedhas_protects_species(species);
3281 default:
3282 return false;
3283 }
3284 }
3285
_transformed_player_can_join_god(god_type which_god)3286 static bool _transformed_player_can_join_god(god_type which_god)
3287 {
3288 if (which_god == GOD_ZIN && you.form != transformation::none)
3289 return false; // zin hates everything
3290
3291 if (is_good_god(which_god) && you.form == transformation::lich)
3292 return false;
3293
3294 return true;
3295 }
3296
gozag_service_fee()3297 int gozag_service_fee()
3298 {
3299 if (you.char_class == JOB_MONK && had_gods() == 0)
3300 return 0;
3301
3302 if (crawl_state.game_is_sprint())
3303 return 0;
3304
3305 const int gold = you.attribute[ATTR_GOLD_GENERATED];
3306 int fee = (int)(gold - gold / log10(gold + 10.0))/2;
3307
3308 dprf("found %d gold, fee %d", gold, fee);
3309 return fee;
3310 }
3311
_god_rejects_loveless(god_type god)3312 static bool _god_rejects_loveless(god_type god)
3313 {
3314 switch (god)
3315 {
3316 case GOD_BEOGH:
3317 case GOD_JIYVA:
3318 case GOD_HEPLIAKLQANA:
3319 case GOD_FEDHAS:
3320 case GOD_YREDELEMNUL:
3321 return true;
3322 default:
3323 return false;
3324 }
3325 }
3326
3327 /**
3328 * Return true if the player can worship which_god.
3329 *
3330 * @param which_god god to query
3331 * @param temp If true (default), test if you can worship which_god now.
3332 * If false, test if you may ever be able to worship the god.
3333 * @return Whether you can worship which_god.
3334 */
player_can_join_god(god_type which_god,bool temp)3335 bool player_can_join_god(god_type which_god, bool temp)
3336 {
3337 if (you.has_mutation(MUT_FORLORN))
3338 return false;
3339
3340 if (is_good_god(which_god) && you.undead_or_demonic(temp))
3341 return false;
3342
3343 if (you.has_mutation(MUT_INNATE_CASTER)
3344 && (which_god == GOD_SIF_MUNA
3345 || which_god == GOD_VEHUMET
3346 || which_god == GOD_KIKUBAAQUDGHA))
3347 {
3348 return false;
3349 }
3350
3351 if (which_god == GOD_BEOGH && !species::is_orcish(you.species))
3352 return false;
3353
3354 if (which_god == GOD_GOZAG && temp && you.gold < gozag_service_fee())
3355 return false;
3356
3357 if (you.get_base_mutation_level(MUT_NO_LOVE, true, temp, temp)
3358 && _god_rejects_loveless(which_god))
3359 {
3360 return false;
3361 }
3362
3363 #if TAG_MAJOR_VERSION == 34
3364 if (you.get_base_mutation_level(MUT_NO_ARTIFICE, true, temp, temp)
3365 && which_god == GOD_PAKELLAS)
3366 {
3367 return false;
3368 }
3369 #endif
3370
3371 return !temp || _transformed_player_can_join_god(which_god);
3372 }
3373
3374 // Handle messaging and identification for items/equipment on conversion.
_god_welcome_handle_gear()3375 static void _god_welcome_handle_gear()
3376 {
3377 // Check for amulets of faith.
3378 item_def *amulet = you.slot_item(EQ_AMULET, false);
3379 if (amulet && amulet->sub_type == AMU_FAITH && !is_useless_item(*amulet))
3380 {
3381 mprf(MSGCH_GOD, "Your amulet flashes!");
3382 flash_view_delay(UA_PLAYER, god_colour(you.religion), 300);
3383 }
3384
3385 if (have_passive(passive_t::identify_items))
3386 auto_id_inventory();
3387
3388 if (have_passive(passive_t::detect_portals))
3389 ash_detect_portals(true);
3390
3391 // Give a reminder to remove any disallowed equipment.
3392 for (int i = EQ_FIRST_EQUIP; i < NUM_EQUIP; i++)
3393 {
3394 const item_def* item = you.slot_item(static_cast<equipment_type>(i));
3395 if (item && god_hates_item(*item))
3396 {
3397 mprf(MSGCH_GOD, "%s warns you to remove %s.",
3398 uppercase_first(god_name(you.religion)).c_str(),
3399 item->name(DESC_YOUR, false, false, false).c_str());
3400 }
3401 }
3402
3403 // Refresh wielded/quivered weapons in case we have a new conduct
3404 // on them.
3405 you.wield_change = true;
3406 quiver::set_needs_redraw();
3407 }
3408
3409 /* Make a CrawlStoreValue an empty vector with the requested item type.
3410 * It is an error if the value already had a different type.
3411 */
_make_empty_vec(CrawlStoreValue & v,store_val_type vectype)3412 static void _make_empty_vec(CrawlStoreValue &v, store_val_type vectype)
3413 {
3414 const store_val_type currtype = v.get_type();
3415 ASSERT(currtype == SV_NONE || currtype == SV_VEC);
3416
3417 if (currtype == SV_NONE)
3418 v.new_vector(vectype);
3419 else
3420 {
3421 CrawlVector &vec = v.get_vector();
3422 const store_val_type old_vectype = vec.get_type();
3423 ASSERT(old_vectype == SV_NONE || old_vectype == vectype);
3424 vec.clear();
3425 }
3426 }
3427
3428 // Note: we're trying for a behaviour where the player gets
3429 // to keep their assigned invocation slots if they get excommunicated
3430 // and then rejoin (but if they spend time with another god we consider
3431 // the old invocation slots void and erase them). We also try to
3432 // protect any bindings the character might have made into the
3433 // traditional invocation slots (a-e and X). -- bwr
set_god_ability_slots()3434 void set_god_ability_slots()
3435 {
3436 ASSERT(!you_worship(GOD_NO_GOD));
3437
3438 if (find(begin(you.ability_letter_table), end(you.ability_letter_table),
3439 ABIL_RENOUNCE_RELIGION) == end(you.ability_letter_table)
3440 && you.ability_letter_table[letter_to_index('X')] == ABIL_NON_ABILITY)
3441 {
3442 you.ability_letter_table[letter_to_index('X')] = ABIL_RENOUNCE_RELIGION;
3443 }
3444
3445 // Clear out other god invocations.
3446 for (ability_type& slot : you.ability_letter_table)
3447 {
3448 for (god_iterator it; it; ++it)
3449 {
3450 if (slot == ABIL_NON_ABILITY)
3451 break;
3452 if (*it == you.religion)
3453 continue;
3454 for (const god_power& power : god_powers[*it])
3455 if (slot == power.abil)
3456 slot = ABIL_NON_ABILITY;
3457 }
3458 }
3459
3460 int num = letter_to_index('a');
3461 // Not using get_god_powers, so that hotkeys remain stable across games
3462 // even if you can't use a particular ability in a given game.
3463 for (const god_power& power : god_powers[you.religion])
3464 {
3465 if (power.abil != ABIL_NON_ABILITY
3466 // Animate Dead doesn't have its own hotkey; it steals
3467 // Animate Remains'
3468 && power.abil != ABIL_YRED_ANIMATE_DEAD
3469 // hep ident goes to G, so don't take b for it (hack alert)
3470 && power.abil != ABIL_HEPLIAKLQANA_IDENTITY
3471 && find(begin(you.ability_letter_table),
3472 end(you.ability_letter_table), power.abil)
3473 == end(you.ability_letter_table)
3474 && you.ability_letter_table[num] == ABIL_NON_ABILITY)
3475 {
3476 // Assign sequentially: first ability 'a', third ability 'c',
3477 // etc., even if one is remapped.
3478 if (find_ability_slot(power.abil, index_to_letter(num)) < 0)
3479 {
3480 you.ability_letter_table[num] = power.abil;
3481 auto_assign_ability_slot(num);
3482 }
3483 ++num;
3484 }
3485 }
3486 }
3487
3488 /// Check if the monk's joining bonus should be given. (Except Gozag's.)
_apply_monk_bonus()3489 static void _apply_monk_bonus()
3490 {
3491 if (you.char_class != JOB_MONK || had_gods() > 0)
3492 return;
3493
3494 // monks get bonus piety for first god
3495 if (you_worship(GOD_RU))
3496 you.props[RU_SACRIFICE_PROGRESS_KEY] = 9999;
3497 else if (you_worship(GOD_ASHENZARI))
3498 {
3499 // two curses in (somewhat) rapid succession
3500 ashenzari_offer_new_curse();
3501 you.props[ASHENZARI_CURSE_PROGRESS_KEY] = 19;
3502 }
3503 else if (you_worship(GOD_USKAYAW)) // Gaining piety past this point does nothing
3504 gain_piety(15, 1, false); // of value with this god and looks weird.
3505 else
3506 gain_piety(35, 1, false);
3507 }
3508
3509 /// Transfer some piety from an old good god to a new one, if applicable.
_transfer_good_god_piety()3510 static void _transfer_good_god_piety()
3511 {
3512 if (!is_good_god(you.religion))
3513 return;
3514
3515 const god_type old_god = you.previous_good_god;
3516 const uint8_t old_piety = you.saved_good_god_piety;
3517
3518 if (!is_good_god(old_god))
3519 return;
3520
3521 if (you.religion != old_god)
3522 {
3523 static const map<god_type, const char*> farewell_messages = {
3524 { GOD_ELYVILON, "aid the meek" },
3525 { GOD_SHINING_ONE, "vanquish evil" },
3526 { GOD_ZIN, "enforce order" },
3527 };
3528
3529 // Some feedback that piety moved over.
3530 simple_god_message(make_stringf(" says: Farewell. Go and %s with %s.",
3531 lookup(farewell_messages, you.religion,
3532 "become a bug"),
3533 god_name(you.religion).c_str()).c_str(),
3534
3535 old_god);
3536 }
3537
3538 // Give a piety bonus when switching between good gods, or back to the
3539 // same good god.
3540 if (old_piety > piety_breakpoint(0))
3541 gain_piety(old_piety - piety_breakpoint(0), 2, false);
3542 }
3543
3544
3545 /**
3546 * Give an appropriate message for the given good god to give in response to
3547 * the player joining a god that brings down their wrath.
3548 *
3549 * @param good_god The good god in question.
3550 */
_good_god_wrath_message(god_type good_god)3551 static string _good_god_wrath_message(god_type good_god)
3552 {
3553 switch (good_god)
3554 {
3555 case GOD_ELYVILON:
3556 return "Your evil deeds will not go unpunished";
3557 case GOD_SHINING_ONE:
3558 return "You will pay for your evil ways, mortal";
3559 case GOD_ZIN:
3560 return make_stringf("You will suffer for embracing such %s",
3561 is_chaotic_god(you.religion) ? "chaos"
3562 : "evil");
3563 default:
3564 return "You will be buggily punished for this";
3565 }
3566 }
3567
3568 /**
3569 * Check if joining the current god will cause wrath for any previously-
3570 * worshipped good gods. If so, message & set penance timeouts.
3571 *
3572 * @param old_god The previous god worshipped; may be GOD_NO_GOD.
3573 */
_check_good_god_wrath(god_type old_god)3574 static void _check_good_god_wrath(god_type old_god)
3575 {
3576 for (god_type good_god : { GOD_ELYVILON, GOD_SHINING_ONE, GOD_ZIN })
3577 {
3578 if (old_god == good_god || !you.penance[good_god]
3579 || !god_hates_your_god(good_god, you.religion))
3580 {
3581 continue;
3582 }
3583
3584 const string wrath_message
3585 = make_stringf(" says: %s!",
3586 _good_god_wrath_message(good_god).c_str());
3587 simple_god_message(wrath_message.c_str(), good_god);
3588 set_penance_xp_timeout();
3589 }
3590 }
3591
initialize_ashenzari_props()3592 void initialize_ashenzari_props()
3593 {
3594 if (!you.props.exists(ASHENZARI_CURSE_PROGRESS_KEY))
3595 you.props[ASHENZARI_CURSE_PROGRESS_KEY] = 0;
3596 if (!you.props.exists(ASHENZARI_CURSE_DELAY_KEY))
3597 {
3598 int delay = 20;
3599 if (crawl_state.game_is_sprint())
3600 delay /= SPRINT_MULTIPLIER;
3601 you.props[ASHENZARI_CURSE_DELAY_KEY] = delay;
3602 }
3603 }
3604
3605 /// Handle basic god piety & related setup for a new-joined god.
_set_initial_god_piety()3606 static void _set_initial_god_piety()
3607 {
3608 // Currently, penance is just zeroed. This could be much more
3609 // interesting.
3610 you.penance[you.religion] = 0;
3611
3612 switch (you.religion)
3613 {
3614 case GOD_XOM:
3615 // Xom uses piety and gift_timeout differently.
3616 you.piety = HALF_MAX_PIETY;
3617 you.gift_timeout = random2(40) + random2(40);
3618 break;
3619
3620 case GOD_ASHENZARI:
3621 you.piety = ASHENZARI_BASE_PIETY;
3622 you.piety_hysteresis = 0;
3623 you.gift_timeout = 0;
3624 initialize_ashenzari_props();
3625 break;
3626
3627 case GOD_RU:
3628 you.piety = 10; // one moderate sacrifice should get you to *.
3629 you.piety_hysteresis = 0;
3630 you.gift_timeout = 0;
3631
3632 // I'd rather this be in on_join(), but then it overrides the
3633 // monk bonus...
3634 you.props[RU_SACRIFICE_PROGRESS_KEY] = 0;
3635 // offer the first sacrifice faster than normal
3636 {
3637 int delay = 50;
3638 if (crawl_state.game_is_sprint())
3639 delay /= SPRINT_MULTIPLIER;
3640 you.props[RU_SACRIFICE_DELAY_KEY] = delay;
3641 }
3642 you.props[RU_SACRIFICE_PENALTY_KEY] = 0;
3643 break;
3644
3645 default:
3646 you.piety = 15; // to prevent near instant excommunication
3647 if (you.piety_max[you.religion] < 15)
3648 you.piety_max[you.religion] = 15;
3649 you.piety_hysteresis = 0;
3650 you.gift_timeout = 0;
3651 break;
3652 }
3653
3654 // Tutorial needs berserk usable.
3655 if (crawl_state.game_is_tutorial())
3656 gain_piety(30, 1, false);
3657
3658 _apply_monk_bonus();
3659 _transfer_good_god_piety();
3660 }
3661
3662 /// Setup when joining the greedy magnates of Gozag.
_join_gozag()3663 static void _join_gozag()
3664 {
3665 // Handle the fee.
3666 const int fee = gozag_service_fee();
3667 if (fee > 0)
3668 {
3669 ASSERT(you.gold >= fee);
3670 mprf(MSGCH_GOD, "You pay a service fee of %d gold.", fee);
3671 you.gold -= fee;
3672 you.attribute[ATTR_GOZAG_GOLD_USED] += fee;
3673 }
3674 else
3675 simple_god_message(" waives the service fee.");
3676
3677 // Note relevant powers.
3678 bool needs_redraw = false;
3679 for (const auto& power : get_god_powers(you.religion))
3680 {
3681 if (you.gold >= get_gold_cost(power.abil))
3682 {
3683 power.display(true, "You have enough gold to %s.");
3684 needs_redraw = true;
3685 }
3686 }
3687
3688 if (needs_redraw)
3689 {
3690 #ifdef USE_TILE_LOCAL
3691 tiles.layout_statcol();
3692 redraw_screen();
3693 update_screen();
3694 #else
3695 ;
3696 #endif
3697 }
3698
3699 // Move gold to top of piles & detect it.
3700 add_daction(DACT_GOLD_ON_TOP);
3701 }
3702
3703 /// Setup when joining the gelatinous groupies of Jiyva.
_join_jiyva()3704 static void _join_jiyva()
3705 {
3706 // Complimentary jelly upon joining.
3707 if (_has_jelly())
3708 return;
3709
3710 mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, you.pos());
3711 mg.set_summoned(&you, 0, 0, GOD_JIYVA);
3712
3713 delayed_monster(mg);
3714 simple_god_message(" grants you a jelly!");
3715 }
3716
3717 /// Setup when joining the sacred cult of Ru.
_join_ru()3718 static void _join_ru()
3719 {
3720 _make_empty_vec(you.props[AVAILABLE_SAC_KEY], SV_INT);
3721 _make_empty_vec(you.props[HEALTH_SAC_KEY], SV_INT);
3722 _make_empty_vec(you.props[ESSENCE_SAC_KEY], SV_INT);
3723 _make_empty_vec(you.props[PURITY_SAC_KEY], SV_INT);
3724 _make_empty_vec(you.props[ARCANA_SAC_KEY], SV_INT);
3725 }
3726
3727 /// Setup for joining the furious barbarians of Trog.
join_trog_skills()3728 void join_trog_skills()
3729 {
3730 if (!you.has_mutation(MUT_DISTRIBUTED_TRAINING))
3731 for (int sk = SK_SPELLCASTING; sk <= SK_LAST_MAGIC; ++sk)
3732 you.train[sk] = you.train_alt[sk] = TRAINING_DISABLED;
3733 }
3734
3735 // Setup for joining the orderly ascetics of Zin.
_join_zin()3736 static void _join_zin()
3737 {
3738 // Need to pay St. Peters.
3739 if (you.attribute[ATTR_DONATIONS] * 9 < you.gold)
3740 {
3741 item_def lucre;
3742 lucre.base_type = OBJ_GOLD;
3743 // If you worshipped Zin before, the already tithed for part is fine.
3744 lucre.quantity = you.gold - you.attribute[ATTR_DONATIONS] * 9;
3745 // Use the harsh acquirement pricing -- with a cap at +50 piety.
3746 // We don't want you get max piety at start just because you're filthy
3747 // rich. In that case, you have to donate again more... That the poor
3748 // widow is not spared doesn't mean the rich can't be milked for more.
3749 lucre.props[ACQUIRE_KEY] = 0;
3750 you.gold -= zin_tithe(lucre, lucre.quantity, true);
3751 }
3752 }
3753
3754 #if TAG_MAJOR_VERSION == 34
3755 // Setup when becoming an overworked assistant to Pakellas.
_join_pakellas()3756 static void _join_pakellas()
3757 {
3758 mprf(MSGCH_GOD, "You stop regenerating magic.");
3759 you.attribute[ATTR_PAKELLAS_EXTRA_MP] = POT_MAGIC_MP;
3760 }
3761 #endif
3762
3763 // Setup for joining the easygoing followers of Cheibriados.
_join_cheibriados()3764 static void _join_cheibriados()
3765 {
3766 simple_god_message(" begins to support your attributes as your "
3767 "movement slows.");
3768 notify_stat_change();
3769 }
3770
3771 /// What special things happen when you join a god?
3772 static const map<god_type, function<void ()>> on_join = {
3773 { GOD_BEOGH, update_player_symbol },
3774 { GOD_CHEIBRIADOS, _join_cheibriados },
__anon576266bf0202() 3775 { GOD_FEDHAS, []() {
3776 mprf(MSGCH_MONSTER_ENCHANT, "The plants of the dungeon cease their "
3777 "hostilities.");
3778 if (env.forest_awoken_until)
3779 for (monster_iterator mi; mi; ++mi)
3780 mi->del_ench(ENCH_AWAKEN_FOREST);
3781 }},
3782 { GOD_GOZAG, _join_gozag },
3783 { GOD_JIYVA, _join_jiyva },
__anon576266bf0302() 3784 { GOD_LUGONU, []() {
3785 if (you.worshipped[GOD_LUGONU] == 0)
3786 gain_piety(20, 1, false); // allow instant access to first power
3787 }},
3788 #if TAG_MAJOR_VERSION == 34
3789 { GOD_PAKELLAS, _join_pakellas },
3790 #endif
3791 { GOD_RU, _join_ru },
3792 { GOD_TROG, join_trog_skills },
3793 { GOD_ZIN, _join_zin },
3794 };
3795
join_religion(god_type which_god)3796 void join_religion(god_type which_god)
3797 {
3798 ASSERT(which_god != GOD_NO_GOD);
3799 ASSERT(which_god != GOD_ECUMENICAL);
3800 ASSERT(!you.has_mutation(MUT_FORLORN));
3801
3802 redraw_screen();
3803 update_screen();
3804
3805 const god_type old_god = you.religion;
3806 if (you.previous_good_god == GOD_NO_GOD)
3807 {
3808 you.previous_good_god = old_god;
3809 you.saved_good_god_piety = you.piety;
3810 // doesn't matter if old_god isn't actually a good god; we check later
3811 // and then wipe it at the end of the function regardless
3812 }
3813
3814 // Leave your prior religion first.
3815 if (!you_worship(GOD_NO_GOD))
3816 excommunication(true, which_god);
3817
3818 // Welcome to the fold!
3819 you.religion = static_cast<god_type>(which_god);
3820 set_god_ability_slots(); // remove old god's slots, reserve new god's
3821
3822 mark_milestone("god.worship", "became a worshipper of "
3823 + god_name(you.religion) + ".");
3824 take_note(Note(NOTE_GET_GOD, you.religion));
3825
3826 simple_god_message(make_stringf(" welcomes you%s!",
3827 you.worshipped[which_god] ? " back"
3828 : "").c_str());
3829 // included in default force_more_message
3830 #ifdef DGL_WHEREIS
3831 whereis_record();
3832 #endif
3833
3834 _set_initial_god_piety();
3835
3836 const function<void ()> *join_effect = map_find(on_join, you.religion);
3837 if (join_effect != nullptr)
3838 (*join_effect)();
3839
3840 // after join_effect() so that gozag's service fee is right for monks
3841 if (you.worshipped[you.religion] < 100)
3842 you.worshipped[you.religion]++;
3843
3844 // after join_effect so that ru is initialized correctly for get_abilities
3845 // when flash_view_delay redraws the screen in local tiles
3846 _god_welcome_handle_gear();
3847
3848 // Warn if a good god is starting wrath now.
3849 _check_good_god_wrath(old_god);
3850
3851 if (!you_worship(GOD_GOZAG))
3852 for (const auto& power : get_god_powers(you.religion))
3853 if (power.rank <= 0)
3854 power.display(true, "You can now %s.");
3855
3856 // Allow training all divine ability skills immediately.
3857 vector<ability_type> abilities = get_god_abilities();
3858 for (ability_type abil : abilities)
3859 you.skills_to_show.insert(abil_skill(abil));
3860 update_can_currently_train();
3861
3862 // now that you have a god, you can't save any piety from your prev god
3863 you.previous_good_god = GOD_NO_GOD;
3864 you.saved_good_god_piety = 0;
3865
3866 you.redraw_title = true;
3867
3868 #ifdef USE_TILE_LOCAL
3869 tiles.layout_statcol();
3870 redraw_screen();
3871 update_screen();
3872 #endif
3873
3874 learned_something_new(HINT_CONVERT);
3875 }
3876
god_pitch(god_type which_god)3877 void god_pitch(god_type which_god)
3878 {
3879 if (which_god == GOD_BEOGH && env.grid(you.pos()) != DNGN_ALTAR_BEOGH)
3880 mpr("You bow before the missionary of Beogh.");
3881 else
3882 {
3883 mprf("You %s the altar of %s.",
3884 get_form()->player_prayer_action().c_str(),
3885 god_name(which_god).c_str());
3886 }
3887 // these are included in default force_more_message
3888
3889 const int fee = (which_god == GOD_GOZAG) ? gozag_service_fee() : 0;
3890
3891 // Note: using worship we could make some gods not allow followers to
3892 // return, or not allow worshippers from other religions. - bwr
3893
3894 // Gods can be racist...
3895 if (!player_can_join_god(which_god))
3896 {
3897 you.turn_is_over = false;
3898 if (which_god == GOD_GOZAG)
3899 {
3900 simple_god_message(" does not accept service from beggars like you!",
3901 which_god);
3902 if (you.gold == 0)
3903 {
3904 mprf("The service fee for joining is currently %d gold; you have"
3905 " none.", fee);
3906 }
3907 else
3908 {
3909 mprf("The service fee for joining is currently %d gold; you only"
3910 " have %d.", fee, you.gold);
3911 }
3912 }
3913 else if (you.get_mutation_level(MUT_NO_LOVE)
3914 && _god_rejects_loveless(which_god))
3915 {
3916 simple_god_message(" does not accept worship from the loveless!",
3917 which_god);
3918 }
3919 #if TAG_MAJOR_VERSION == 34
3920 else if (you.get_mutation_level(MUT_NO_ARTIFICE)
3921 && which_god == GOD_PAKELLAS)
3922 {
3923 simple_god_message(" does not accept worship from those who are "
3924 "unable to use magical devices!", which_god);
3925 }
3926 #endif
3927 else if (!_transformed_player_can_join_god(which_god))
3928 {
3929 simple_god_message(" says: How dare you approach in such a "
3930 "loathsome form!",
3931 which_god);
3932 }
3933 else
3934 {
3935 simple_god_message(" does not accept worship from those such as"
3936 " you!",
3937 which_god);
3938 }
3939 return;
3940 }
3941
3942 if (which_god == GOD_LUGONU && you.penance[GOD_LUGONU])
3943 {
3944 you.turn_is_over = false;
3945 simple_god_message(" refuses to forgive you so easily!", which_god);
3946 return;
3947 }
3948
3949 if (describe_god_with_join(which_god))
3950 join_religion(which_god);
3951 else
3952 {
3953 you.turn_is_over = false;
3954 redraw_screen();
3955 update_screen();
3956 }
3957 }
3958
3959 /** Ask the user for a god by name.
3960 *
3961 * @param def_god The god to use if the user presses just ENTER
3962 * (default NUM_GODS).
3963 * @return the best match for the user's input, or def_god if the user
3964 * pressed ENTER without providing input, or NUM_GODS if the
3965 * user cancelled or there was no match.
3966 */
choose_god(god_type def_god)3967 god_type choose_god(god_type def_god)
3968 {
3969 char specs[80];
3970
3971 string help = def_god == NUM_GODS ? "by name"
3972 : "default " + god_name(def_god);
3973 string prompt = make_stringf("Which god (%s)? ", help.c_str());
3974
3975 if (msgwin_get_line(prompt, specs, sizeof(specs)) != 0)
3976 return NUM_GODS; // FIXME: distinguish cancellation from no match
3977
3978 // If they pressed enter with no input.
3979 if (specs[0] == '\0')
3980 return def_god;
3981
3982 string spec = lowercase_string(specs);
3983
3984 return find_earliest_match(spec, GOD_NO_GOD, NUM_GODS,
3985 always_true<god_type>,
3986 bind(god_name, placeholders::_1, false));
3987 }
3988
had_gods()3989 int had_gods()
3990 {
3991 int count = 0;
3992 for (god_iterator it; it; ++it)
3993 count += you.worshipped[*it];
3994 return count;
3995 }
3996
god_likes_your_god(god_type god,god_type your_god)3997 bool god_likes_your_god(god_type god, god_type your_god)
3998 {
3999 return is_good_god(god) && is_good_god(your_god);
4000 }
4001
god_hates_your_god(god_type god,god_type your_god)4002 bool god_hates_your_god(god_type god, god_type your_god)
4003 {
4004 // Ru doesn't care.
4005 if (god == GOD_RU)
4006 return false;
4007
4008 // Gods do not hate themselves.
4009 if (god == your_god)
4010 return false;
4011
4012 // Non-good gods always hate your current god.
4013 if (!is_good_god(god))
4014 return true;
4015
4016 // Zin hates chaotic gods.
4017 if (god == GOD_ZIN && is_chaotic_god(your_god))
4018 return true;
4019
4020 return is_evil_god(your_god);
4021 }
4022
god_hates_killing(god_type god,const monster & mon)4023 bool god_hates_killing(god_type god, const monster& mon)
4024 {
4025 if (invalid_monster(&mon))
4026 return false;
4027 // Must be at least a creature of sorts. Smacking down an enchanted
4028 // weapon or disrupting a lightning doesn't count. Technically, this
4029 // might raise a concern about necromancy but zombies traditionally
4030 // count as creatures and that's the average person's (even if not ours)
4031 // intuition.
4032 if (mons_is_object(mon.type))
4033 return false;
4034
4035 // kill as many illusions as you want.
4036 if (mon.is_illusion())
4037 return false;
4038
4039 bool retval = false;
4040 const mon_holy_type holiness = mon.holiness();
4041
4042 if (holiness & MH_HOLY)
4043 retval = (is_good_god(god));
4044 else if (holiness & MH_NATURAL)
4045 retval = (god == GOD_ELYVILON);
4046
4047 if (god == GOD_FEDHAS)
4048 retval = (fedhas_protects(&mon));
4049
4050 return retval;
4051 }
4052
god_likes_spell(spell_type spell,god_type god)4053 bool god_likes_spell(spell_type spell, god_type god)
4054 {
4055 switch (god)
4056 {
4057 case GOD_VEHUMET:
4058 return vehumet_supports_spell(spell);
4059 case GOD_KIKUBAAQUDGHA:
4060 return spell_typematch(spell, spschool::necromancy);
4061 default: // quash unhandled constants warnings
4062 return false;
4063 }
4064 }
4065
4066 /**
4067 * Does your god hate spellcasting?
4068 *
4069 * @param god The god to check against
4070 * @return Whether the god hates spellcasting
4071 */
god_hates_spellcasting(god_type god)4072 bool god_hates_spellcasting(god_type god)
4073 {
4074 return god == GOD_TROG;
4075 }
4076
4077 /**
4078 * Will your god put you under penance if you actually cast spell?
4079 *
4080 * @param spell The spell to check against
4081 * @param god The god to check against
4082 * @param fake_spell true if the spell is evoked or from an innate or divine ability
4083 * false if it is a spell being cast normally.
4084 * @return true if the god hates the spell
4085 */
god_hates_spell(spell_type spell,god_type god,bool fake_spell)4086 bool god_hates_spell(spell_type spell, god_type god, bool fake_spell)
4087 {
4088 if (god_hates_spellcasting(god))
4089 return !fake_spell;
4090
4091 if (god_punishes_spell(spell, god))
4092 return true;
4093
4094 switch (god)
4095 {
4096 case GOD_CHEIBRIADOS:
4097 if (is_hasty_spell(spell))
4098 return true;
4099 break;
4100 #if TAG_MAJOR_VERSION == 34
4101 case GOD_PAKELLAS:
4102 if (spell == SPELL_SUBLIMATION_OF_BLOOD)
4103 return true;
4104 break;
4105 #endif
4106 default:
4107 break;
4108 }
4109 return false;
4110 }
4111
4112 /**
4113 * Will your god excommunicate you if you actually cast spell?
4114 *
4115 * @param spell The spell to check against
4116 * @param god The god to check against
4117 * @return Whether the god loathes the spell
4118 */
god_loathes_spell(spell_type spell,god_type god)4119 bool god_loathes_spell(spell_type spell, god_type god)
4120 {
4121 if (spell == SPELL_NECROMUTATION && is_good_god(god))
4122 return true;
4123 return false;
4124 }
4125
4126 /**
4127 * Checks to see if your god hates or loathes this spell,
4128 * or just hates spellcasting in general, and returns a warning string
4129 *
4130 * @param spell The spell to check against
4131 * @param god The god to check against
4132 * @return Warning string if god has strong opinions on spell
4133 * Empty string if god doesn't care about spell
4134 */
god_spell_warn_string(spell_type spell,god_type god)4135 string god_spell_warn_string(spell_type spell, god_type god)
4136 {
4137 if (god_loathes_spell(spell, god))
4138 return "Your god extremely despises this spell!";
4139 else if (god_hates_spellcasting(god))
4140 return "Your god hates spellcasting!";
4141 else if (god_hates_spell(spell, god))
4142 return "Your god hates this spell!";
4143 else
4144 return "";
4145 }
4146
god_hates_ability(ability_type ability,god_type god)4147 bool god_hates_ability(ability_type ability, god_type god)
4148 {
4149 switch (ability)
4150 {
4151 case ABIL_EVOKE_BERSERK:
4152 return god == GOD_CHEIBRIADOS;
4153 default:
4154 break;
4155 }
4156 return false;
4157 }
4158
elyvilon_lifesaving()4159 lifesaving_chance elyvilon_lifesaving()
4160 {
4161 if (!you_worship(GOD_ELYVILON))
4162 return lifesaving_chance::never;
4163
4164 if (you.piety < piety_breakpoint(0))
4165 return lifesaving_chance::never;
4166
4167 return you.piety >= piety_breakpoint(4) ? lifesaving_chance::always
4168 : lifesaving_chance::sometimes;
4169 }
4170
god_protects_from_harm()4171 bool god_protects_from_harm()
4172 {
4173 if (you.duration[DUR_LIFESAVING])
4174 {
4175 switch (elyvilon_lifesaving())
4176 {
4177 case lifesaving_chance::sometimes:
4178 if (random2(you.piety) >= piety_breakpoint(0))
4179 return true;
4180 break;
4181 case lifesaving_chance::always:
4182 // Reliable lifesaving is costly.
4183 lose_piety(21 + random2(20));
4184 return true;
4185 default:
4186 break;
4187 }
4188 }
4189
4190 if (have_passive(passive_t::protect_from_harm)
4191 && (one_chance_in(10) || x_chance_in_y(you.piety, 1000)))
4192 {
4193 return true;
4194 }
4195
4196 return false;
4197 }
4198
handle_god_time(int)4199 void handle_god_time(int /*time_delta*/)
4200 {
4201 if (you.attribute[ATTR_GOD_WRATH_COUNT] > 0)
4202 {
4203 vector<god_type> angry_gods;
4204 // First count the number of gods to whom we owe penance.
4205 for (god_iterator it; it; ++it)
4206 {
4207 if (active_penance(*it))
4208 angry_gods.push_back(*it);
4209 }
4210 if (x_chance_in_y(angry_gods.size(), 20))
4211 {
4212 // This should be guaranteed; otherwise the god wouldn't have
4213 // appeared in the angry_gods list.
4214 const bool succ = divine_retribution(*random_iterator(angry_gods));
4215 ASSERT(succ);
4216 }
4217 you.attribute[ATTR_GOD_WRATH_COUNT]--;
4218 }
4219
4220 // Update the god's opinion of the player.
4221 if (!you_worship(GOD_NO_GOD))
4222 {
4223 int delay;
4224 int sacrifice_count;
4225 switch (you.religion)
4226 {
4227 case GOD_TROG:
4228 case GOD_OKAWARU:
4229 case GOD_MAKHLEB:
4230 case GOD_BEOGH:
4231 case GOD_LUGONU:
4232 case GOD_DITHMENOS:
4233 case GOD_QAZLAL:
4234 case GOD_YREDELEMNUL:
4235 case GOD_KIKUBAAQUDGHA:
4236 case GOD_VEHUMET:
4237 case GOD_ZIN:
4238 #if TAG_MAJOR_VERSION == 34
4239 case GOD_PAKELLAS:
4240 #endif
4241 case GOD_JIYVA:
4242 case GOD_WU_JIAN:
4243 case GOD_SIF_MUNA:
4244 if (one_chance_in(17))
4245 lose_piety(1);
4246 break;
4247
4248 case GOD_ELYVILON:
4249 case GOD_HEPLIAKLQANA:
4250 case GOD_FEDHAS:
4251 case GOD_CHEIBRIADOS:
4252 case GOD_SHINING_ONE:
4253 case GOD_NEMELEX_XOBEH:
4254 if (one_chance_in(35))
4255 lose_piety(1);
4256 break;
4257
4258 case GOD_ASHENZARI:
4259 ASSERT(you.props.exists(ASHENZARI_CURSE_PROGRESS_KEY));
4260 ASSERT(you.props.exists(ASHENZARI_CURSE_DELAY_KEY));
4261
4262 if (you.props[ASHENZARI_CURSE_PROGRESS_KEY].get_int()
4263 >= you.props[ASHENZARI_CURSE_DELAY_KEY].get_int())
4264 {
4265 ashenzari_offer_new_curse();
4266 }
4267 break;
4268
4269 case GOD_RU:
4270 ASSERT(you.props.exists(RU_SACRIFICE_PROGRESS_KEY));
4271 ASSERT(you.props.exists(RU_SACRIFICE_DELAY_KEY));
4272 ASSERT(you.props.exists(AVAILABLE_SAC_KEY));
4273
4274 delay = you.props[RU_SACRIFICE_DELAY_KEY].get_int();
4275 sacrifice_count = you.props[AVAILABLE_SAC_KEY].get_vector().size();
4276
4277 // 6* is max piety for Ru
4278 if (sacrifice_count == 0 && you.piety < piety_breakpoint(5)
4279 && you.props[RU_SACRIFICE_PROGRESS_KEY].get_int() >= delay)
4280 {
4281 ru_offer_new_sacrifices();
4282 }
4283
4284 break;
4285
4286 case GOD_USKAYAW:
4287 // We handle Uskayaw elsewhere because this func gets called rarely
4288 case GOD_GOZAG:
4289 case GOD_XOM:
4290 // Gods without normal piety do nothing each tick.
4291 return;
4292
4293 case GOD_NO_GOD:
4294 case GOD_RANDOM:
4295 case GOD_ECUMENICAL:
4296 case GOD_NAMELESS:
4297 case NUM_GODS:
4298 die("Bad god, no bishop!");
4299 return;
4300
4301 }
4302
4303 if (you.piety < 1)
4304 excommunication();
4305 }
4306 }
4307
god_colour(god_type god)4308 int god_colour(god_type god) // mv - added
4309 {
4310 switch (god)
4311 {
4312 case GOD_ZIN:
4313 case GOD_SHINING_ONE:
4314 case GOD_ELYVILON:
4315 case GOD_OKAWARU:
4316 case GOD_FEDHAS:
4317 return CYAN;
4318
4319 case GOD_YREDELEMNUL:
4320 case GOD_KIKUBAAQUDGHA:
4321 case GOD_MAKHLEB:
4322 case GOD_VEHUMET:
4323 case GOD_TROG:
4324 case GOD_BEOGH:
4325 case GOD_LUGONU:
4326 case GOD_ASHENZARI:
4327 case GOD_WU_JIAN:
4328 return LIGHTRED;
4329
4330 case GOD_GOZAG:
4331 case GOD_XOM:
4332 return YELLOW;
4333
4334 case GOD_NEMELEX_XOBEH:
4335 return LIGHTMAGENTA;
4336
4337 case GOD_SIF_MUNA:
4338 return LIGHTBLUE;
4339
4340 case GOD_JIYVA:
4341 return GREEN;
4342
4343 case GOD_CHEIBRIADOS:
4344 case GOD_HEPLIAKLQANA:
4345 return LIGHTCYAN;
4346
4347 case GOD_DITHMENOS:
4348 case GOD_USKAYAW:
4349 return MAGENTA;
4350
4351 case GOD_QAZLAL:
4352 case GOD_RU:
4353 return BROWN;
4354
4355 #if TAG_MAJOR_VERSION == 34
4356 case GOD_PAKELLAS:
4357 return LIGHTGREEN;
4358 #endif
4359
4360 case GOD_NO_GOD:
4361 case NUM_GODS:
4362 case GOD_RANDOM:
4363 case GOD_NAMELESS:
4364 default:
4365 break;
4366 }
4367
4368 return YELLOW;
4369 }
4370
god_message_altar_colour(god_type god)4371 colour_t god_message_altar_colour(god_type god)
4372 {
4373 int rnd;
4374
4375 switch (god)
4376 {
4377 case GOD_SHINING_ONE:
4378 return YELLOW;
4379
4380 case GOD_ZIN:
4381 return WHITE;
4382
4383 case GOD_ELYVILON:
4384 return LIGHTBLUE; // Really, LIGHTGREY but that's plain text.
4385
4386 case GOD_OKAWARU:
4387 return CYAN;
4388
4389 case GOD_YREDELEMNUL:
4390 return random_choose(DARKGREY, RED);
4391
4392 case GOD_BEOGH:
4393 return random_choose(BROWN, LIGHTRED);
4394
4395 case GOD_KIKUBAAQUDGHA:
4396 return DARKGREY;
4397
4398 case GOD_FEDHAS:
4399 return random_choose(BROWN, GREEN);
4400
4401 case GOD_XOM:
4402 return random2(15) + 1;
4403
4404 case GOD_VEHUMET:
4405 rnd = random2(3);
4406 return (rnd == 0) ? LIGHTMAGENTA :
4407 (rnd == 1) ? LIGHTRED
4408 : LIGHTBLUE;
4409
4410 case GOD_MAKHLEB:
4411 rnd = random2(3);
4412 return (rnd == 0) ? RED :
4413 (rnd == 1) ? LIGHTRED
4414 : YELLOW;
4415
4416 case GOD_TROG:
4417 return RED;
4418
4419 case GOD_NEMELEX_XOBEH:
4420 return LIGHTMAGENTA;
4421
4422 case GOD_SIF_MUNA:
4423 return BLUE;
4424
4425 case GOD_LUGONU:
4426 case GOD_WU_JIAN:
4427 return LIGHTRED;
4428
4429 case GOD_CHEIBRIADOS:
4430 return LIGHTCYAN;
4431
4432 case GOD_JIYVA:
4433 return random_choose(GREEN, LIGHTGREEN);
4434
4435 case GOD_DITHMENOS:
4436 return MAGENTA;
4437
4438 case GOD_GOZAG:
4439 return random_choose(YELLOW, BROWN);
4440
4441 case GOD_QAZLAL:
4442 case GOD_RU:
4443 return BROWN;
4444
4445 #if TAG_MAJOR_VERSION == 34
4446 case GOD_PAKELLAS:
4447 return random_choose(LIGHTMAGENTA, LIGHTGREEN, LIGHTCYAN);
4448 #endif
4449
4450 case GOD_USKAYAW:
4451 return random_choose(RED, MAGENTA);
4452
4453 case GOD_HEPLIAKLQANA:
4454 return random_choose(LIGHTGREEN, LIGHTBLUE);
4455
4456 default:
4457 return YELLOW;
4458 }
4459 }
4460
piety_rank(int piety)4461 int piety_rank(int piety)
4462 {
4463 // XXX: this seems to be used only in dat/database/godspeak.txt?
4464 if (you_worship(GOD_XOM))
4465 {
4466 const int breakpoints[] = { 20, 50, 80, 120, 180, INT_MAX };
4467 for (unsigned int i = 0; i < ARRAYSZ(breakpoints); ++i)
4468 if (piety <= breakpoints[i])
4469 return i + 1;
4470 die("INT_MAX is no good");
4471 }
4472
4473 for (int i = NUM_PIETY_STARS; i >= 1; --i)
4474 if (piety >= piety_breakpoint(i - 1))
4475 return i;
4476
4477 return 0;
4478 }
4479
piety_breakpoint(int i)4480 int piety_breakpoint(int i)
4481 {
4482 int breakpoints[NUM_PIETY_STARS] = { 30, 50, 75, 100, 120, 160 };
4483 if (i >= NUM_PIETY_STARS || i < 0)
4484 return 255;
4485 else
4486 return breakpoints[i];
4487 }
4488
get_monster_tension(const monster & mons,god_type god)4489 int get_monster_tension(const monster& mons, god_type god)
4490 {
4491 if (!mons.alive())
4492 return 0;
4493
4494 if (you.see_cell(mons.pos()))
4495 {
4496 if (!mons_can_hurt_player(&mons))
4497 return 0;
4498 }
4499
4500 const mon_attitude_type att = mons_attitude(mons);
4501 if (att == ATT_GOOD_NEUTRAL || att == ATT_NEUTRAL)
4502 return 0;
4503
4504 if (mons.cannot_act() || mons.asleep() || mons_is_fleeing(mons))
4505 return 0;
4506
4507 int exper = exper_value(mons);
4508 if (exper <= 0)
4509 return 0;
4510
4511 // Almost dead monsters don't count as much.
4512 exper *= mons.hit_points;
4513 exper /= mons.max_hit_points;
4514
4515 bool gift = false;
4516
4517 if (god != GOD_NO_GOD)
4518 gift = mons_is_god_gift(mons, god);
4519
4520 if (att == ATT_HOSTILE)
4521 {
4522 // God is punishing you with a hostile gift, so it doesn't
4523 // count towards tension.
4524 if (gift)
4525 return 0;
4526 }
4527 else if (att == ATT_FRIENDLY)
4528 {
4529 // Friendly monsters being around to help you reduce
4530 // tension.
4531 exper = -exper;
4532
4533 // If it's a god gift, it reduces tension even more, since
4534 // the god is already helping you out.
4535 if (gift)
4536 exper *= 2;
4537 }
4538
4539 if (att != ATT_FRIENDLY)
4540 {
4541 if (!you.visible_to(&mons))
4542 exper /= 2;
4543 if (!mons.visible_to(&you))
4544 exper *= 2;
4545 }
4546
4547 if (mons.confused() || mons.caught())
4548 exper /= 2;
4549
4550 if (mons.has_ench(ENCH_SLOW))
4551 {
4552 exper *= 2;
4553 exper /= 3;
4554 }
4555
4556 if (mons.has_ench(ENCH_HASTE))
4557 {
4558 exper *= 3;
4559 exper /= 2;
4560 }
4561
4562 if (mons.has_ench(ENCH_MIGHT))
4563 {
4564 exper *= 5;
4565 exper /= 4;
4566 }
4567
4568 if (mons.berserk_or_insane())
4569 {
4570 // in addition to haste and might bonuses above
4571 exper *= 3;
4572 exper /= 2;
4573 }
4574
4575 return exper;
4576 }
4577
get_tension(god_type god)4578 int get_tension(god_type god)
4579 {
4580 int total = 0;
4581
4582 bool nearby_monster = false;
4583 for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri)
4584 {
4585 const monster* mon = monster_at(*ri);
4586
4587 if (mon && mon->alive() && you.can_see(*mon))
4588 {
4589 int exper = get_monster_tension(*mon, god);
4590
4591 if (!mon->wont_attack())
4592 nearby_monster = true;
4593
4594 total += exper;
4595 }
4596 }
4597
4598 // At least one monster has to be nearby, for tension to count.
4599 if (!nearby_monster)
4600 return 0;
4601
4602 const int scale = 1;
4603
4604 int tension = total;
4605
4606 // Tension goes up inversely proportional to the percentage of max
4607 // hp you have.
4608 tension *= (scale + 1) * you.hp_max;
4609 tension /= max(you.hp_max + scale * you.hp, 1);
4610
4611 // Divides by 1 at level 1, 200 at level 27.
4612 const int exp_lev = you.get_experience_level();
4613 const int exp_need = exp_needed(exp_lev);
4614 const int factor = (int)ceil(sqrt(exp_need / 30.0));
4615 const int div = 1 + factor;
4616
4617 tension /= div;
4618
4619 if (player_in_branch(BRANCH_ABYSS))
4620 {
4621 if (tension < 2)
4622 tension = 2;
4623 else
4624 {
4625 tension *= 3;
4626 tension /= 2;
4627 }
4628 }
4629
4630 if (you.cannot_act())
4631 {
4632 tension *= 10;
4633 tension = max(1, tension);
4634
4635 return tension;
4636 }
4637
4638 if (you.confused())
4639 tension *= 2;
4640
4641 if (you.caught())
4642 tension *= 2;
4643
4644 if (you.duration[DUR_SLOW])
4645 {
4646 tension *= 3;
4647 tension /= 2;
4648 }
4649
4650 if (you.duration[DUR_HASTE])
4651 {
4652 tension *= 2;
4653 tension /= 3;
4654 }
4655
4656 return max(0, tension);
4657 }
4658
get_fuzzied_monster_difficulty(const monster & mons)4659 int get_fuzzied_monster_difficulty(const monster& mons)
4660 {
4661 double factor = sqrt(exp_needed(you.experience_level) / 30.0);
4662 int exp = exper_value(mons) * 100;
4663 exp = random2(exp) + random2(exp);
4664 return exp / (1 + factor);
4665 }
4666
4667 /////////////////////////////////////////////////////////////////////////////
4668 // Stuff for placing god gift monsters after the player's turn has ended.
4669 /////////////////////////////////////////////////////////////////////////////
4670
4671 static vector<mgen_data> _delayed_data;
4672 static deque<delayed_callback> _delayed_callbacks;
4673 static deque<unsigned int> _delayed_done_trigger_pos;
4674 static deque<delayed_callback> _delayed_done_callbacks;
4675 static deque<string> _delayed_success;
4676
delayed_monster(const mgen_data & mg,delayed_callback callback)4677 void delayed_monster(const mgen_data &mg, delayed_callback callback)
4678 {
4679 _delayed_data.push_back(mg);
4680 _delayed_callbacks.push_back(callback);
4681 }
4682
delayed_monster_done(string success,delayed_callback callback)4683 void delayed_monster_done(string success, delayed_callback callback)
4684 {
4685 const unsigned int size = _delayed_data.size();
4686 ASSERT(size > 0);
4687
4688 _delayed_done_trigger_pos.push_back(size - 1);
4689 _delayed_success.push_back(success);
4690 _delayed_done_callbacks.push_back(callback);
4691 }
4692
_place_delayed_monsters()4693 static void _place_delayed_monsters()
4694 {
4695 // Last monster that was successfully placed (so far).
4696 monster *lastmon = nullptr;
4697 int placed = 0;
4698 god_type prev_god = GOD_NO_GOD;
4699
4700 for (unsigned int i = 0; i < _delayed_data.size(); i++)
4701 {
4702 mgen_data &mg = _delayed_data[i];
4703 delayed_callback cback = _delayed_callbacks[i];
4704
4705 if (prev_god != mg.god)
4706 {
4707 lastmon = nullptr;
4708 placed = 0;
4709 prev_god = mg.god;
4710 }
4711
4712 monster *mon = create_monster(mg);
4713
4714 if (cback)
4715 (*cback)(mg, mon, placed);
4716
4717 if (mon)
4718 {
4719 if (you_worship(GOD_YREDELEMNUL)
4720 || you_worship(GOD_HEPLIAKLQANA)
4721 || have_passive(passive_t::convert_orcs))
4722 {
4723 add_companion(mon);
4724 }
4725 lastmon = mon;
4726 placed++;
4727 }
4728
4729 if (!_delayed_done_trigger_pos.empty()
4730 && _delayed_done_trigger_pos[0] == i)
4731 {
4732 cback = _delayed_done_callbacks[0];
4733
4734 string msg;
4735 if (lastmon)
4736 {
4737 ASSERT(placed > 0);
4738 msg = replace_all(_delayed_success[0], "@servant@",
4739 placed == 1
4740 ? lastmon->name(DESC_A)
4741 : pluralise(lastmon->name(DESC_PLAIN)));
4742 }
4743 else
4744 ASSERT(placed == 0);
4745
4746 prev_god = GOD_NO_GOD;
4747 _delayed_done_trigger_pos.pop_front();
4748 _delayed_success.pop_front();
4749 _delayed_done_callbacks.pop_front();
4750
4751 if (msg.empty())
4752 {
4753 if (cback)
4754 (*cback)(mg, lastmon, placed);
4755 continue;
4756 }
4757
4758 // Fake its coming from simple_god_message().
4759 if (msg[0] == ' ' || msg[0] == '\'')
4760 msg = uppercase_first(god_name(mg.god)) + msg;
4761
4762 trim_string(msg);
4763
4764 god_speaks(mg.god, msg.c_str());
4765
4766 if (cback)
4767 (*cback)(mg, lastmon, placed);
4768 }
4769 }
4770
4771 _delayed_data.clear();
4772 _delayed_callbacks.clear();
4773 _delayed_done_trigger_pos.clear();
4774 _delayed_success.clear();
4775 }
4776
_is_god(god_type god)4777 static bool _is_god(god_type god)
4778 {
4779 return god > GOD_NO_GOD && god < NUM_GODS;
4780 }
4781
_is_temple_god(god_type god)4782 static bool _is_temple_god(god_type god)
4783 {
4784 if (!_is_god(god) || _is_disabled_god(god))
4785 return false;
4786
4787 switch (god)
4788 {
4789 case GOD_NO_GOD:
4790 case GOD_LUGONU:
4791 case GOD_BEOGH:
4792 case GOD_JIYVA:
4793 return false;
4794
4795 default:
4796 return true;
4797 }
4798 }
4799
_is_nontemple_god(god_type god)4800 static bool _is_nontemple_god(god_type god)
4801 {
4802 return _is_god(god) && !_is_temple_god(god) && !_is_disabled_god(god);
4803 }
4804
_cmp_god_by_name(god_type god1,god_type god2)4805 static bool _cmp_god_by_name(god_type god1, god_type god2)
4806 {
4807 return god_name(god1, false) < god_name(god2, false);
4808 }
4809
4810 // Vector of temple gods.
4811 // Sorted by name for the benefit of the overview.
temple_god_list()4812 vector<god_type> temple_god_list()
4813 {
4814 vector<god_type> god_list;
4815 for (god_iterator it; it; ++it)
4816 if (_is_temple_god(*it))
4817 god_list.push_back(*it);
4818 sort(god_list.begin(), god_list.end(), _cmp_god_by_name);
4819 return god_list;
4820 }
4821
4822 // Vector of non-temple gods.
4823 // Sorted by name for the benefit of the overview.
nontemple_god_list()4824 vector<god_type> nontemple_god_list()
4825 {
4826 vector<god_type> god_list;
4827 for (god_iterator it; it; ++it)
4828 if (_is_nontemple_god(*it))
4829 god_list.push_back(*it);
4830 sort(god_list.begin(), god_list.end(), _cmp_god_by_name);
4831 return god_list;
4832 }
4833
god_power_usable(const god_power & power,bool ignore_piety,bool ignore_penance)4834 bool god_power_usable(const god_power& power, bool ignore_piety, bool ignore_penance)
4835 {
4836 // not an activated power
4837 if (power.abil == ABIL_NON_ABILITY)
4838 return false;
4839 const ability_type abil = fixup_ability(power.abil);
4840 ASSERT(abil != ABIL_NON_ABILITY);
4841 return (power.rank <= 0
4842 || power.rank == 7 && can_do_capstone_ability(you.religion)
4843 || piety_rank() >= power.rank
4844 || ignore_piety)
4845 && (!player_under_penance()
4846 || power.rank == -1
4847 || ignore_penance);
4848 }
4849
god_power_from_ability(ability_type abil)4850 const god_power* god_power_from_ability(ability_type abil)
4851 {
4852 for (int god = GOD_NO_GOD; god < NUM_GODS; god++)
4853 {
4854 for (const auto& power : god_powers[god])
4855 {
4856 if (power.abil == abil)
4857 return &power;
4858 }
4859 }
4860 return nullptr;
4861 }
4862