1 /*
2 * PROPRIETARY INFORMATION. This software is proprietary to POWDER
3 * Development, and is not to be reproduced, transmitted, or disclosed
4 * in any way without written permission.
5 *
6 * Produced by: Jeff Lait
7 *
8 * POWDER Development
9 *
10 * NAME: piety.cpp ( POWDER Library, C++ )
11 *
12 * COMMENTS:
13 * This implements all the piety handling code.
14 */
15
16 #include "glbdef.h"
17 #include "assert.h"
18 #include <stdio.h>
19 #include "creature.h"
20 #include "piety.h"
21 #include "sramstream.h"
22 #include "item.h"
23 #include "itemstack.h"
24 #include "msg.h"
25 #include "map.h"
26 #include "encyc_support.h"
27
28 //
29 // This stores our total piety & total action points.
30 //
31 s16 glbPiety[NUM_GODS];
32 s16 glbGodPoints[NUM_GODS];
33 GOD_NAMES glbChosenGod = GOD_AGNOSTIC;
34 GOD_NAMES glbWhimOfXOM;
35 u8 glbWhimOfXOMTimer;
36 u8 glbFlameStrikeTimer;
37 GOD_NAMES glbFlameGod;
38
39 //
40 // Global Piety Functions
41 //
42 GOD_NAMES
piety_randomnonxomgod()43 piety_randomnonxomgod()
44 {
45 int god;
46
47 while (1)
48 {
49 god = rand_choice(NUM_GODS);
50 if (god == GOD_AGNOSTIC || god == GOD_CULTIST)
51 continue;
52 break;
53 }
54
55 return (GOD_NAMES) god;
56 }
57
58 void
piety_init()59 piety_init()
60 {
61 GOD_NAMES god;
62
63 FOREACH_GOD(god)
64 {
65 glbPiety[god] = 0;
66 glbGodPoints[god] = 0;
67 }
68
69 // We do not set our god here as it was set in the god selection
70 // stage
71 // glbChosenGod = GOD_AGNOSTIC;
72 glbWhimOfXOM = piety_randomnonxomgod();
73 glbWhimOfXOMTimer = rand_range(100, 200);
74 glbFlameStrikeTimer = 0;
75 glbFlameGod = GOD_AGNOSTIC;
76 }
77
78 GOD_NAMES
piety_chosengod()79 piety_chosengod()
80 {
81 return glbChosenGod;
82 }
83
84 int
piety_chosengodspiety()85 piety_chosengodspiety()
86 {
87 GOD_NAMES god = piety_chosengod();
88
89 if (god == GOD_AGNOSTIC)
90 return 0;
91
92 return glbPiety[god];
93 }
94
95 void
piety_setgod(GOD_NAMES god)96 piety_setgod(GOD_NAMES god)
97 {
98 glbChosenGod = god;
99 }
100
101 void
piety_load(SRAMSTREAM & is)102 piety_load(SRAMSTREAM &is)
103 {
104 int val;
105 GOD_NAMES god;
106
107 FOREACH_GOD(god)
108 {
109 is.read(val, 16);
110 glbPiety[god] = val;
111 is.read(val, 16);
112 glbGodPoints[god] = val;
113 }
114
115 is.read(val, 8);
116 glbChosenGod = (GOD_NAMES) val;
117
118 is.read(val, 8);
119 glbWhimOfXOM = (GOD_NAMES) val;
120
121 is.read(val, 8);
122 glbWhimOfXOMTimer = val;
123
124 is.read(val, 8);
125 glbFlameStrikeTimer = val;
126 is.read(val, 8);
127 glbFlameGod = (GOD_NAMES) val;
128 }
129
130 void
piety_save(SRAMSTREAM & os)131 piety_save(SRAMSTREAM &os)
132 {
133 GOD_NAMES god;
134
135 FOREACH_GOD(god)
136 {
137 os.write(glbPiety[god], 16);
138 os.write(glbGodPoints[god], 16);
139 }
140
141 os.write(glbChosenGod, 8);
142 os.write(glbWhimOfXOM, 8);
143 os.write(glbWhimOfXOMTimer, 8);
144 os.write(glbFlameStrikeTimer, 8);
145 os.write(glbFlameGod, 8);
146 }
147
148 //
149 // MOB::piety Functions
150 //
151 void
pietyKill(MOB * mob,ATTACKSTYLE_NAMES attackstyle)152 MOB::pietyKill(MOB *mob, ATTACKSTYLE_NAMES attackstyle)
153 {
154 int val;
155
156 // Check to see if we are a slave. If so, grant the piety
157 // to our master as well.
158 MOB *master;
159 master = getMaster();
160 if (master)
161 {
162 master->pietyKill(mob, ATTACKSTYLE_MINION);
163 }
164
165 val = mob->getExpLevel();
166
167 if (val < getExpLevel() - 5)
168 val = 1;
169 else if (val < getExpLevel() + 2)
170 val = 2;
171 else
172 val = 3;
173
174 if (attackstyle != ATTACKSTYLE_SPELL)
175 pietyGrant(GOD_FIGHTER, val * 2);
176
177 if (attackstyle == ATTACKSTYLE_MELEE)
178 pietyGrant(GOD_BARB, val);
179 else
180 pietyGrant(GOD_NECRO, val);
181
182 if (attackstyle == ATTACKSTYLE_SPELL)
183 pietyGrant(GOD_WIZARD, val);
184
185 if (attackstyle == ATTACKSTYLE_THROWN)
186 pietyGrant(GOD_ROGUE, val);
187
188 if (mob->defn().mobtype == MOBTYPE_UNDEAD)
189 {
190 pietyGrant(GOD_CLERIC, val);
191 }
192 }
193
194 void
pietyEat(ITEM * item,int foodval)195 MOB::pietyEat(ITEM *item, int foodval)
196 {
197 if (item->getCorpseMob())
198 {
199 // Fallen foe....
200 // Only counts if you aren't hungry.
201 if (getHungerLevel() > HUNGER_HUNGRY)
202 pietyGrant(GOD_CLERIC, -2);
203 }
204 }
205
206 void
pietyDress(INTRINSIC_NAMES intrinsic)207 MOB::pietyDress(INTRINSIC_NAMES intrinsic)
208 {
209 // Only one in 5 chance of actually responding to this state.
210 if (rand_choice(5))
211 return;
212
213 if (intrinsic == INTRINSIC_DRESSED_WIZARD)
214 pietyGrant(GOD_WIZARD, 1);
215 if (intrinsic == INTRINSIC_DRESSED_FIGHTER)
216 pietyGrant(GOD_FIGHTER, 1);
217 if (intrinsic == INTRINSIC_DRESSED_RANGER)
218 pietyGrant(GOD_ROGUE, 1);
219 if (intrinsic == INTRINSIC_DRESSED_CLERIC)
220 {
221 // Pax isn't too impressed by all this..
222 if (rand_choice(8))
223 return;
224 pietyGrant(GOD_CLERIC, 1);
225 }
226 if (intrinsic == INTRINSIC_DRESSED_NECROMANCER)
227 {
228 // Necros should not be about piety.
229 if (rand_choice(4))
230 return;
231 pietyGrant(GOD_NECRO, 1);
232 }
233 if (intrinsic == INTRINSIC_DRESSED_BARBARIAN)
234 {
235 // H'ruth isn't into fashion.
236 if (rand_choice(8))
237 return;
238 pietyGrant(GOD_BARB, 1);
239 }
240 }
241
242 void
pietyZapWand(ITEM * wand)243 MOB::pietyZapWand(ITEM *wand)
244 {
245 pietyGrant(GOD_ROGUE, 2);
246 pietyGrant(GOD_WIZARD, 1);
247 pietyGrant(GOD_BARB, -1);
248 }
249
250 void
pietySurrounded(int numenemy)251 MOB::pietySurrounded(int numenemy)
252 {
253 // Barbarian bonus:
254 if (numenemy > 1)
255 {
256 // TODO: This would be a good time to grant BERSERK.
257 pietyGrant(GOD_BARB, numenemy * 2);
258
259 // Wizards do not like to be surrounded.
260 pietyGrant(GOD_WIZARD, -1);
261 }
262 }
263
264 void
pietyHeal(int amount,bool self,bool enemy,bool vampiric)265 MOB::pietyHeal(int amount, bool self, bool enemy, bool vampiric)
266 {
267 // Necros are rewarded for healing enemies, as it is assumed
268 // one merely wants them to suffer longer.
269 // Otherwise, it isn't something one should be doing.
270 if (enemy || vampiric)
271 pietyGrant(GOD_NECRO, 1);
272 else
273 pietyGrant(GOD_NECRO, -5);
274
275 // Clerics are of two minds of enemy healing. It is a no-op
276 // as otherwise it would encourage uncleric like behaviour.
277 // We get massive bonuses for healing our pets.
278 if (!enemy)
279 {
280 // vampiric styles of healing are not appreciated.
281 if (vampiric)
282 pietyGrant(GOD_CLERIC, -1);
283 else
284 pietyGrant(GOD_CLERIC, self ? 1 : 3);
285 }
286 }
287
288 void
pietyCastSpell(SPELL_NAMES spell)289 MOB::pietyCastSpell(SPELL_NAMES spell)
290 {
291 int val;
292
293 val = glb_spelldefs[spell].mpcost +
294 (glb_spelldefs[spell].hpcost/2) +
295 (glb_spelldefs[spell].xpcost/10);
296
297 // An additional point is given for every 5 vals.
298 val /= 5;
299 if (val <= 0) val = 1;
300
301 pietyGrant(GOD_WIZARD, val);
302
303 if (glb_spelldefs[spell].type == SPELLTYPE_DEATH)
304 {
305 pietyGrant(GOD_NECRO, (val + 1) / 2);
306 pietyGrant(GOD_CLERIC, -val, true);
307 }
308 if (glb_spelldefs[spell].type == SPELLTYPE_HEAL)
309 {
310 pietyGrant(GOD_NECRO, -val, true);
311 pietyGrant(GOD_CLERIC, (val + 1) / 2);
312 }
313
314 // Forbidden for barbarians!
315 pietyGrant(GOD_BARB, -val, true);
316 }
317
318 void
pietyCreateTrap()319 MOB::pietyCreateTrap()
320 {
321 pietyGrant(GOD_ROGUE, 5);
322 }
323
324 void
pietyFindSecret()325 MOB::pietyFindSecret()
326 {
327 pietyGrant(GOD_ROGUE, 5);
328 }
329
330 void
pietyAttack(MOB * mob,const ATTACK_DEF * attack,ATTACKSTYLE_NAMES style)331 MOB::pietyAttack(MOB *mob, const ATTACK_DEF *attack, ATTACKSTYLE_NAMES style)
332 {
333 // Determine if it is a friendly attack.
334 ATTITUDE_NAMES attitude;
335
336 attitude = mob->getAttitude(this);
337
338 // Check for attacking friendly or what not.
339 if (attitude == ATTITUDE_FRIENDLY)
340 {
341 // Killing friendly undead is an act of mercy.
342 if (mob->defn().mobtype != MOBTYPE_UNDEAD)
343 pietyGrant(GOD_CLERIC, -5);
344 }
345 if (attitude == ATTITUDE_NEUTRAL)
346 {
347 // It is not *that* bad to start combat.
348 // However, if the target is undead, Pax has no issues.
349 if (mob->defn().mobtype != MOBTYPE_UNDEAD)
350 pietyGrant(GOD_CLERIC, -1);
351 }
352
353 if ( ( mob->hasIntrinsic(INTRINSIC_PARALYSED) &&
354 !mob->hasIntrinsic(INTRINSIC_FREEDOM)) ||
355 (mob->hasIntrinsic(INTRINSIC_ASLEEP)) )
356 {
357 // Strike helpless.
358 pietyGrant(GOD_ROGUE, 1);
359 pietyGrant(GOD_NECRO, 2);
360
361 // The exception is undead. You are free to
362 // engage them regardless of their status.
363 if (mob->defn().mobtype != MOBTYPE_UNDEAD)
364 {
365 pietyGrant(GOD_CLERIC, -2);
366 }
367 }
368
369 if (style == ATTACKSTYLE_THROWN)
370 {
371 // Ranged attack.
372 pietyGrant(GOD_ROGUE, 1);
373 pietyGrant(GOD_BARB, -2);
374 }
375
376 if (style == ATTACKSTYLE_MELEE)
377 {
378 // Melee attack
379 if (!rand_choice(5))
380 {
381 pietyGrant(GOD_WIZARD, -1);
382 pietyGrant(GOD_NECRO, -1);
383 }
384 }
385 }
386
387 void
pietyMakeNoise(int noiselevel)388 MOB::pietyMakeNoise(int noiselevel)
389 {
390 if (noiselevel > 2)
391 {
392 if (!rand_choice(30))
393 pietyGrant(GOD_ROGUE, -1 * (noiselevel - 2));
394 }
395 }
396
397 void
pietyIdentify(ITEM_NAMES)398 MOB::pietyIdentify(ITEM_NAMES /*itemdef*/)
399 {
400 pietyGrant(GOD_ROGUE, 5);
401 pietyGrant(GOD_WIZARD, 3);
402 }
403
404 void
pietyBreak(ITEM * item)405 MOB::pietyBreak(ITEM *item)
406 {
407 if (glbWhimOfXOM == GOD_CLERIC)
408 {
409 // The hint makes it seem like that breaking things abuses
410 // ><0|V| The wiki picked up on this and I'd hate for
411 // it to be incorrect so I've retconned this pathway
412 pietyGrant(GOD_CULTIST, -2);
413 }
414 }
415
416 void
pietyGrant(GOD_NAMES god,int amount,bool forbidden)417 MOB::pietyGrant(GOD_NAMES god, int amount, bool forbidden)
418 {
419 // Only record piety for the avatar.
420 if (!isAvatar())
421 return;
422
423 // If this god is CULTIST, we need to see what the current
424 // whim of ><0|V| is, and act accordingly.
425 if (god == glbWhimOfXOM)
426 {
427 pietyGrant(GOD_CULTIST, amount, forbidden);
428 }
429
430 // If the action is forbidden, we want to zero out
431 // our piety in one go.
432 if (forbidden && glbPiety[god] > 0)
433 {
434 // You will likely invoke the wrath of the god. If it is
435 // your god, you will wipe your xp.
436 pietyTransgress(god);
437 glbPiety[god] += amount*10;
438 }
439
440 // If the piety is negative, and it is your chosen god,
441 // it is twice as bad.
442 if (god == glbChosenGod && amount < 0)
443 amount *= 2;
444
445 // DIminish returns on positive piety gain to prevent people
446 // stacking up 10k piety for constant healing
447 if (amount > 0)
448 {
449 if (glbPiety[god] > 200)
450 {
451 // Lose 1/16th chance for every 100 piety above this
452 // up to 15 * 100 + 200 = 1700..
453 int goal = (glbPiety[god]-200)/100;
454 if (goal >= 15)
455 goal = 14;
456 if (rand_choice(16) <= goal)
457 amount = 0;
458
459 // Double jeopardy for every 1000 there on (Caps at 10k)
460 if (glbPiety[god] > 2000)
461 {
462 if (rand_choice(16) < (glbPiety[god]-2000)/1000)
463 {
464 amount = 0;
465 }
466 }
467 }
468 }
469
470 // Adjust our piety & god points.
471 if (glbPiety[god] * amount > 0)
472 {
473 // Both piety & amount have same sign, increment god points.
474 if (amount > 0)
475 glbGodPoints[god] += amount;
476 else
477 glbGodPoints[god] -= amount;
478 }
479 glbPiety[god] += amount;
480
481 // Clamp piety to reasonable limits to avoid overflow/underflow
482 if (glbPiety[god] > 10000)
483 glbPiety[god] = 10000;
484 if (glbPiety[god] < -10000)
485 glbPiety[god] = -10000;
486
487 // Reduce god points to not become larger than piety.
488 if (abs(glbPiety[god]) < glbGodPoints[god])
489 glbGodPoints[god] = abs(glbPiety[god]);
490
491 #if 0
492 BUF buf;
493
494 buf.sprintf("%s: %d:%d. ",
495 glb_goddefs[god].name,
496 glbPiety[god],
497 amount);
498 msg_report(buf);
499 #endif
500 }
501
502 void
pietyTransgress(GOD_NAMES god)503 MOB::pietyTransgress(GOD_NAMES god)
504 {
505 // The user did something forbidden to this god.
506 // The penalty is determined by:
507 // 1) If you are currently following this god, wipe experience,
508 // report transgression, and dump all god piety into punishment.
509 // 2) If you are not, check to see if the god points are more than
510 // your current god's piety. If so, punish. Otherwise it is
511 // assumed that your own god stood in the way.
512 //
513 // We wipe out our god points, but don't wipe out our piety.
514 BUF buf;
515
516 // First, the god is given as many points as he wants to play with!
517 glbGodPoints[god] = glbPiety[god];
518
519 if (god == glbChosenGod)
520 {
521 const char *abusemsg[] =
522 {
523 "Your Actions Defile Me!",
524 "Do you value me so little?",
525 "Respect My Commands!"
526 };
527
528 buf.sprintf("%s: %s ", glb_goddefs[god].name,
529 abusemsg[rand_choice(3)]);
530 msg_announce(buf);
531 wipeExp();
532 pietyPunish(god);
533 }
534 else
535 {
536 if (glbChosenGod == GOD_AGNOSTIC)
537 {
538 const char *agnosticsavemsg[] =
539 {
540 "You sense celestial displeasure. ",
541 "You wonder if there are gods after all? ",
542 "A painful hangnail briefly distracts you. "
543 };
544
545 msg_announce(agnosticsavemsg[rand_choice(3)]);
546
547 // Your powers of disbelief succeed.
548 glbGodPoints[god] = 0;
549 }
550 else if (glbGodPoints[god] > glbPiety[glbChosenGod])
551 {
552 // Your current god cannot come to your rescue.
553 const char *abusemsg[] =
554 {
555 "%s: Do not look to %s to protect you! ",
556 "%s: You should obey Me! ",
557 "%s: You cannot hide from Me! "
558 };
559 buf.sprintf(abusemsg[rand_choice(3)],
560 glb_goddefs[god].name,
561 glb_goddefs[glbChosenGod].name);
562 msg_announce(buf);
563 pietyPunish(god);
564 }
565 else
566 {
567 // Let the player know a divine struggle just occurred.
568 const char *godsavemsg[] =
569 {
570 "%s: %s shall not meddle with my disciple! ",
571 "%s: Fear not %s while you follow me! ",
572 "%s: %s! Leave my people alone! "
573 };
574 buf.sprintf(godsavemsg[rand_choice(3)],
575 glb_goddefs[glbChosenGod].name,
576 glb_goddefs[god].name);
577 msg_announce(buf);
578 // This will cost you piety with your god!
579 glbPiety[glbChosenGod] -= glbGodPoints[god];
580 // We may have moved our piety to 0. If we leave
581 // our god points, this could result in us being
582 // punished!
583 // Thus, we ensure god points are less than piety.
584 if (glbGodPoints[glbChosenGod] > abs(glbPiety[glbChosenGod]))
585 glbGodPoints[glbChosenGod] = abs(glbPiety[glbChosenGod]);
586 // They all get nullified against your chosen god.
587 glbGodPoints[god] = 0;
588 }
589 }
590
591 glbPiety[god] = glbGodPoints[god];
592 glbGodPoints[god] = 0;
593 }
594
595 void
pietyPunish(GOD_NAMES god)596 MOB::pietyPunish(GOD_NAMES god)
597 {
598 // Choose a punishment that fits the god and fits the available points.
599 PUNISH_NAMES valid[NUM_PUNISHS];
600 int numvalid = 0;
601 int points;
602 PUNISH_NAMES punish;
603 BUF buf;
604
605 points = glbGodPoints[god];
606
607 FOREACH_PUNISH(punish)
608 {
609 if (glb_punishdefs[punish].points <= points)
610 {
611 if (strchr(glb_punishdefs[punish].god, (char) god))
612 {
613 // This god is willing to do this punishment.
614 valid[numvalid++] = punish;
615 }
616 }
617 }
618
619 // If there is no valid punishments, quit.
620 if (!numvalid)
621 return;
622
623 punish = valid[rand_choice(numvalid)];
624
625 // Subtract the points & apply the punishment.
626 glbGodPoints[god] -= glb_punishdefs[punish].points;
627
628 switch (punish)
629 {
630 case PUNISH_FLAMESTRIKE:
631 {
632 formatAndReport("%U <smell> sulphur.");
633 glbFlameStrikeTimer = rand_range(3, 6);
634 glbFlameGod = god;
635 break;
636 }
637
638 case PUNISH_SUMMON:
639 {
640 buf.sprintf("%s: Prove your worth! ",
641 glb_goddefs[god].name);
642 msg_announce(buf);
643
644 MOB *mob;
645 int dx, dy;
646
647 for (dy = -1; dy <= 1; dy++)
648 {
649 for (dx = -1; dx <= 1; dx++)
650 {
651 if (glbCurLevel->getMob(getX()+dx,
652 getY()+dy))
653 continue;
654
655 mob = MOB::createNPC(getExpLevel()+3);
656 if (!mob->canMove(getX() + dx,
657 getY() + dy,
658 true))
659 {
660 delete mob;
661 continue;
662 }
663
664 mob->move(getX() + dx,
665 getY() + dy,
666 true);
667 glbCurLevel->registerMob(mob);
668
669 mob->formatAndReport("%U <appear> out of thin air!");
670
671 // Ensure we want to kill the target, which is this.
672 mob->setAITarget(this);
673 }
674 }
675
676 break;
677 }
678
679 case PUNISH_CURSE_WORN:
680 {
681 buf.sprintf("%s: To the pits with you! ",
682 glb_goddefs[god].name);
683 msg_announce(buf);
684
685 // Curse only equpped items.
686 receiveCurse(true, false);
687 break;
688 }
689
690 case PUNISH_CURSE_ANY:
691 {
692 buf.sprintf("%s: A pox on you! ",
693 glb_goddefs[god].name);
694 msg_announce(buf);
695
696 // Curse all items with equal chance.
697 receiveCurse(false, true);
698 break;
699 }
700
701 case PUNISH_DISENCHANT_WEAPON:
702 {
703 buf.sprintf("%s: You are an inferior tool! ",
704 glb_goddefs[god].name);
705 msg_announce(buf);
706
707 // gods do not invoke shuddering.
708 receiveWeaponEnchant(-1, false);
709 break;
710 }
711
712 case PUNISH_DISENCHANT_ARMOUR:
713 {
714 buf.sprintf("%s: You deserve no protection! ",
715 glb_goddefs[god].name);
716 msg_announce(buf);
717
718 // gods do not invoke shuddering.
719 receiveArmourEnchant((ITEMSLOT_NAMES)-1, -1, false);
720 break;
721 }
722
723 case PUNISH_POISON:
724 {
725 buf.sprintf("%s: Drink the poison you have brewed! ",
726 glb_goddefs[god].name);
727 msg_announce(buf);
728
729 setTimedIntrinsic(0, INTRINSIC_POISON_STRONG, 20);
730
731 break;
732 }
733
734 case PUNISH_PARALYSE:
735 {
736 buf.sprintf("%s: Freeze with Fright at my Wrath! ",
737 glb_goddefs[god].name);
738 msg_announce(buf);
739
740 setTimedIntrinsic(0, INTRINSIC_PARALYSED, 5);
741 break;
742 }
743
744 case PUNISH_SLEEP:
745 {
746 buf.sprintf("%s: Dream in Terror! ",
747 glb_goddefs[god].name);
748 msg_announce(buf);
749
750 setTimedIntrinsic(0, INTRINSIC_ASLEEP, 30);
751 break;
752 }
753
754 case PUNISH_POLY:
755 {
756 MOB_NAMES mob;
757
758 // Determine a suitable pathetic beast.
759 MOB_NAMES targets[3] =
760 {
761 MOB_MOUSE,
762 MOB_BROWNSLUG,
763 MOB_GRIDBUG
764 };
765
766 if (god == GOD_NECRO)
767 mob = MOB_SKELETON;
768 else
769 mob = targets[rand_choice(3)];
770
771 buf.sprintf("%s: Learn Humility! ",
772 glb_goddefs[god].name);
773 msg_announce(buf);
774
775 // And poly the loser into it!
776 actionPolymorph(false, true, mob);
777 break;
778 }
779
780 case PUNISH_MANADRAIN:
781 {
782 buf.sprintf("%s: Your Magic Will Not Avail You! ",
783 glb_goddefs[god].name);
784 msg_announce(buf);
785
786 // drain magic.
787 // 50 + 5d10 turns.
788 setTimedIntrinsic(0, INTRINSIC_MAGICDRAIN,
789 rand_dice(5, 10, 50));
790 break;
791 }
792
793 case PUNISH_POLYWEAPON:
794 {
795 ITEM *weapon;
796
797 weapon = getEquippedItem(ITEMSLOT_RHAND);
798 if (!weapon)
799 {
800 // Should not occur?
801 buf.sprintf("%s: I have caught you empty handed! Ha! ",
802 glb_goddefs[god].name);
803 msg_announce(buf);
804 break;
805 }
806
807 BUF weapname = weapon->getName();
808 buf.sprintf("%s: Your over use of %s bores me! ",
809 glb_goddefs[god].name,
810 weapname.buffer());
811 msg_announce(buf);
812
813 // polymorph the weapon...
814 ITEM *newweapon;
815
816 newweapon = weapon->polymorph(this);
817
818 // If the polymorph fails, we don't want to delete
819 // their weapon!
820 if (!newweapon)
821 {
822 // We haven't yet dropped the old weapon,
823 // so just break for status quo
824 break;
825 }
826
827 // Some day I will make a less error prone way of writing
828 // this. This is not that day!
829 weapon = dropItem(weapon->getX(), weapon->getY());
830
831 // If the weapon has a stack, we split & reacquire. Otherwise
832 // we destroy.
833 if (weapon->getStackCount() > 1)
834 {
835 weapon->splitAndDeleteStack();
836 // Try and reacquire as a non-weapon.
837 if (!acquireItem(weapon))
838 {
839 // Failed to put in inventory, drop.
840 formatAndReport("%U <lack> room for %IU.", weapon);
841 glbCurLevel->acquireItem(weapon, getX(), getY(), 0);
842 }
843 }
844 else
845 {
846 // Toss the item silently
847 delete weapon;
848 }
849
850 // Re-equip the new item. This could fail.
851 // First, we need it in our inventory.
852 if (!acquireItem(newweapon, &newweapon))
853 {
854 // Failed to acquire, drop on ground.
855 formatAndReport("%U <lack> room for %IU.", newweapon);
856 glbCurLevel->acquireItem(newweapon, getX(), getY(), 0);
857 }
858 else
859 {
860 // It is now in our inventory. Try to equip it,
861 // including failure messages!
862 actionEquip(newweapon->getX(), newweapon->getY(), ITEMSLOT_RHAND);
863 }
864
865 break;
866 }
867
868 case NUM_PUNISHS:
869 {
870 // Confusion!
871 buf.sprintf("%s wails in confusion. ",
872 glb_goddefs[god].name);
873 msg_announce(buf);
874 break;
875 }
876 }
877 }
878
879 bool
pietyBoonValid(BOON_NAMES boon)880 MOB::pietyBoonValid(BOON_NAMES boon)
881 {
882 ITEM *item;
883 bool haswater = false;
884 bool hascursed = false;
885 bool hasweapon = false;
886 bool hasarmour = false;
887 bool hasnonid = false;
888
889 // Check for items needed.
890 for (item = myInventory; item; item = item->getNext())
891 {
892 // Check for potential sanctify:
893 if ( item->getDefinition() == ITEM_WATER &&
894 !item->isBlessed())
895 haswater = true;
896
897 // Check if the item is an unided artifact or unided
898 // magic type.
899 if (!item->isIdentified() && item->getMagicType() != MAGICTYPE_NONE)
900 hasnonid = true;
901
902 if (item->getArtifact() && !item->isFullyIdentified())
903 hasnonid = true;
904
905 // Check for an uncursing.
906 if (item->isCursed() && item->getX() == 0)
907 hascursed = true;
908
909 if (item->getX() == 0 &&
910 item->getY() == ITEMSLOT_RHAND)
911 hasweapon = true;
912
913 if (item->getX() == 0 &&
914 (item->getY() == ITEMSLOT_LHAND ||
915 item->getY() == ITEMSLOT_HEAD ||
916 item->getY() == ITEMSLOT_BODY ||
917 item->getY() == ITEMSLOT_FEET))
918 hasarmour = true;
919 }
920
921 switch (boon)
922 {
923 case BOON_UNCURSE:
924 return hascursed;
925
926 case BOON_HEAL:
927 if (getHP() < getMaxHP() / 3)
928 return true;
929 return false;
930
931 case BOON_LICHFORM:
932 if (getHP() < getMaxHP() / 4)
933 return true;
934 return false;
935
936 case BOON_CURE:
937 return aiIsPoisoned();
938
939 case BOON_SANCTIFY:
940 return haswater;
941
942 case BOON_SURROUNDATTACK:
943 // Verify you are surrounded by a foe...
944 if (calculateFoesSurrounding() > 1)
945 {
946 return true;
947 }
948 break;
949
950 case BOON_UNSTONE:
951 // If you are turning to stone, and are not actively resisting
952 // turning to stone, then help.
953 return hasIntrinsic(INTRINSIC_STONING) &&
954 !hasIntrinsic(INTRINSIC_RESISTSTONING) &&
955 !hasIntrinsic(INTRINSIC_UNCHANGING);
956
957 case BOON_ENCHANT_WEAPON:
958 return hasweapon;
959
960 case BOON_ENCHANT_ARMOUR:
961 return hasarmour;
962
963 case BOON_GRANT_SPELL:
964 // TODO: Find if we have any holes in our spell schools.
965 return true;
966
967 // Trivially true boons:
968 case BOON_GIFT_WEAPON:
969 case BOON_GIFT_ARMOUR:
970 case BOON_GIFT_WAND:
971 case BOON_GIFT_SPELLBOOK:
972 case BOON_GIFT_STAFF:
973 return true;
974
975 case BOON_IDENTIFY:
976 return hasnonid;
977
978 case NUM_BOONS:
979 break;
980 }
981
982 return false;
983 }
984
985 void
pietyBoon(GOD_NAMES god)986 MOB::pietyBoon(GOD_NAMES god)
987 {
988 BOON_NAMES valid[NUM_BOONS], boon;
989 int numvalid = 0;
990 BUF buf;
991 ITEM *item;
992 bool hasrescue = false;
993
994 // Run through the boons determining if they apply and if they
995 // can be paid for.
996 FOREACH_BOON(boon)
997 {
998 // See if we can afford the cost.
999 if (glb_boondefs[boon].points > glbGodPoints[god])
1000 continue;
1001
1002 // See if this is a valid god.
1003 if (!strchr(glb_boondefs[boon].god, (char) god))
1004 continue;
1005
1006 // Check to see if it applies. Eg, no point curing
1007 // someone not poisoned.
1008 if (pietyBoonValid(boon))
1009 {
1010 if (hasrescue && !glb_boondefs[boon].isrescue)
1011 continue;
1012
1013 if (glb_boondefs[boon].isrescue && !hasrescue)
1014 {
1015 hasrescue = true;
1016 numvalid = 0;
1017 }
1018 valid[numvalid++] = boon;
1019 }
1020 }
1021
1022 // If no valid boons, quit.
1023 if (!numvalid)
1024 return;
1025
1026 boon = valid[rand_choice(numvalid)];
1027
1028 // Pay the cost.
1029 glbGodPoints[god] -= glb_boondefs[boon].points;
1030
1031 // Do the boon:
1032 switch (boon)
1033 {
1034 case BOON_UNCURSE:
1035 buf.sprintf("%s: Allow me to aid you. ",
1036 glb_goddefs[god].name);
1037 msg_announce(buf);
1038 receiveUncurse(false);
1039 break;
1040
1041 case BOON_HEAL:
1042 buf.sprintf("%s: Your flesh shall mend! ",
1043 glb_goddefs[god].name);
1044 msg_announce(buf);
1045 // Full heal
1046 receiveHeal(getMaxHP() - getHP(), 0);
1047 break;
1048
1049 case BOON_LICHFORM:
1050 buf.sprintf("%s: Show your devotion! ",
1051 glb_goddefs[god].name);
1052 msg_announce(buf);
1053 setTimedIntrinsic(0, INTRINSIC_LICHFORM, 2);
1054 break;
1055
1056 case BOON_SURROUNDATTACK:
1057 {
1058 buf.sprintf("%s: You've proven your worth!",
1059 glb_goddefs[god].name);
1060 msg_announce(buf);
1061
1062 int dx, dy;
1063
1064 FORALL_4DIR(dx, dy)
1065 {
1066 MOB *mob;
1067
1068 mob = glbCurLevel->getMob(getX()+dx, getY()+dy);
1069
1070 if (mob && mob->getAttitude(this) == ATTITUDE_HOSTILE)
1071 {
1072 mob->receiveAttack(ATTACK_SURROUNDSMITE, 0, 0, 0,
1073 ATTACKSTYLE_SPELL);
1074 }
1075 }
1076 break;
1077 }
1078
1079 case BOON_CURE:
1080 buf.sprintf("%s: Your affliction pains me! ",
1081 glb_goddefs[god].name);
1082 msg_announce(buf);
1083
1084 receiveCure();
1085 break;
1086
1087 case BOON_UNSTONE:
1088 buf.sprintf("%s: I wish no more statues. ",
1089 glb_goddefs[god].name);
1090 msg_announce(buf);
1091
1092 clearIntrinsic(INTRINSIC_STONING);
1093 setTimedIntrinsic(0, INTRINSIC_RESISTSTONING, 10);
1094 break;
1095
1096 case BOON_SANCTIFY:
1097 {
1098 buf.sprintf("%s: Your water is blessed! ",
1099 glb_goddefs[god].name);
1100 msg_announce(buf);
1101
1102 for (item = myInventory; item; item = item->getNext())
1103 {
1104 if (item->getDefinition() == ITEM_WATER)
1105 {
1106 // Twice to ensure we end up at blessed status.
1107 item->makeBlessed();
1108 item->makeBlessed();
1109 // It is rather obvious that the water must now be
1110 // holy water.
1111 item->markCursedKnown();
1112 }
1113 }
1114
1115 break;
1116 }
1117
1118 case BOON_ENCHANT_WEAPON:
1119 {
1120 buf.sprintf("%s: You are my weapon: Cut Deeply! ",
1121 glb_goddefs[god].name);
1122 msg_announce(buf);
1123
1124 receiveWeaponEnchant(1, false);
1125 break;
1126 }
1127
1128 case BOON_ENCHANT_ARMOUR:
1129 {
1130 buf.sprintf("%s: Accept my protection. ",
1131 glb_goddefs[god].name);
1132 msg_announce(buf);
1133
1134 receiveArmourEnchant((ITEMSLOT_NAMES) -1, 1, false);
1135 break;
1136 }
1137
1138 case BOON_GRANT_SPELL:
1139 {
1140 buf.sprintf("%s: Knowledge is Power! ",
1141 glb_goddefs[god].name);
1142 msg_announce(buf);
1143
1144 // Random spell..
1145 SPELL_NAMES spell;
1146
1147 spell = findSpell(god);
1148
1149 if (spell == SPELL_NONE)
1150 {
1151 // You are so cool you already know all
1152 // the spells you can! Deity is suitably impressed.
1153 msg_announce("You already have knowledge. Now gain power! ");
1154
1155 // Maximize MP.
1156 if (getMP() < getMaxMP())
1157 {
1158 formatAndReport("%U <be> energized.");
1159 myMP = getMaxMP();
1160 }
1161
1162 // Bonus XP.
1163 formatAndReport("%U <gain> experience.");
1164 receiveExp(100);
1165 }
1166 else
1167 learnSpell(spell);
1168 break;
1169 }
1170
1171 case BOON_GIFT_WEAPON:
1172 case BOON_GIFT_ARMOUR:
1173 case BOON_GIFT_WAND:
1174 case BOON_GIFT_SPELLBOOK:
1175 case BOON_GIFT_STAFF:
1176 {
1177 buf.sprintf("%s: Use my gift wisely. ",
1178 glb_goddefs[god].name);
1179 msg_announce(buf);
1180
1181 ITEM *gift;
1182
1183 gift = ITEM::createRandomType((ITEMTYPE_NAMES)
1184 glb_boondefs[boon].gifttype);
1185
1186 // Ensure it is blessed and a +3 enchant.
1187 gift->makeBlessed();
1188 gift->makeBlessed();
1189
1190 gift->enchant(3 - gift->getEnchantment());
1191
1192 // Drop at feet:
1193 buf = formatToString("%IU <I:appear> by %R %B1.",
1194 this, 0, 0, gift,
1195 getSlotName(ITEMSLOT_FEET) ?
1196 getSlotName(ITEMSLOT_FEET) :
1197 "shadow");
1198 reportMessage(buf);
1199
1200 glbCurLevel->acquireItem(gift, getX(), getY(), 0);
1201 break;
1202 }
1203
1204 case BOON_IDENTIFY:
1205 {
1206 ITEMSTACK stack;
1207 ITEM *item;
1208
1209 buf.sprintf("%s: Know Your Tools! ",
1210 glb_goddefs[god].name);
1211 msg_announce(buf);
1212
1213 for (item = myInventory; item; item = item->getNext())
1214 {
1215 if (!item->isIdentified() && item->getMagicType() != MAGICTYPE_NONE)
1216 stack.append(item);
1217 else if (item->getArtifact() && !item->isFullyIdentified())
1218 stack.append(item);
1219 }
1220
1221 UT_ASSERT(stack.entries());
1222 if (!stack.entries())
1223 break;
1224
1225 item = stack(rand_choice(stack.entries()));
1226
1227 if (isAvatar())
1228 item->markIdentified();
1229
1230 formatAndReport("%U <gain> insight into the nature of %IU.", item);
1231 break;
1232 }
1233
1234 case NUM_BOONS:
1235 // Should not occur.
1236 break;
1237 }
1238 }
1239
1240 void
pietyAnnounceWhimOfXom()1241 MOB::pietyAnnounceWhimOfXom()
1242 {
1243 // If you worship ><0|V|, you get a clue as to his new preference.
1244 if (glbChosenGod == GOD_CULTIST)
1245 {
1246 msg_announce(glb_goddefs[glbWhimOfXOM].whimofxom);
1247 }
1248 }
1249
1250 void
pietyRungods()1251 MOB::pietyRungods()
1252 {
1253 GOD_NAMES god;
1254
1255 // Only run the god code on the avatar.
1256 if (!isAvatar())
1257 return;
1258
1259 // Update ><0|V|s whim.
1260 if (rand_chance(80))
1261 glbWhimOfXOMTimer--;
1262
1263 if (!glbWhimOfXOMTimer)
1264 {
1265 glbWhimOfXOMTimer = rand_range(100, 200);
1266 glbWhimOfXOM = piety_randomnonxomgod();
1267
1268 pietyAnnounceWhimOfXom();
1269 }
1270
1271 // If we are worshipping no one god, we get no benefits or punishments.
1272 if (glbChosenGod == GOD_AGNOSTIC)
1273 {
1274 return;
1275 }
1276
1277 if (glbFlameStrikeTimer)
1278 {
1279 glbFlameStrikeTimer--;
1280
1281 if (!glbFlameStrikeTimer)
1282 {
1283 BUF buf;
1284
1285 buf.sprintf("%s: Suffer my Wrath! ",
1286 glb_goddefs[glbFlameGod].name);
1287 msg_announce(buf);
1288
1289 // Peform flamestrike.
1290 // TODO: Have MOBs for placeholders for the gods.
1291 receiveAttack(ATTACK_FLAMESTRIKE, 0, 0, 0,
1292 ATTACKSTYLE_SPELL);
1293 return;
1294 }
1295 }
1296
1297 FOREACH_GOD(god)
1298 {
1299 // Fickle gods do not always act.
1300 // this is broken and should be continue, not return, or we bias
1301 // against later gods.
1302 if (!rand_choice(10))
1303 return;
1304 if (glbGodPoints[god] > 100)
1305 {
1306 // Consider granting a boon.
1307 // TODO: Track number of levels gained and bias
1308 // accordingly.
1309 if (god == glbChosenGod || !rand_choice(50))
1310 {
1311 if (glbPiety[god] > 0)
1312 pietyBoon((GOD_NAMES) god);
1313 else
1314 pietyPunish((GOD_NAMES) god);
1315
1316 // Do not test anything else in case we died
1317 return;
1318 }
1319 }
1320 }
1321 }
1322
1323 void
pietyGainLevel()1324 MOB::pietyGainLevel()
1325 {
1326 GOD_NAMES godlist[NUM_GODS], god;
1327 int numvalid = 0, i, choice, y;
1328 int aorb = 0;
1329 MOB *base;
1330 SPELL_NAMES spell = (SPELL_NAMES) -1;
1331 BUF buf;
1332 SKILL_NAMES skill = SKILL_NONE;
1333 int newpts;
1334
1335 base = myBaseType.getMob();
1336
1337 const char *gainmsg[] =
1338 {
1339 "You have gained a level! ",
1340 "Welcome to the next level. ",
1341 "Level Up! ",
1342 "You learn from experience. ",
1343 "Another kill, Another level. "
1344 };
1345 // This message announce helps avoid accidental button presses.
1346 msg_announce(gainmsg[rand_choice(5)]);
1347
1348 // Report current god...
1349 BUF curgod;
1350 curgod.sprintf("You currently worship %s. ", glb_goddefs[glbChosenGod].name);
1351 msg_report(curgod);
1352
1353 FOREACH_GOD(god)
1354 {
1355 // Is this a valid god? Agnostic is always valid.
1356 if (god == GOD_AGNOSTIC ||
1357 glbPiety[god] >= 10)
1358 {
1359 godlist[numvalid++] = god;
1360 }
1361 }
1362
1363 // Ask the user to pick a level.
1364 char **menu;
1365
1366 menu = new char *[numvalid+2];
1367 // First choice is a sentinel to insure rapid clickers don't get
1368 // get the wrong choice.
1369 menu[0] = "Select a god";
1370 for (i = 0; i < numvalid; i++)
1371 {
1372 if (godlist[i] != GOD_AGNOSTIC)
1373 {
1374 // Give some detailed info about the god.
1375 // I think providing both numbers is a bit confusing, so
1376 // we'll stick with the Piety
1377 menu[i+1] = new char [30];
1378 sprintf(menu[i+1], "%-11s (%d)",
1379 glb_goddefs[godlist[i]].classname,
1380 glbPiety[godlist[i]]);
1381 }
1382 else
1383 menu[i+1] = (char *) glb_goddefs[godlist[i]].classname;
1384 }
1385 menu[numvalid+1] = 0;
1386
1387 while (1)
1388 {
1389 choice = gfx_selectmenu(30 - 20, 3, (const char **)menu, aorb);
1390 for (y = 3; y < 19; y++)
1391 gfx_cleartextline(y);
1392
1393 if (hamfake_forceQuit())
1394 {
1395 // We sadly have to force-pick a god to be able
1396 // to save successfully. Adventurer is likely the safest.
1397 god = GOD_AGNOSTIC;
1398 break;
1399 }
1400
1401 // Valid choices,,,,
1402 if (choice >= 1 && !aorb)
1403 {
1404 BUF godchoice;
1405
1406 // Fix off by one due to sentinel
1407 choice--;
1408
1409 // User chose godlist[choice].
1410 god = godlist[choice];
1411
1412 // Inform the user of their future decision.
1413 // Display the info text.
1414 encyc_viewentry("GOD", god);
1415
1416 godchoice.sprintf("Follow %s?", glb_goddefs[god].name);
1417
1418 // Verify user is serious.
1419 if (gfx_yesnomenu(godchoice))
1420 break;
1421 }
1422 }
1423
1424 // Wipe out our menu.
1425 for (i = 0; i < numvalid; i++)
1426 {
1427 if (godlist[i] != GOD_AGNOSTIC)
1428 {
1429 delete [] menu[i+1];
1430 }
1431 }
1432 delete [] menu;
1433
1434 glbChosenGod = god;
1435
1436 formatAndReport("%U <worship> %B1.",
1437 glb_goddefs[god].name);
1438
1439 // Add an exp level.
1440 myExpLevel++;
1441
1442 // Add our health & magic.
1443 myHitDie += glb_goddefs[god].physical;
1444
1445 // 3-5 points per level with a bias to 4. Considered having it
1446 // controled by piety but that just forces people away from
1447 // experimentation.
1448 // 2d2+1
1449 newpts = rand_dice(glb_goddefs[god].physical*2, 2, glb_goddefs[god].physical);
1450 incrementMaxHP(newpts);
1451
1452 if (base)
1453 {
1454 base->myHitDie += glb_goddefs[god].physical;
1455 }
1456
1457 myMagicDie += glb_goddefs[god].mental;
1458 newpts = rand_dice(glb_goddefs[god].mental*2, 2, glb_goddefs[god].mental);
1459 incrementMaxMP(newpts);
1460
1461 if (base)
1462 {
1463 base->myMagicDie += glb_goddefs[god].mental;
1464 }
1465
1466 int numskill = 0, numspell = 0;
1467
1468 skill = findSkill(god, &numskill);
1469 spell = findSpell(god, &numspell);
1470
1471 // You only get one of skill or spell, never both.
1472 // We bias according to the number of valid choices.
1473 if (spell != SPELL_NONE && skill != SKILL_NONE)
1474 {
1475 if (rand_choice(numspell + numskill) < numskill)
1476 spell = SPELL_NONE;
1477 else
1478 skill = SKILL_NONE;
1479 }
1480
1481 // Special cases for gods...
1482 switch (god)
1483 {
1484 case GOD_CULTIST:
1485 {
1486 // Gain random hit & magic dice.
1487 int phys, ment;
1488
1489 phys = rand_choice(5);
1490 ment = rand_choice(5);
1491 myHitDie += phys;
1492 myMagicDie += ment;
1493 if (base)
1494 {
1495 base->myHitDie += phys;
1496 base->myMagicDie += ment;
1497 }
1498
1499 phys = rand_choice(phys * 10);
1500 ment = rand_choice(ment * 10);
1501
1502 incrementMaxHP(phys);
1503 incrementMaxMP(ment);
1504 break;
1505 }
1506
1507 case GOD_WIZARD:
1508 {
1509 break;
1510 }
1511
1512 case GOD_CLERIC:
1513 {
1514 break;
1515 }
1516
1517 case GOD_NECRO:
1518 {
1519 break;
1520 }
1521
1522 case GOD_AGNOSTIC:
1523 {
1524 // Do nothing!
1525 break;
1526 }
1527
1528 case GOD_FIGHTER:
1529 {
1530 break;
1531 }
1532
1533 case GOD_ROGUE:
1534 {
1535 break;
1536 }
1537
1538 case GOD_BARB:
1539 {
1540 break;
1541 }
1542
1543 case NUM_GODS:
1544 {
1545 break;
1546 }
1547 }
1548
1549 learnSpell(spell);
1550 learnSkill(skill);
1551
1552 // Report number of free slots
1553 buf.sprintf("You have %d free spell and %d free skill slots.",
1554 getFreeSpellSlots(),
1555 getFreeSkillSlots());
1556 reportMessage(buf);
1557
1558 // If you just started following Xom, pretty important.
1559 pietyAnnounceWhimOfXom();
1560 }
1561
1562 void
pietyReport()1563 MOB::pietyReport()
1564 {
1565 char *menu[NUM_GODS + 1];
1566 int dressiness[NUM_GODS];
1567
1568 int i, aorb;
1569 GOD_NAMES god;
1570
1571 determineClassiness(dressiness);
1572
1573 FOREACH_GOD(god)
1574 {
1575 menu[god] = new char[30];
1576
1577 sprintf(menu[god], "%10s: %d (%d)",
1578 glb_goddefs[god].name,
1579 glbPiety[god],
1580 glbGodPoints[god]);
1581 if (dressiness[god])
1582 {
1583 // Pad out a tad
1584 strcat(menu[god], " ");
1585 }
1586 for (int i = 2; i <= dressiness[god]; i+=2)
1587 strcat(menu[god], "*");
1588 if (dressiness[god] & 1)
1589 strcat(menu[god], "+");
1590 }
1591 menu[NUM_GODS] = 0;
1592
1593 {
1594 BUF buf;
1595 buf.sprintf("Now Worshipping: %s", glb_goddefs[glbChosenGod].name);
1596 gfx_printtext(2, 4, buf.buffer());
1597 }
1598
1599 gfx_selectmenu(5, 6, (const char **) menu, aorb, glbChosenGod);
1600
1601 // And clear it...
1602 for (i = 3; i < 18; i++)
1603 {
1604 gfx_cleartextline(i);
1605 }
1606
1607 for (i = 0; i < NUM_GODS; i++)
1608 delete [] menu[i];
1609 }
1610