2529 lines
89 KiB
C
2529 lines
89 KiB
C
/* NetHack 3.7 pray.c $NHDT-Date: 1649454525 2022/04/08 21:48:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.168 $ */
|
|
/* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h"
|
|
|
|
static int prayer_done(void);
|
|
static struct obj *worst_cursed_item(void);
|
|
static int in_trouble(void);
|
|
static void fix_curse_trouble(struct obj *, const char *);
|
|
static void fix_worst_trouble(int);
|
|
static void angrygods(aligntyp);
|
|
static void at_your_feet(const char *);
|
|
static void gcrownu(void);
|
|
static void give_spell(void);
|
|
static void pleased(aligntyp);
|
|
static void godvoice(aligntyp, const char *);
|
|
static void god_zaps_you(aligntyp);
|
|
static void fry_by_god(aligntyp, boolean);
|
|
static void gods_angry(aligntyp);
|
|
static void gods_upset(aligntyp);
|
|
static void consume_offering(struct obj *);
|
|
static void offer_too_soon(aligntyp);
|
|
static void desecrate_high_altar(aligntyp);
|
|
static void offer_real_amulet(struct obj *, aligntyp); /* NORETURN */
|
|
static void offer_different_alignment_altar(struct obj *, aligntyp);
|
|
static boolean pray_revive(void);
|
|
static boolean water_prayer(boolean);
|
|
static boolean blocked_boulder(int, int);
|
|
|
|
/* simplify a few tests */
|
|
#define Cursed_obj(obj, typ) ((obj) && (obj)->otyp == (typ) && (obj)->cursed)
|
|
|
|
/*
|
|
* Logic behind deities and altars and such:
|
|
* + prayers are made to your god if not on an altar, and to the altar's god
|
|
* if you are on an altar
|
|
* + If possible, your god answers all prayers, which is why bad things happen
|
|
* if you try to pray on another god's altar
|
|
* + sacrifices work basically the same way, but the other god may decide to
|
|
* accept your allegiance, after which they are your god. If rejected,
|
|
* your god takes over with your punishment.
|
|
* + if you're in Gehennom, all messages come from Moloch
|
|
*/
|
|
|
|
/*
|
|
* Moloch, who dwells in Gehennom, is the "renegade" cruel god
|
|
* responsible for the theft of the Amulet from Marduk, the Creator.
|
|
* Moloch is unaligned.
|
|
*/
|
|
static const char *const Moloch = "Moloch";
|
|
|
|
static const char *const godvoices[] = {
|
|
"booms out", "thunders", "rings out", "booms",
|
|
};
|
|
|
|
#define PIOUS 20
|
|
#define DEVOUT 14
|
|
#define FERVENT 9
|
|
#define STRIDENT 4
|
|
|
|
/*
|
|
* The actual trouble priority is determined by the order of the
|
|
* checks performed in in_trouble() rather than by these numeric
|
|
* values, so keep that code and these values synchronized in
|
|
* order to have the values be meaningful.
|
|
*/
|
|
|
|
#define TROUBLE_STONED 14
|
|
#define TROUBLE_SLIMED 13
|
|
#define TROUBLE_STRANGLED 12
|
|
#define TROUBLE_LAVA 11
|
|
#define TROUBLE_SICK 10
|
|
#define TROUBLE_STARVING 9
|
|
#define TROUBLE_REGION 8 /* stinking cloud */
|
|
#define TROUBLE_HIT 7
|
|
#define TROUBLE_LYCANTHROPE 6
|
|
#define TROUBLE_COLLAPSING 5
|
|
#define TROUBLE_STUCK_IN_WALL 4
|
|
#define TROUBLE_CURSED_LEVITATION 3
|
|
#define TROUBLE_UNUSEABLE_HANDS 2
|
|
#define TROUBLE_CURSED_BLINDFOLD 1
|
|
|
|
#define TROUBLE_PUNISHED (-1)
|
|
#define TROUBLE_FUMBLING (-2)
|
|
#define TROUBLE_CURSED_ITEMS (-3)
|
|
#define TROUBLE_SADDLE (-4)
|
|
#define TROUBLE_BLIND (-5)
|
|
#define TROUBLE_POISONED (-6)
|
|
#define TROUBLE_WOUNDED_LEGS (-7)
|
|
#define TROUBLE_HUNGRY (-8)
|
|
#define TROUBLE_STUNNED (-9)
|
|
#define TROUBLE_CONFUSED (-10)
|
|
#define TROUBLE_HALLUCINATION (-11)
|
|
|
|
|
|
#define ugod_is_angry() (u.ualign.record < 0)
|
|
#define on_altar() IS_ALTAR(levl[u.ux][u.uy].typ)
|
|
#define on_shrine() ((levl[u.ux][u.uy].altarmask & AM_SHRINE) != 0)
|
|
#define a_align(x, y) ((aligntyp) Amask2align(levl[x][y].altarmask & AM_MASK))
|
|
|
|
/* critically low hit points if hp <= 5 or hp <= maxhp/N for some N */
|
|
boolean
|
|
critically_low_hp(boolean only_if_injured) /* determines whether maxhp <= 5
|
|
matters */
|
|
{
|
|
int divisor, hplim, curhp = Upolyd ? u.mh : u.uhp,
|
|
maxhp = Upolyd ? u.mhmax : u.uhpmax;
|
|
|
|
if (only_if_injured && !(curhp < maxhp))
|
|
return FALSE;
|
|
/* if maxhp is extremely high, use lower threshold for the division test
|
|
(golden glow cuts off at 11+5*lvl, nurse interaction at 25*lvl; this
|
|
ought to use monster hit dice--and a smaller multiplier--rather than
|
|
ulevel when polymorphed, but polyself doesn't maintain that) */
|
|
hplim = 15 * u.ulevel;
|
|
if (maxhp > hplim)
|
|
maxhp = hplim;
|
|
/* 7 used to be the unconditional divisor */
|
|
switch (xlev_to_rank(u.ulevel)) { /* maps 1..30 into 0..8 */
|
|
case 0:
|
|
case 1:
|
|
divisor = 5;
|
|
break; /* explvl 1 to 5 */
|
|
case 2:
|
|
case 3:
|
|
divisor = 6;
|
|
break; /* explvl 6 to 13 */
|
|
case 4:
|
|
case 5:
|
|
divisor = 7;
|
|
break; /* explvl 14 to 21 */
|
|
case 6:
|
|
case 7:
|
|
divisor = 8;
|
|
break; /* explvl 22 to 29 */
|
|
default:
|
|
divisor = 9;
|
|
break; /* explvl 30+ */
|
|
}
|
|
/* 5 is a magic number in TROUBLE_HIT handling below */
|
|
return (boolean) (curhp <= 5 || curhp * divisor <= maxhp);
|
|
}
|
|
|
|
/* return True if surrounded by impassible rock, regardless of the state
|
|
of your own location (for example, inside a doorless closet) */
|
|
boolean
|
|
stuck_in_wall(void)
|
|
{
|
|
int i, j, x, y, count = 0;
|
|
|
|
if (Passes_walls)
|
|
return FALSE;
|
|
for (i = -1; i <= 1; i++) {
|
|
x = u.ux + i;
|
|
for (j = -1; j <= 1; j++) {
|
|
if (!i && !j)
|
|
continue;
|
|
y = u.uy + j;
|
|
if (!isok(x, y)
|
|
|| (IS_ROCK(levl[x][y].typ)
|
|
&& (levl[x][y].typ != SDOOR && levl[x][y].typ != SCORR))
|
|
|| (blocked_boulder(i, j) && !throws_rocks(gy.youmonst.data)))
|
|
++count;
|
|
}
|
|
}
|
|
return (count == 8) ? TRUE : FALSE;
|
|
}
|
|
|
|
/*
|
|
* Return 0 if nothing particular seems wrong, positive numbers for
|
|
* serious trouble, and negative numbers for comparative annoyances.
|
|
* This returns the worst problem. There may be others, and the gods
|
|
* may fix more than one.
|
|
*
|
|
* This could get as bizarre as noting surrounding opponents, (or
|
|
* hostile dogs), but that's really hard.
|
|
*
|
|
* We could force rehumanize of polyselfed people, but we can't tell
|
|
* unintentional shape changes from the other kind. Oh well.
|
|
* 3.4.2: make an exception if polymorphed into a form which lacks
|
|
* hands; that's a case where the ramifications override this doubt.
|
|
*/
|
|
static int
|
|
in_trouble(void)
|
|
{
|
|
struct obj *otmp;
|
|
int i;
|
|
|
|
/*
|
|
* major troubles
|
|
*/
|
|
if (Stoned)
|
|
return TROUBLE_STONED;
|
|
if (Slimed)
|
|
return TROUBLE_SLIMED;
|
|
if (Strangled)
|
|
return TROUBLE_STRANGLED;
|
|
if (u.utrap && u.utraptype == TT_LAVA)
|
|
return TROUBLE_LAVA;
|
|
if (Sick)
|
|
return TROUBLE_SICK;
|
|
if (u.uhs >= WEAK)
|
|
return TROUBLE_STARVING;
|
|
if (region_danger())
|
|
return TROUBLE_REGION;
|
|
if (critically_low_hp(FALSE))
|
|
return TROUBLE_HIT;
|
|
if (u.ulycn >= LOW_PM)
|
|
return TROUBLE_LYCANTHROPE;
|
|
if (near_capacity() >= EXT_ENCUMBER && AMAX(A_STR) - ABASE(A_STR) > 3)
|
|
return TROUBLE_COLLAPSING;
|
|
if (stuck_in_wall())
|
|
return TROUBLE_STUCK_IN_WALL;
|
|
if (Cursed_obj(uarmf, LEVITATION_BOOTS)
|
|
|| stuck_ring(uleft, RIN_LEVITATION)
|
|
|| stuck_ring(uright, RIN_LEVITATION))
|
|
return TROUBLE_CURSED_LEVITATION;
|
|
if (nohands(gy.youmonst.data) || !freehand()) {
|
|
/* for bag/box access [cf use_container()]...
|
|
make sure it's a case that we know how to handle;
|
|
otherwise "fix all troubles" would get stuck in a loop */
|
|
if (welded(uwep))
|
|
return TROUBLE_UNUSEABLE_HANDS;
|
|
if (Upolyd && nohands(gy.youmonst.data)
|
|
&& (!Unchanging || ((otmp = unchanger()) != 0 && otmp->cursed)))
|
|
return TROUBLE_UNUSEABLE_HANDS;
|
|
}
|
|
if (Blindfolded && ublindf->cursed)
|
|
return TROUBLE_CURSED_BLINDFOLD;
|
|
|
|
/*
|
|
* minor troubles
|
|
*/
|
|
if (Punished || (u.utrap && u.utraptype == TT_BURIEDBALL))
|
|
return TROUBLE_PUNISHED;
|
|
if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING)
|
|
|| Cursed_obj(uarmf, FUMBLE_BOOTS))
|
|
return TROUBLE_FUMBLING;
|
|
if (worst_cursed_item())
|
|
return TROUBLE_CURSED_ITEMS;
|
|
if (u.usteed) { /* can't voluntarily dismount from a cursed saddle */
|
|
otmp = which_armor(u.usteed, W_SADDLE);
|
|
if (Cursed_obj(otmp, SADDLE))
|
|
return TROUBLE_SADDLE;
|
|
}
|
|
|
|
if (Blinded > 1 && haseyes(gy.youmonst.data)
|
|
&& (!u.uswallow
|
|
|| !attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND)))
|
|
return TROUBLE_BLIND;
|
|
/* deafness isn't it's own trouble; healing magic cures deafness
|
|
when it cures blindness, so do the same with trouble repair */
|
|
if ((HDeaf & TIMEOUT) > 1L)
|
|
return TROUBLE_BLIND;
|
|
|
|
for (i = 0; i < A_MAX; i++)
|
|
if (ABASE(i) < AMAX(i))
|
|
return TROUBLE_POISONED;
|
|
if (Wounded_legs && !u.usteed)
|
|
return TROUBLE_WOUNDED_LEGS;
|
|
if (u.uhs >= HUNGRY)
|
|
return TROUBLE_HUNGRY;
|
|
if (HStun & TIMEOUT)
|
|
return TROUBLE_STUNNED;
|
|
if (HConfusion & TIMEOUT)
|
|
return TROUBLE_CONFUSED;
|
|
if (HHallucination & TIMEOUT)
|
|
return TROUBLE_HALLUCINATION;
|
|
return 0;
|
|
}
|
|
|
|
/* select an item for TROUBLE_CURSED_ITEMS */
|
|
static struct obj *
|
|
worst_cursed_item(void)
|
|
{
|
|
register struct obj *otmp;
|
|
|
|
/* if strained or worse, check for loadstone first */
|
|
if (near_capacity() >= HVY_ENCUMBER) {
|
|
for (otmp = gi.invent; otmp; otmp = otmp->nobj)
|
|
if (Cursed_obj(otmp, LOADSTONE))
|
|
return otmp;
|
|
}
|
|
/* weapon takes precedence if it is interfering
|
|
with taking off a ring or putting on a shield */
|
|
if (welded(uwep) && (uright || bimanual(uwep))) { /* weapon */
|
|
otmp = uwep;
|
|
/* gloves come next, due to rings */
|
|
} else if (uarmg && uarmg->cursed) { /* gloves */
|
|
otmp = uarmg;
|
|
/* then shield due to two handed weapons and spells */
|
|
} else if (uarms && uarms->cursed) { /* shield */
|
|
otmp = uarms;
|
|
/* then cloak due to body armor */
|
|
} else if (uarmc && uarmc->cursed) { /* cloak */
|
|
otmp = uarmc;
|
|
} else if (uarm && uarm->cursed) { /* suit */
|
|
otmp = uarm;
|
|
/* if worn helmet of opposite alignment is making you an adherent
|
|
of the current god, he/she/it won't uncurse that for you */
|
|
} else if (uarmh && uarmh->cursed /* helmet */
|
|
&& uarmh->otyp != HELM_OF_OPPOSITE_ALIGNMENT) {
|
|
otmp = uarmh;
|
|
} else if (uarmf && uarmf->cursed) { /* boots */
|
|
otmp = uarmf;
|
|
} else if (uarmu && uarmu->cursed) { /* shirt */
|
|
otmp = uarmu;
|
|
} else if (uamul && uamul->cursed) { /* amulet */
|
|
otmp = uamul;
|
|
} else if (uleft && uleft->cursed) { /* left ring */
|
|
otmp = uleft;
|
|
} else if (uright && uright->cursed) { /* right ring */
|
|
otmp = uright;
|
|
} else if (ublindf && ublindf->cursed) { /* eyewear */
|
|
otmp = ublindf; /* must be non-blinding lenses */
|
|
/* if weapon wasn't handled above, do it now */
|
|
} else if (welded(uwep)) { /* weapon */
|
|
otmp = uwep;
|
|
/* active secondary weapon even though it isn't welded */
|
|
} else if (uswapwep && uswapwep->cursed && u.twoweap) {
|
|
otmp = uswapwep;
|
|
/* all worn items ought to be handled by now */
|
|
} else {
|
|
for (otmp = gi.invent; otmp; otmp = otmp->nobj) {
|
|
if (!otmp->cursed)
|
|
continue;
|
|
if (otmp->otyp == LOADSTONE || confers_luck(otmp))
|
|
break;
|
|
}
|
|
}
|
|
return otmp;
|
|
}
|
|
|
|
static void
|
|
fix_curse_trouble(struct obj *otmp, const char *what)
|
|
{
|
|
if (!otmp) {
|
|
impossible("fix_curse_trouble: nothing to uncurse.");
|
|
return;
|
|
}
|
|
if (otmp == uarmg && Glib) {
|
|
make_glib(0);
|
|
Your("%s are no longer slippery.", gloves_simple_name(uarmg));
|
|
if (!otmp->cursed)
|
|
return;
|
|
}
|
|
if (!Blind || (otmp == ublindf && Blindfolded_only)) {
|
|
pline("%s %s.",
|
|
what ? what : (const char *) Yobjnam2(otmp, "softly glow"),
|
|
hcolor(NH_AMBER));
|
|
iflags.last_msg = PLNMSG_OBJ_GLOWS;
|
|
otmp->bknown = !Hallucination; /* ok to skip set_bknown() */
|
|
}
|
|
uncurse(otmp);
|
|
update_inventory();
|
|
}
|
|
|
|
static void
|
|
fix_worst_trouble(int trouble)
|
|
{
|
|
int i;
|
|
struct obj *otmp = 0;
|
|
const char *what = (const char *) 0;
|
|
static NEARDATA const char leftglow[] = "Your left ring softly glows",
|
|
rightglow[] = "Your right ring softly glows";
|
|
|
|
switch (trouble) {
|
|
case TROUBLE_STONED:
|
|
make_stoned(0L, "You feel more limber.", 0, (char *) 0);
|
|
break;
|
|
case TROUBLE_SLIMED:
|
|
make_slimed(0L, "The slime disappears.");
|
|
break;
|
|
case TROUBLE_STRANGLED:
|
|
if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
|
|
Your("amulet vanishes!");
|
|
useup(uamul);
|
|
}
|
|
You("can breathe again.");
|
|
Strangled = 0;
|
|
gc.context.botl = 1;
|
|
break;
|
|
case TROUBLE_LAVA:
|
|
You("are back on solid ground.");
|
|
/* teleport should always succeed, but if not, just untrap them */
|
|
if (!safe_teleds(FALSE))
|
|
reset_utrap(TRUE);
|
|
break;
|
|
case TROUBLE_STARVING:
|
|
/* temporarily lost strength recovery now handled by init_uhunger() */
|
|
/*FALLTHRU*/
|
|
case TROUBLE_HUNGRY:
|
|
Your("%s feels content.", body_part(STOMACH));
|
|
init_uhunger();
|
|
gc.context.botl = 1;
|
|
break;
|
|
case TROUBLE_SICK:
|
|
You_feel("better.");
|
|
make_sick(0L, (char *) 0, FALSE, SICK_ALL);
|
|
break;
|
|
case TROUBLE_REGION:
|
|
/* stinking cloud, with hero vulnerable to HP loss */
|
|
region_safety();
|
|
break;
|
|
case TROUBLE_HIT:
|
|
/* "fix all troubles" will keep trying if hero has
|
|
5 or less hit points, so make sure they're always
|
|
boosted to be more than that */
|
|
You_feel("much better.");
|
|
if (Upolyd) {
|
|
u.mhmax += rnd(5);
|
|
if (u.mhmax <= 5)
|
|
u.mhmax = 5 + 1;
|
|
u.mh = u.mhmax;
|
|
}
|
|
if (u.uhpmax < u.ulevel * 5 + 11)
|
|
u.uhpmax += rnd(5);
|
|
if (u.uhpmax <= 5)
|
|
u.uhpmax = 5 + 1;
|
|
if (u.uhpmax > u.uhppeak)
|
|
u.uhppeak = u.uhpmax;
|
|
u.uhp = u.uhpmax;
|
|
gc.context.botl = 1;
|
|
break;
|
|
case TROUBLE_COLLAPSING:
|
|
/* override Fixed_abil; uncurse that if feasible */
|
|
You_feel("%sstronger.",
|
|
(AMAX(A_STR) - ABASE(A_STR) > 6) ? "much " : "");
|
|
ABASE(A_STR) = AMAX(A_STR);
|
|
gc.context.botl = 1;
|
|
if (Fixed_abil) {
|
|
if ((otmp = stuck_ring(uleft, RIN_SUSTAIN_ABILITY)) != 0) {
|
|
if (otmp == uleft)
|
|
what = leftglow;
|
|
} else if ((otmp = stuck_ring(uright, RIN_SUSTAIN_ABILITY)) != 0) {
|
|
if (otmp == uright)
|
|
what = rightglow;
|
|
}
|
|
if (otmp) {
|
|
fix_curse_trouble(otmp, what);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case TROUBLE_STUCK_IN_WALL:
|
|
/* no control, but works on no-teleport levels */
|
|
if (safe_teleds(FALSE)) {
|
|
Your("surroundings change.");
|
|
} else {
|
|
/* safe_teleds() couldn't find a safe place; perhaps the
|
|
level is completely full. As a last resort, confer
|
|
intrinsic wall/rock-phazing. Hero might get stuck
|
|
again fairly soon....
|
|
Without something like this, fix_all_troubles can get
|
|
stuck in an infinite loop trying to fix STUCK_IN_WALL
|
|
and repeatedly failing. */
|
|
set_itimeout(&HPasses_walls, (long) (d(4, 4) + 4)); /* 8..20 */
|
|
/* how else could you move between packed rocks or among
|
|
lattice forming "solid" rock? */
|
|
You_feel("much slimmer.");
|
|
}
|
|
break;
|
|
case TROUBLE_CURSED_LEVITATION:
|
|
if (Cursed_obj(uarmf, LEVITATION_BOOTS)) {
|
|
otmp = uarmf;
|
|
} else if ((otmp = stuck_ring(uleft, RIN_LEVITATION)) != 0) {
|
|
if (otmp == uleft)
|
|
what = leftglow;
|
|
} else if ((otmp = stuck_ring(uright, RIN_LEVITATION)) != 0) {
|
|
if (otmp == uright)
|
|
what = rightglow;
|
|
}
|
|
fix_curse_trouble(otmp, what);
|
|
break;
|
|
case TROUBLE_UNUSEABLE_HANDS:
|
|
if (welded(uwep)) {
|
|
otmp = uwep;
|
|
fix_curse_trouble(otmp, what);
|
|
break;
|
|
}
|
|
if (Upolyd && nohands(gy.youmonst.data)) {
|
|
if (!Unchanging) {
|
|
Your("shape becomes uncertain.");
|
|
rehumanize(); /* "You return to {normal} form." */
|
|
} else if ((otmp = unchanger()) != 0 && otmp->cursed) {
|
|
/* otmp is an amulet of unchanging */
|
|
fix_curse_trouble(otmp, what);
|
|
break;
|
|
}
|
|
}
|
|
if (nohands(gy.youmonst.data) || !freehand())
|
|
impossible("fix_worst_trouble: couldn't cure hands.");
|
|
break;
|
|
case TROUBLE_CURSED_BLINDFOLD:
|
|
otmp = ublindf;
|
|
fix_curse_trouble(otmp, what);
|
|
break;
|
|
case TROUBLE_LYCANTHROPE:
|
|
you_unwere(TRUE);
|
|
break;
|
|
/*
|
|
*/
|
|
case TROUBLE_PUNISHED:
|
|
Your("chain disappears.");
|
|
if (u.utrap && u.utraptype == TT_BURIEDBALL)
|
|
buried_ball_to_freedom();
|
|
else
|
|
unpunish();
|
|
break;
|
|
case TROUBLE_FUMBLING:
|
|
if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING))
|
|
otmp = uarmg;
|
|
else if (Cursed_obj(uarmf, FUMBLE_BOOTS))
|
|
otmp = uarmf;
|
|
fix_curse_trouble(otmp, what);
|
|
break;
|
|
case TROUBLE_CURSED_ITEMS:
|
|
otmp = worst_cursed_item();
|
|
if (otmp == uright)
|
|
what = rightglow;
|
|
else if (otmp == uleft)
|
|
what = leftglow;
|
|
fix_curse_trouble(otmp, what);
|
|
break;
|
|
case TROUBLE_POISONED:
|
|
/* override Fixed_abil; ignore items which confer that */
|
|
if (Hallucination)
|
|
pline("There's a tiger in your tank.");
|
|
else
|
|
You_feel("in good health again.");
|
|
for (i = 0; i < A_MAX; i++) {
|
|
if (ABASE(i) < AMAX(i)) {
|
|
ABASE(i) = AMAX(i);
|
|
gc.context.botl = 1;
|
|
}
|
|
}
|
|
(void) encumber_msg();
|
|
break;
|
|
case TROUBLE_BLIND: { /* handles deafness as well as blindness */
|
|
char msgbuf[BUFSZ];
|
|
const char *eyes = body_part(EYE);
|
|
boolean cure_deaf = (HDeaf & TIMEOUT) ? TRUE : FALSE;
|
|
|
|
msgbuf[0] = '\0';
|
|
if (Blinded) {
|
|
if (eyecount(gy.youmonst.data) != 1)
|
|
eyes = makeplural(eyes);
|
|
Sprintf(msgbuf, "Your %s %s better", eyes, vtense(eyes, "feel"));
|
|
u.ucreamed = 0;
|
|
make_blinded(0L, FALSE);
|
|
}
|
|
if (cure_deaf) {
|
|
make_deaf(0L, FALSE);
|
|
if (!Deaf)
|
|
Sprintf(eos(msgbuf), "%s can hear again",
|
|
!*msgbuf ? "You" : " and you");
|
|
}
|
|
if (*msgbuf)
|
|
pline("%s.", msgbuf);
|
|
break;
|
|
}
|
|
case TROUBLE_WOUNDED_LEGS:
|
|
heal_legs(0);
|
|
break;
|
|
case TROUBLE_STUNNED:
|
|
make_stunned(0L, TRUE);
|
|
break;
|
|
case TROUBLE_CONFUSED:
|
|
make_confused(0L, TRUE);
|
|
break;
|
|
case TROUBLE_HALLUCINATION:
|
|
pline("Looks like you are back in Kansas.");
|
|
(void) make_hallucinated(0L, FALSE, 0L);
|
|
break;
|
|
case TROUBLE_SADDLE:
|
|
otmp = which_armor(u.usteed, W_SADDLE);
|
|
if (!Blind) {
|
|
pline("%s %s.", Yobjnam2(otmp, "softly glow"), hcolor(NH_AMBER));
|
|
set_bknown(otmp, 1);
|
|
}
|
|
uncurse(otmp);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* "I am sometimes shocked by... the nuns who never take a bath without
|
|
* wearing a bathrobe all the time. When asked why, since no man can see them,
|
|
* they reply 'Oh, but you forget the good God'. Apparently they conceive of
|
|
* the Deity as a Peeping Tom, whose omnipotence enables Him to see through
|
|
* bathroom walls, but who is foiled by bathrobes." --Bertrand Russell, 1943
|
|
* Divine wrath, dungeon walls, and armor follow the same principle.
|
|
*/
|
|
static void
|
|
god_zaps_you(aligntyp resp_god)
|
|
{
|
|
if (u.uswallow) {
|
|
pline(
|
|
"Suddenly a bolt of lightning comes down at you from the heavens!");
|
|
pline("It strikes %s!", mon_nam(u.ustuck));
|
|
if (!resists_elec(u.ustuck)) {
|
|
pline("%s fries to a crisp!", Monnam(u.ustuck));
|
|
/* Yup, you get experience. It takes guts to successfully
|
|
* pull off this trick on your god, anyway.
|
|
* Other credit/blame applies (luck or alignment adjustments),
|
|
* but not direct kill count (pacifist conduct).
|
|
*/
|
|
xkilled(u.ustuck, XKILL_NOMSG | XKILL_NOCONDUCT);
|
|
} else
|
|
pline("%s seems unaffected.", Monnam(u.ustuck));
|
|
} else {
|
|
pline("Suddenly, a bolt of lightning strikes you!");
|
|
if (Reflecting) {
|
|
shieldeff(u.ux, u.uy);
|
|
if (Blind)
|
|
pline("For some reason you're unaffected.");
|
|
else
|
|
(void) ureflects("%s reflects from your %s.", "It");
|
|
monstseesu(M_SEEN_REFL);
|
|
} else if (Shock_resistance) {
|
|
shieldeff(u.ux, u.uy);
|
|
pline("It seems not to affect you.");
|
|
monstseesu(M_SEEN_ELEC);
|
|
} else
|
|
fry_by_god(resp_god, FALSE);
|
|
}
|
|
|
|
pline("%s is not deterred...", align_gname(resp_god));
|
|
if (u.uswallow) {
|
|
pline("A wide-angle disintegration beam aimed at you hits %s!",
|
|
mon_nam(u.ustuck));
|
|
if (!resists_disint(u.ustuck)) {
|
|
pline("%s disintegrates into a pile of dust!", Monnam(u.ustuck));
|
|
xkilled(u.ustuck, XKILL_NOMSG | XKILL_NOCORPSE | XKILL_NOCONDUCT);
|
|
} else
|
|
pline("%s seems unaffected.", Monnam(u.ustuck));
|
|
} else {
|
|
pline("A wide-angle disintegration beam hits you!");
|
|
|
|
/* disintegrate shield and body armor before disintegrating
|
|
* the impudent mortal, like black dragon breath -3.
|
|
*/
|
|
if (uarms && !(EReflecting & W_ARMS)
|
|
&& !(EDisint_resistance & W_ARMS))
|
|
(void) destroy_arm(uarms);
|
|
if (uarmc && !(EReflecting & W_ARMC)
|
|
&& !(EDisint_resistance & W_ARMC))
|
|
(void) destroy_arm(uarmc);
|
|
if (uarm && !(EReflecting & W_ARM) && !(EDisint_resistance & W_ARM)
|
|
&& !uarmc)
|
|
(void) destroy_arm(uarm);
|
|
if (uarmu && !uarm && !uarmc)
|
|
(void) destroy_arm(uarmu);
|
|
if (!Disint_resistance) {
|
|
fry_by_god(resp_god, TRUE);
|
|
} else {
|
|
You("bask in its %s glow for a minute...", NH_BLACK);
|
|
godvoice(resp_god, "I believe it not!");
|
|
monstseesu(M_SEEN_DISINT);
|
|
}
|
|
if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) {
|
|
/* one more try for high altars */
|
|
verbalize("Thou cannot escape my wrath, mortal!");
|
|
summon_minion(resp_god, FALSE);
|
|
summon_minion(resp_god, FALSE);
|
|
summon_minion(resp_god, FALSE);
|
|
verbalize("Destroy %s, my servants!", uhim());
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
fry_by_god(aligntyp resp_god, boolean via_disintegration)
|
|
{
|
|
You("%s!", !via_disintegration ? "fry to a crisp"
|
|
: "disintegrate into a pile of dust");
|
|
gk.killer.format = KILLED_BY;
|
|
Sprintf(gk.killer.name, "the wrath of %s", align_gname(resp_god));
|
|
done(DIED);
|
|
}
|
|
|
|
static void
|
|
angrygods(aligntyp resp_god)
|
|
{
|
|
int maxanger, new_ublesscnt;
|
|
|
|
if (Inhell)
|
|
resp_god = A_NONE;
|
|
u.ublessed = 0; /* lose divine protection */
|
|
|
|
/* changed from tmp = u.ugangr + abs (u.uluck) -- rph */
|
|
/* added test for alignment diff -dlc */
|
|
if (resp_god != u.ualign.type)
|
|
maxanger = u.ualign.record / 2 + (Luck > 0 ? -Luck / 3 : -Luck);
|
|
else
|
|
maxanger = 3 * u.ugangr + ((Luck > 0 || u.ualign.record >= STRIDENT)
|
|
? -Luck / 3
|
|
: -Luck);
|
|
if (maxanger < 1)
|
|
maxanger = 1; /* possible if bad align & good luck */
|
|
else if (maxanger > 15)
|
|
maxanger = 15; /* be reasonable */
|
|
|
|
switch (rn2(maxanger)) {
|
|
case 0:
|
|
case 1:
|
|
You_feel("that %s is %s.", align_gname(resp_god),
|
|
Hallucination ? "bummed" : "displeased");
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
godvoice(resp_god, (char *) 0);
|
|
pline("\"Thou %s, %s.\"",
|
|
(ugod_is_angry() && resp_god == u.ualign.type)
|
|
? "hast strayed from the path"
|
|
: "art arrogant",
|
|
gy.youmonst.data->mlet == S_HUMAN ? "mortal" : "creature");
|
|
verbalize("Thou must relearn thy lessons!");
|
|
(void) adjattrib(A_WIS, -1, FALSE);
|
|
losexp((char *) 0);
|
|
break;
|
|
case 6:
|
|
if (!Punished) {
|
|
gods_angry(resp_god);
|
|
punish((struct obj *) 0);
|
|
break;
|
|
} /* else fall thru */
|
|
case 4:
|
|
case 5:
|
|
gods_angry(resp_god);
|
|
if (!Blind && !Antimagic)
|
|
pline("%s glow surrounds you.", An(hcolor(NH_BLACK)));
|
|
rndcurse();
|
|
break;
|
|
case 7:
|
|
case 8:
|
|
godvoice(resp_god, (char *) 0);
|
|
verbalize("Thou durst %s me?",
|
|
(on_altar() && (a_align(u.ux, u.uy) != resp_god))
|
|
? "scorn"
|
|
: "call upon");
|
|
/* [why isn't this using verbalize()?] */
|
|
pline("\"Then die, %s!\"",
|
|
(gy.youmonst.data->mlet == S_HUMAN) ? "mortal" : "creature");
|
|
summon_minion(resp_god, FALSE);
|
|
break;
|
|
|
|
default:
|
|
gods_angry(resp_god);
|
|
god_zaps_you(resp_god);
|
|
break;
|
|
}
|
|
/* even though this might not be in response to prayer, set pray timer */
|
|
new_ublesscnt = rnz(300);
|
|
if (new_ublesscnt > u.ublesscnt)
|
|
u.ublesscnt = new_ublesscnt;
|
|
return;
|
|
}
|
|
|
|
/* helper to print "str appears at your feet", or appropriate */
|
|
static void
|
|
at_your_feet(const char *str)
|
|
{
|
|
if (Blind)
|
|
str = Something;
|
|
if (u.uswallow) {
|
|
/* barrier between you and the floor */
|
|
pline("%s %s into %s %s.", str, vtense(str, "drop"),
|
|
s_suffix(mon_nam(u.ustuck)), mbodypart(u.ustuck, STOMACH));
|
|
} else {
|
|
pline("%s %s %s your %s!", str,
|
|
vtense(str, Blind ? "land" : "appear"),
|
|
Levitation ? "beneath" : "at",
|
|
makeplural(body_part(FOOT)));
|
|
}
|
|
}
|
|
|
|
static void
|
|
gcrownu(void)
|
|
{
|
|
struct obj *obj;
|
|
const char *what;
|
|
boolean already_exists, in_hand;
|
|
short class_gift;
|
|
#define ok_wep(o) ((o) && ((o)->oclass == WEAPON_CLASS || is_weptool(o)))
|
|
|
|
HSee_invisible |= FROMOUTSIDE;
|
|
HFire_resistance |= FROMOUTSIDE;
|
|
HCold_resistance |= FROMOUTSIDE;
|
|
HShock_resistance |= FROMOUTSIDE;
|
|
HSleep_resistance |= FROMOUTSIDE;
|
|
HPoison_resistance |= FROMOUTSIDE;
|
|
godvoice(u.ualign.type, (char *) 0);
|
|
|
|
class_gift = STRANGE_OBJECT;
|
|
/* 3.3.[01] had this in the A_NEUTRAL case,
|
|
preventing chaotic wizards from receiving a spellbook */
|
|
if (Role_if(PM_WIZARD)
|
|
&& !u_wield_art(ART_VORPAL_BLADE)
|
|
&& !u_wield_art(ART_STORMBRINGER)
|
|
&& !carrying(SPE_FINGER_OF_DEATH)) {
|
|
class_gift = SPE_FINGER_OF_DEATH;
|
|
} else if (Role_if(PM_MONK) && (!uwep || !uwep->oartifact)
|
|
&& !carrying(SPE_RESTORE_ABILITY)) {
|
|
/* monks rarely wield a weapon */
|
|
class_gift = SPE_RESTORE_ABILITY;
|
|
}
|
|
|
|
obj = ok_wep(uwep) ? uwep : 0;
|
|
already_exists = in_hand = FALSE; /* lint suppression */
|
|
switch (u.ualign.type) {
|
|
case A_LAWFUL:
|
|
u.uevent.uhand_of_elbereth = 1;
|
|
verbalize("I crown thee... The Hand of Elbereth!");
|
|
livelog_printf(LL_DIVINEGIFT,
|
|
"was crowned \"The Hand of Elbereth\" by %s",
|
|
u_gname());
|
|
break;
|
|
case A_NEUTRAL:
|
|
u.uevent.uhand_of_elbereth = 2;
|
|
in_hand = u_wield_art(ART_VORPAL_BLADE);
|
|
already_exists = exist_artifact(LONG_SWORD,
|
|
artiname(ART_VORPAL_BLADE));
|
|
verbalize("Thou shalt be my Envoy of Balance!");
|
|
livelog_printf(LL_DIVINEGIFT, "became %s Envoy of Balance",
|
|
s_suffix(u_gname()));
|
|
break;
|
|
case A_CHAOTIC:
|
|
u.uevent.uhand_of_elbereth = 3;
|
|
in_hand = u_wield_art(ART_STORMBRINGER);
|
|
already_exists = exist_artifact(RUNESWORD, artiname(ART_STORMBRINGER));
|
|
what = (((already_exists && !in_hand) || class_gift != STRANGE_OBJECT)
|
|
? "take lives"
|
|
: "steal souls");
|
|
verbalize("Thou art chosen to %s for My Glory!", what);
|
|
livelog_printf(LL_DIVINEGIFT, "was chosen to %s for the Glory of %s",
|
|
what, u_gname());
|
|
break;
|
|
}
|
|
|
|
if (objects[class_gift].oc_class == SPBOOK_CLASS) {
|
|
char bbuf[BUFSZ];
|
|
|
|
obj = mksobj(class_gift, TRUE, FALSE);
|
|
/* get book type before dropping (don't think that could destroy
|
|
the book because we need to be on an altar in order to become
|
|
crowned, but be paranoid about it) */
|
|
Strcpy(bbuf, actualoname(obj)); /* for livelog; "spellbook of <foo>"
|
|
* even if hero doesn't know book */
|
|
bless(obj);
|
|
obj->bknown = 1; /* ok to skip set_bknown() */
|
|
obj->dknown = 1;
|
|
at_your_feet(upstart(ansimpleoname(obj)));
|
|
dropy(obj);
|
|
u.ugifts++;
|
|
/* not an artifact, but treat like one for this situation;
|
|
classify as a spoiler in case player hasn't IDed the book yet */
|
|
livelog_printf(LL_DIVINEGIFT | LL_ARTIFACT | LL_SPOILER,
|
|
"was bestowed with %s", bbuf);
|
|
|
|
/* when getting a new book for known spell, enhance
|
|
currently wielded weapon rather than the book */
|
|
if (known_spell(class_gift) != spe_Unknown && ok_wep(uwep))
|
|
obj = uwep; /* to be blessed,&c */
|
|
}
|
|
|
|
switch (u.ualign.type) {
|
|
case A_LAWFUL:
|
|
if (class_gift != STRANGE_OBJECT) {
|
|
; /* already got bonus above */
|
|
} else if (obj && obj->otyp == LONG_SWORD && !obj->oartifact) {
|
|
char lbuf[BUFSZ];
|
|
|
|
Strcpy(lbuf, simpleonames(obj)); /* before transformation */
|
|
if (!Blind)
|
|
Your("sword shines brightly for a moment.");
|
|
obj = oname(obj, artiname(ART_EXCALIBUR),
|
|
ONAME_GIFT | ONAME_KNOW_ARTI);
|
|
if (is_art(obj, ART_EXCALIBUR)) {
|
|
u.ugifts++;
|
|
livelog_printf(LL_DIVINEGIFT | LL_ARTIFACT,
|
|
"had %s wielded %s transformed into %s",
|
|
uhis(), lbuf, artiname(ART_EXCALIBUR));
|
|
}
|
|
}
|
|
/* acquire Excalibur's skill regardless of weapon or gift */
|
|
unrestrict_weapon_skill(P_LONG_SWORD);
|
|
if (is_art(obj, ART_EXCALIBUR))
|
|
discover_artifact(ART_EXCALIBUR);
|
|
break;
|
|
case A_NEUTRAL:
|
|
if (class_gift != STRANGE_OBJECT) {
|
|
; /* already got bonus above */
|
|
} else if (obj && in_hand) {
|
|
Your("%s goes snicker-snack!", xname(obj));
|
|
obj->dknown = 1;
|
|
} else if (!already_exists) {
|
|
obj = mksobj(LONG_SWORD, FALSE, FALSE);
|
|
obj = oname(obj, artiname(ART_VORPAL_BLADE),
|
|
ONAME_GIFT | ONAME_KNOW_ARTI);
|
|
obj->spe = 1;
|
|
at_your_feet("A sword");
|
|
dropy(obj);
|
|
u.ugifts++;
|
|
livelog_printf(LL_DIVINEGIFT | LL_ARTIFACT,
|
|
"was bestowed with %s",
|
|
artiname(ART_VORPAL_BLADE));
|
|
}
|
|
/* acquire Vorpal Blade's skill regardless of weapon or gift */
|
|
unrestrict_weapon_skill(P_LONG_SWORD);
|
|
if (is_art(obj, ART_VORPAL_BLADE))
|
|
discover_artifact(ART_VORPAL_BLADE);
|
|
break;
|
|
case A_CHAOTIC: {
|
|
char swordbuf[BUFSZ];
|
|
|
|
Sprintf(swordbuf, "%s sword", hcolor(NH_BLACK));
|
|
if (class_gift != STRANGE_OBJECT) {
|
|
; /* already got bonus above */
|
|
} else if (obj && in_hand) {
|
|
Your("%s hums ominously!", swordbuf);
|
|
obj->dknown = 1;
|
|
} else if (!already_exists) {
|
|
obj = mksobj(RUNESWORD, FALSE, FALSE);
|
|
obj = oname(obj, artiname(ART_STORMBRINGER),
|
|
ONAME_GIFT | ONAME_KNOW_ARTI);
|
|
obj->spe = 1;
|
|
at_your_feet(An(swordbuf));
|
|
dropy(obj);
|
|
u.ugifts++;
|
|
livelog_printf(LL_DIVINEGIFT | LL_ARTIFACT,
|
|
"was bestowed with %s",
|
|
artiname(ART_STORMBRINGER));
|
|
}
|
|
/* acquire Stormbringer's skill regardless of weapon or gift */
|
|
unrestrict_weapon_skill(P_BROAD_SWORD);
|
|
if (is_art(obj, ART_STORMBRINGER))
|
|
discover_artifact(ART_STORMBRINGER);
|
|
break;
|
|
}
|
|
default:
|
|
obj = 0; /* lint */
|
|
break;
|
|
}
|
|
|
|
/* enhance weapon regardless of alignment or artifact status */
|
|
if (ok_wep(obj)) {
|
|
bless(obj);
|
|
obj->oeroded = obj->oeroded2 = 0;
|
|
obj->oerodeproof = TRUE;
|
|
obj->bknown = obj->rknown = 1; /* ok to skip set_bknown() */
|
|
if (obj->spe < 1)
|
|
obj->spe = 1;
|
|
/* acquire skill in this weapon */
|
|
unrestrict_weapon_skill(weapon_type(obj));
|
|
} else if (class_gift == STRANGE_OBJECT) {
|
|
/* opportunity knocked, but there was nobody home... */
|
|
You_feel("unworthy.");
|
|
}
|
|
update_inventory();
|
|
|
|
/* lastly, confer an extra skill slot/credit beyond the
|
|
up-to-29 you can get from gaining experience levels */
|
|
add_weapon_skill(1);
|
|
return;
|
|
}
|
|
|
|
static void
|
|
give_spell(void)
|
|
{
|
|
struct obj *otmp;
|
|
char spe_let;
|
|
int spe_knowledge, trycnt = u.ulevel + 1;
|
|
|
|
/* not yet known spells and forgotten spells are given preference over
|
|
usable ones; also, try to grant spell that hero could gain skill in
|
|
(even though being restricted doesn't prevent learning and casting) */
|
|
otmp = mkobj(SPBOOK_no_NOVEL, TRUE);
|
|
while (--trycnt > 0) {
|
|
if (otmp->otyp != SPE_BLANK_PAPER) {
|
|
if (known_spell(otmp->otyp) <= spe_Unknown
|
|
&& !P_RESTRICTED(spell_skilltype(otmp->otyp)))
|
|
break; /* forgotten or not yet known */
|
|
} else {
|
|
/* blank paper is acceptable if not discovered yet or
|
|
if hero has a magic marker to write something on it
|
|
(doesn't matter if marker is out of charges); it will
|
|
become discovered (below) without needing to be read */
|
|
if (!objects[SPE_BLANK_PAPER].oc_name_known
|
|
|| carrying(MAGIC_MARKER))
|
|
break;
|
|
}
|
|
otmp->otyp = rnd_class(gb.bases[SPBOOK_CLASS], SPE_BLANK_PAPER);
|
|
}
|
|
/*
|
|
* 25% chance of learning the spell directly instead of
|
|
* receiving the book for it, unless it's already well known.
|
|
* The chance is not influenced by whether hero is illiterate.
|
|
*/
|
|
if (otmp->otyp != SPE_BLANK_PAPER && !rn2(4)
|
|
&& (spe_knowledge = known_spell(otmp->otyp)) != spe_Fresh) {
|
|
/* force_learn_spell() should only return '\0' if the book
|
|
is blank paper or the spell is known and has retention
|
|
of spe_Fresh, so no 'else' case is needed here */
|
|
if ((spe_let = force_learn_spell(otmp->otyp)) != '\0') {
|
|
/* for spellbook class, OBJ_NAME() yields the name of
|
|
the spell rather than "spellbook of <spell-name>" */
|
|
const char *spe_name = OBJ_NAME(objects[otmp->otyp]);
|
|
|
|
if (spe_knowledge == spe_Unknown) /* prior to learning */
|
|
/* appending "spell 'a'" seems slightly silly but
|
|
is similar to "added to your repertoire, as 'a'"
|
|
and without any spellbook on hand a novice player
|
|
might not recognize that 'spe_name' is a spell */
|
|
pline("Divine knowledge of %s fills your mind! Spell '%c'.",
|
|
spe_name, spe_let);
|
|
else
|
|
Your("knowledge of spell '%c' - %s is %s.",
|
|
spe_let, spe_name,
|
|
(spe_knowledge == spe_Forgotten) ? "restored"
|
|
: "refreshed");
|
|
}
|
|
obfree(otmp, (struct obj *) 0); /* discard the book */
|
|
} else {
|
|
otmp->dknown = 1; /* not bknown */
|
|
/* discovering blank paper will make it less likely to
|
|
be given again; small chance to arbitrarily discover
|
|
some other book type without having to read it first */
|
|
if (otmp->otyp == SPE_BLANK_PAPER || !rn2(100))
|
|
makeknown(otmp->otyp);
|
|
bless(otmp);
|
|
at_your_feet(upstart(ansimpleoname(otmp)));
|
|
place_object(otmp, u.ux, u.uy);
|
|
newsym(u.ux, u.uy);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
pleased(aligntyp g_align)
|
|
{
|
|
/* don't use p_trouble, worst trouble may get fixed while praying */
|
|
int trouble = in_trouble(); /* what's your worst difficulty? */
|
|
int pat_on_head = 0, kick_on_butt;
|
|
|
|
You_feel("that %s is %s.", align_gname(g_align),
|
|
(u.ualign.record >= DEVOUT)
|
|
? Hallucination ? "pleased as punch" : "well-pleased"
|
|
: (u.ualign.record >= STRIDENT)
|
|
? Hallucination ? "ticklish" : "pleased"
|
|
: Hallucination ? "full" : "satisfied");
|
|
|
|
/* not your deity */
|
|
if (on_altar() && gp.p_aligntyp != u.ualign.type) {
|
|
adjalign(-1);
|
|
return;
|
|
} else if (u.ualign.record < 2 && trouble <= 0)
|
|
adjalign(1);
|
|
|
|
/*
|
|
* Depending on your luck & align level, the god you prayed to will:
|
|
* - fix your worst problem if it's major;
|
|
* - fix all your major problems;
|
|
* - fix your worst problem if it's minor;
|
|
* - fix all of your problems;
|
|
* - do you a gratuitous favor.
|
|
*
|
|
* If you make it to the last category, you roll randomly again
|
|
* to see what they do for you.
|
|
*
|
|
* If your luck is at least 0, then you are guaranteed rescued from
|
|
* your worst major problem.
|
|
*/
|
|
if (!trouble && u.ualign.record >= DEVOUT) {
|
|
/* if hero was in trouble, but got better, no special favor */
|
|
if (gp.p_trouble == 0)
|
|
pat_on_head = 1;
|
|
} else {
|
|
int action, prayer_luck;
|
|
int tryct = 0;
|
|
|
|
/* Negative luck is normally impossible here (can_pray() forces
|
|
prayer failure in that situation), but it's possible for
|
|
Luck to drop during the period of prayer occupation and
|
|
become negative by the time we get here. [Reported case
|
|
was lawful character whose stinking cloud caused a delayed
|
|
killing of a peaceful human, triggering the "murderer"
|
|
penalty while successful prayer was in progress. It could
|
|
also happen due to inconvenient timing on Friday 13th, but
|
|
the magnitude there (-1) isn't big enough to cause trouble.]
|
|
We don't bother remembering start-of-prayer luck, just make
|
|
sure it's at least -1 so that Luck+2 is big enough to avoid
|
|
a divide by zero crash when generating a random number. */
|
|
prayer_luck = max(Luck, -1); /* => (prayer_luck + 2 > 0) */
|
|
action = rn1(prayer_luck + (on_altar() ? 3 + on_shrine() : 2), 1);
|
|
if (!on_altar())
|
|
action = min(action, 3);
|
|
if (u.ualign.record < STRIDENT)
|
|
action = (u.ualign.record > 0 || !rnl(2)) ? 1 : 0;
|
|
|
|
switch (min(action, 5)) {
|
|
case 5:
|
|
pat_on_head = 1;
|
|
/*FALLTHRU*/
|
|
case 4:
|
|
do
|
|
fix_worst_trouble(trouble);
|
|
while ((trouble = in_trouble()) != 0);
|
|
break;
|
|
|
|
case 3:
|
|
fix_worst_trouble(trouble);
|
|
case 2:
|
|
/* arbitrary number of tries */
|
|
while ((trouble = in_trouble()) > 0 && (++tryct < 10))
|
|
fix_worst_trouble(trouble);
|
|
break;
|
|
|
|
case 1:
|
|
if (trouble > 0)
|
|
fix_worst_trouble(trouble);
|
|
case 0:
|
|
break; /* your god blows you off, too bad */
|
|
}
|
|
}
|
|
|
|
/* note: can't get pat_on_head unless all troubles have just been
|
|
fixed or there were no troubles to begin with; hallucination
|
|
won't be in effect so special handling for it is superfluous */
|
|
if (pat_on_head)
|
|
switch (rn2((Luck + 6) >> 1)) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
if (uwep && (welded(uwep) || uwep->oclass == WEAPON_CLASS
|
|
|| is_weptool(uwep))) {
|
|
char repair_buf[BUFSZ];
|
|
|
|
*repair_buf = '\0';
|
|
if (uwep->oeroded || uwep->oeroded2)
|
|
Sprintf(repair_buf, " and %s now as good as new",
|
|
otense(uwep, "are"));
|
|
|
|
if (uwep->cursed) {
|
|
if (!Blind) {
|
|
pline("%s %s%s.", Yobjnam2(uwep, "softly glow"),
|
|
hcolor(NH_AMBER), repair_buf);
|
|
iflags.last_msg = PLNMSG_OBJ_GLOWS;
|
|
} else
|
|
You_feel("the power of %s over %s.", u_gname(),
|
|
yname(uwep));
|
|
uncurse(uwep);
|
|
uwep->bknown = 1; /* ok to bypass set_bknown() */
|
|
*repair_buf = '\0';
|
|
} else if (!uwep->blessed) {
|
|
if (!Blind) {
|
|
pline("%s with %s aura%s.",
|
|
Yobjnam2(uwep, "softly glow"),
|
|
an(hcolor(NH_LIGHT_BLUE)), repair_buf);
|
|
iflags.last_msg = PLNMSG_OBJ_GLOWS;
|
|
} else
|
|
You_feel("the blessing of %s over %s.", u_gname(),
|
|
yname(uwep));
|
|
bless(uwep);
|
|
uwep->bknown = 1; /* ok to bypass set_bknown() */
|
|
*repair_buf = '\0';
|
|
}
|
|
|
|
/* fix any rust/burn/rot damage, but don't protect
|
|
against future damage */
|
|
if (uwep->oeroded || uwep->oeroded2) {
|
|
uwep->oeroded = uwep->oeroded2 = 0;
|
|
/* only give this message if we didn't just bless
|
|
or uncurse (which has already given a message) */
|
|
if (*repair_buf)
|
|
pline("%s as good as new!",
|
|
Yobjnam2(uwep, Blind ? "feel" : "look"));
|
|
}
|
|
update_inventory();
|
|
}
|
|
break;
|
|
case 3:
|
|
/* takes 2 hints to get the music to enter the stronghold;
|
|
skip if you've solved it via mastermind or destroyed the
|
|
drawbridge (both set uopened_dbridge) or if you've already
|
|
travelled past the Valley of the Dead (gehennom_entered) */
|
|
if (!u.uevent.uopened_dbridge && !u.uevent.gehennom_entered) {
|
|
if (u.uevent.uheard_tune < 1) {
|
|
godvoice(g_align, (char *) 0);
|
|
verbalize("Hark, %s!", (gy.youmonst.data->mlet == S_HUMAN)
|
|
? "mortal"
|
|
: "creature");
|
|
verbalize(
|
|
"To enter the castle, thou must play the right tune!");
|
|
u.uevent.uheard_tune++;
|
|
break;
|
|
} else if (u.uevent.uheard_tune < 2) {
|
|
Soundeffect(se_divine_music, 50);
|
|
You_hear("a divine music...");
|
|
pline("It sounds like: \"%s\".", gt.tune);
|
|
u.uevent.uheard_tune++;
|
|
record_achievement(ACH_TUNE);
|
|
break;
|
|
}
|
|
}
|
|
/*FALLTHRU*/
|
|
case 2:
|
|
if (!Blind)
|
|
You("are surrounded by %s glow.", an(hcolor(NH_GOLDEN)));
|
|
/* if any levels have been lost (and not yet regained),
|
|
treat this effect like blessed full healing */
|
|
if (u.ulevel < u.ulevelmax) {
|
|
u.ulevelmax -= 1; /* see potion.c */
|
|
pluslvl(FALSE);
|
|
} else {
|
|
u.uhpmax += 5;
|
|
if (u.uhpmax > u.uhppeak)
|
|
u.uhppeak = u.uhpmax;
|
|
if (Upolyd)
|
|
u.mhmax += 5;
|
|
}
|
|
u.uhp = u.uhpmax;
|
|
if (Upolyd)
|
|
u.mh = u.mhmax;
|
|
if (ABASE(A_STR) < AMAX(A_STR)) {
|
|
ABASE(A_STR) = AMAX(A_STR);
|
|
gc.context.botl = 1; /* before potential message */
|
|
(void) encumber_msg();
|
|
}
|
|
if (u.uhunger < 900)
|
|
init_uhunger();
|
|
/* luck couldn't have been negative at start of prayer because
|
|
the prayer would have failed, but might have been decremented
|
|
due to a timed event (delayed death of peaceful monster hit
|
|
by hero-created stinking cloud) during the praying interval */
|
|
if (u.uluck < 0)
|
|
u.uluck = 0;
|
|
/* superfluous; if hero was blinded we'd be handling trouble
|
|
rather than issuing a pat-on-head */
|
|
u.ucreamed = 0;
|
|
make_blinded(0L, TRUE);
|
|
gc.context.botl = 1;
|
|
break;
|
|
case 4: {
|
|
register struct obj *otmp;
|
|
int any = 0;
|
|
|
|
if (Blind)
|
|
You_feel("the power of %s.", u_gname());
|
|
else
|
|
You("are surrounded by %s aura.", an(hcolor(NH_LIGHT_BLUE)));
|
|
for (otmp = gi.invent; otmp; otmp = otmp->nobj) {
|
|
if (otmp->cursed
|
|
&& (otmp != uarmh /* [see worst_cursed_item()] */
|
|
|| uarmh->otyp != HELM_OF_OPPOSITE_ALIGNMENT)) {
|
|
if (!Blind) {
|
|
pline("%s %s.", Yobjnam2(otmp, "softly glow"),
|
|
hcolor(NH_AMBER));
|
|
iflags.last_msg = PLNMSG_OBJ_GLOWS;
|
|
otmp->bknown = 1; /* ok to bypass set_bknown() */
|
|
++any;
|
|
}
|
|
uncurse(otmp);
|
|
}
|
|
}
|
|
if (any)
|
|
update_inventory();
|
|
break;
|
|
}
|
|
case 5: {
|
|
static NEARDATA const char msg[] =
|
|
"\"and thus I grant thee the gift of %s!\"";
|
|
|
|
godvoice(u.ualign.type,
|
|
"Thou hast pleased me with thy progress,");
|
|
if (!(HTelepat & INTRINSIC)) {
|
|
HTelepat |= FROMOUTSIDE;
|
|
pline(msg, "Telepathy");
|
|
if (Blind)
|
|
see_monsters();
|
|
} else if (!(HFast & INTRINSIC)) {
|
|
HFast |= FROMOUTSIDE;
|
|
pline(msg, "Speed");
|
|
} else if (!(HStealth & INTRINSIC)) {
|
|
HStealth |= FROMOUTSIDE;
|
|
pline(msg, "Stealth");
|
|
} else {
|
|
if (!(HProtection & INTRINSIC)) {
|
|
HProtection |= FROMOUTSIDE;
|
|
if (!u.ublessed)
|
|
u.ublessed = rn1(3, 2);
|
|
} else
|
|
u.ublessed++;
|
|
pline(msg, "my protection");
|
|
}
|
|
verbalize("Use it wisely in my name!");
|
|
break;
|
|
}
|
|
case 7:
|
|
case 8:
|
|
if (u.ualign.record >= PIOUS && !u.uevent.uhand_of_elbereth) {
|
|
gcrownu();
|
|
break;
|
|
}
|
|
/*FALLTHRU*/
|
|
case 6:
|
|
give_spell();
|
|
break;
|
|
default:
|
|
impossible("Confused deity!");
|
|
break;
|
|
}
|
|
|
|
u.ublesscnt = rnz(350);
|
|
kick_on_butt = u.uevent.udemigod ? 1 : 0;
|
|
if (u.uevent.uhand_of_elbereth)
|
|
kick_on_butt++;
|
|
if (kick_on_butt)
|
|
u.ublesscnt += kick_on_butt * rnz(1000);
|
|
|
|
/* Avoid games that go into infinite loops of copy-pasted commands
|
|
with no human interaction; this is a DoS vector against the
|
|
computer running NetHack. Once the turn counter is over 100000,
|
|
every additional 100 turns increases the prayer timeout by 1,
|
|
thus eventually hunger prayers will fail and some other source
|
|
of nutrition will be required. The increase gets throttled if
|
|
it ever reaches 32K so that configurations using 16-bit ints are
|
|
still viable. */
|
|
if (gm.moves > 100000L) {
|
|
long incr = (gm.moves - 100000L) / 100L,
|
|
largest_ublesscnt_incr = (long) (LARGEST_INT - u.ublesscnt);
|
|
|
|
if (incr > largest_ublesscnt_incr)
|
|
incr = largest_ublesscnt_incr;
|
|
u.ublesscnt += (int) incr;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* either blesses or curses water on the altar,
|
|
* returns true if it found any water here.
|
|
*/
|
|
static boolean
|
|
water_prayer(boolean bless_water)
|
|
{
|
|
register struct obj *otmp;
|
|
register long changed = 0;
|
|
boolean other = FALSE, bc_known = !(Blind || Hallucination);
|
|
|
|
for (otmp = gl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
|
|
/* turn water into (un)holy water */
|
|
if (otmp->otyp == POT_WATER
|
|
&& (bless_water ? !otmp->blessed : !otmp->cursed)) {
|
|
otmp->blessed = bless_water;
|
|
otmp->cursed = !bless_water;
|
|
otmp->bknown = bc_known; /* ok to bypass set_bknown() */
|
|
changed += otmp->quan;
|
|
} else if (otmp->oclass == POTION_CLASS)
|
|
other = TRUE;
|
|
}
|
|
if (!Blind && changed) {
|
|
pline("%s potion%s on the altar glow%s %s for a moment.",
|
|
((other && changed > 1L) ? "Some of the"
|
|
: (other ? "One of the" : "The")),
|
|
((other || changed > 1L) ? "s" : ""), (changed > 1L ? "" : "s"),
|
|
(bless_water ? hcolor(NH_LIGHT_BLUE) : hcolor(NH_BLACK)));
|
|
}
|
|
return (boolean) (changed > 0L);
|
|
}
|
|
|
|
static void
|
|
godvoice(aligntyp g_align, const char *words)
|
|
{
|
|
const char *quot = "";
|
|
|
|
if (words)
|
|
quot = "\"";
|
|
else
|
|
words = "";
|
|
|
|
pline_The("voice of %s %s: %s%s%s", align_gname(g_align),
|
|
godvoices[rn2(SIZE(godvoices))], quot, words, quot);
|
|
}
|
|
|
|
static void
|
|
gods_angry(aligntyp g_align)
|
|
{
|
|
godvoice(g_align, "Thou hast angered me.");
|
|
}
|
|
|
|
/* The g_align god is upset with you. */
|
|
static void
|
|
gods_upset(aligntyp g_align)
|
|
{
|
|
if (g_align == u.ualign.type)
|
|
u.ugangr++;
|
|
else if (u.ugangr)
|
|
u.ugangr--;
|
|
angrygods(g_align);
|
|
}
|
|
|
|
static void
|
|
consume_offering(struct obj *otmp)
|
|
{
|
|
if (Hallucination)
|
|
switch (rn2(3)) {
|
|
case 0:
|
|
Your("sacrifice sprouts wings and a propeller and roars away!");
|
|
break;
|
|
case 1:
|
|
Your("sacrifice puffs up, swelling bigger and bigger, and pops!");
|
|
break;
|
|
case 2:
|
|
Your(
|
|
"sacrifice collapses into a cloud of dancing particles and fades away!");
|
|
break;
|
|
}
|
|
else if (Blind && u.ualign.type == A_LAWFUL)
|
|
Your("sacrifice disappears!");
|
|
else
|
|
Your("sacrifice is consumed in a %s!",
|
|
(u.ualign.type == A_LAWFUL)
|
|
? "flash of light"
|
|
: (u.ualign.type == A_NEUTRAL)
|
|
? "plume of smoke"
|
|
: "burst of flame");
|
|
if (carried(otmp))
|
|
useup(otmp);
|
|
else
|
|
useupf(otmp, 1L);
|
|
exercise(A_WIS, TRUE);
|
|
}
|
|
|
|
/* feedback when attempting to offer the Amulet on a "low altar" (not one of
|
|
the high altars in the temples on the Astral Plane or Moloch's Sanctum) */
|
|
static void
|
|
offer_too_soon(aligntyp altaralign)
|
|
{
|
|
if (altaralign == A_NONE && Inhell) {
|
|
/* offering on an unaligned altar in Gehennom;
|
|
hero has left Moloch's Sanctum (caller handles that)
|
|
so is in the process of getting away with the Amulet;
|
|
for any unaligned altar outside of Gehennom, give the
|
|
"you feel ashamed" feedback for wrong alignment below */
|
|
gods_upset(A_NONE); /* Moloch becomes angry */
|
|
return;
|
|
}
|
|
You_feel("%s.", Hallucination
|
|
? "homesick"
|
|
/* if on track, give a big hint */
|
|
: (altaralign == u.ualign.type)
|
|
? "an urge to return to the surface"
|
|
/* else headed towards celestial disgrace */
|
|
: "ashamed");
|
|
}
|
|
|
|
static void
|
|
desecrate_high_altar(aligntyp altaralign)
|
|
{
|
|
/*
|
|
* REAL BAD NEWS!!! High altars cannot be converted. Even an attempt
|
|
* gets the god who owns it truly pissed off.
|
|
*/
|
|
You_feel("the air around you grow charged...");
|
|
pline("Suddenly, you realize that %s has noticed you...", a_gname());
|
|
godvoice(altaralign,
|
|
"So, mortal! You dare desecrate my High Temple!");
|
|
/* Throw everything we have at the player */
|
|
god_zaps_you(altaralign);
|
|
}
|
|
|
|
/* offering the Amulet on a high altar (checked by caller) ends the game;
|
|
we don't declare this 'NORETURN' because done() can return (if called
|
|
with some reasons other than ASCENDED and ESCAPED) */
|
|
static void
|
|
offer_real_amulet(struct obj *otmp, aligntyp altaralign)
|
|
{
|
|
static NEARDATA const char
|
|
cloud_of_smoke[] = "A cloud of %s smoke surrounds you...";
|
|
|
|
/* The final Test. Did you win? */
|
|
if (uamul == otmp)
|
|
Amulet_off();
|
|
if (carried(otmp))
|
|
useup(otmp); /* well, it's gone now */
|
|
else
|
|
useupf(otmp, 1L);
|
|
|
|
You("offer the Amulet of Yendor to %s...", a_gname());
|
|
|
|
if (altaralign == A_NONE) {
|
|
/* Moloch's high altar at the bottom of Gehennom. */
|
|
if (u.ualign.record > -99)
|
|
u.ualign.record = -99;
|
|
pline("An invisible choir chants, and you are bathed in darkness...");
|
|
/*[apparently shrug/snarl can be sensed without being seen]*/
|
|
pline("%s shrugs and retains dominion over %s,", Moloch, u_gname());
|
|
pline("then mercilessly snuffs out your life.");
|
|
Sprintf(gk.killer.name, "%s indifference", s_suffix(Moloch));
|
|
gk.killer.format = KILLED_BY;
|
|
done(DIED);
|
|
/* life-saved (or declined to die in wizard/explore mode) */
|
|
pline("%s snarls and tries again...", Moloch);
|
|
fry_by_god(A_NONE, TRUE); /* wrath of Moloch */
|
|
/* declined to die in wizard or explore mode */
|
|
pline(cloud_of_smoke, hcolor(NH_BLACK));
|
|
done(ESCAPED);
|
|
/*NOTREACHED*/
|
|
} else if (u.ualign.type != altaralign) {
|
|
/* And the opposing team picks you up and carries you off
|
|
on their shoulders. */
|
|
adjalign(-99);
|
|
pline("%s accepts your gift, and gains dominion over %s...",
|
|
a_gname(), u_gname());
|
|
pline("%s is enraged...", u_gname());
|
|
pline("Fortunately, %s permits you to live...", a_gname());
|
|
pline(cloud_of_smoke, hcolor(NH_ORANGE));
|
|
done(ESCAPED);
|
|
/*NOTREACHED*/
|
|
} else {
|
|
/* You've won the game! Feedback-wise, it's a bit of a let down. */
|
|
u.uevent.ascended = 1;
|
|
adjalign(10);
|
|
pline("An invisible choir sings, and you are bathed in radiance...");
|
|
godvoice(altaralign, "Mortal, thou hast done well!");
|
|
display_nhwindow(WIN_MESSAGE, FALSE);
|
|
verbalize(
|
|
"In return for thy service, I grant thee the gift of Immortality!");
|
|
You("ascend to the status of Demigod%s...",
|
|
flags.female ? "dess" : "");
|
|
done(ASCENDED);
|
|
/*NOTREACHED*/
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
/* possibly convert an altar's alignment or the hero's alignment */
|
|
static void
|
|
offer_different_alignment_altar(
|
|
struct obj *otmp,
|
|
aligntyp altaralign)
|
|
{
|
|
/* Is this a conversion ? */
|
|
/* An unaligned altar in Gehennom will always elicit rejection. */
|
|
if (ugod_is_angry() || (altaralign == A_NONE && Inhell)) {
|
|
if (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL]
|
|
&& altaralign != A_NONE) {
|
|
You("have a strong feeling that %s is angry...", u_gname());
|
|
consume_offering(otmp);
|
|
pline("%s accepts your allegiance.", a_gname());
|
|
|
|
uchangealign(altaralign, 0);
|
|
/* Beware, Conversion is costly */
|
|
change_luck(-3);
|
|
u.ublesscnt += 300;
|
|
} else {
|
|
u.ugangr += 3;
|
|
adjalign(-5);
|
|
pline("%s rejects your sacrifice!", a_gname());
|
|
godvoice(altaralign, "Suffer, infidel!");
|
|
change_luck(-5);
|
|
(void) adjattrib(A_WIS, -2, TRUE);
|
|
if (!Inhell)
|
|
angrygods(u.ualign.type);
|
|
}
|
|
} else {
|
|
consume_offering(otmp);
|
|
You("sense a conflict between %s and %s.", u_gname(), a_gname());
|
|
if (rn2(8 + u.ulevel) > 5) {
|
|
struct monst *pri;
|
|
boolean shrine;
|
|
|
|
You_feel("the power of %s increase.", u_gname());
|
|
exercise(A_WIS, TRUE);
|
|
change_luck(1);
|
|
shrine = on_shrine();
|
|
levl[u.ux][u.uy].altarmask = Align2amask(u.ualign.type);
|
|
if (shrine)
|
|
levl[u.ux][u.uy].altarmask |= AM_SHRINE;
|
|
newsym(u.ux, u.uy); /* in case Invisible to self */
|
|
if (!Blind)
|
|
pline_The("altar glows %s.",
|
|
hcolor((u.ualign.type == A_LAWFUL) ? NH_WHITE
|
|
: u.ualign.type ? NH_BLACK
|
|
: (const char *) "gray"));
|
|
|
|
if (rnl(u.ulevel) > 6 && u.ualign.record > 0
|
|
&& rnd(u.ualign.record) > (3 * ALIGNLIM) / 4)
|
|
summon_minion(altaralign, TRUE);
|
|
/* anger priest; test handles bones files */
|
|
if ((pri = findpriest(temple_occupied(u.urooms)))
|
|
&& !p_coaligned(pri))
|
|
angry_priest();
|
|
} else {
|
|
pline("Unluckily, you feel the power of %s decrease.", u_gname());
|
|
change_luck(-1);
|
|
exercise(A_WIS, FALSE);
|
|
if (rnl(u.ulevel) > 6 && u.ualign.record > 0
|
|
&& rnd(u.ualign.record) > (7 * ALIGNLIM) / 8)
|
|
summon_minion(altaralign, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* the #offer command - sacrifice something to the gods */
|
|
int
|
|
dosacrifice(void)
|
|
{
|
|
register struct obj *otmp;
|
|
int value = 0, pm;
|
|
boolean highaltar;
|
|
aligntyp altaralign = a_align(u.ux, u.uy);
|
|
|
|
if (!on_altar() || u.uswallow) {
|
|
You("are not standing on an altar.");
|
|
return ECMD_OK;
|
|
}
|
|
highaltar = (levl[u.ux][u.uy].altarmask & AM_SANCTUM);
|
|
|
|
otmp = floorfood("sacrifice", 1);
|
|
if (!otmp)
|
|
return ECMD_OK;
|
|
/*
|
|
* Was based on nutritional value and aging behavior (< 50 moves).
|
|
* Sacrificing a food ration got you max luck instantly, making the
|
|
* gods as easy to please as an angry dog!
|
|
*
|
|
* Now only accepts corpses, based on the game's evaluation of their
|
|
* toughness. Human and pet sacrifice, as well as sacrificing unicorns
|
|
* of your alignment, is strongly discouraged.
|
|
*/
|
|
#define MAXVALUE 24 /* Highest corpse value (besides Wiz) */
|
|
|
|
if (otmp->otyp == CORPSE) {
|
|
register struct permonst *ptr = &mons[otmp->corpsenm];
|
|
struct monst *mtmp;
|
|
|
|
/* KMH, conduct */
|
|
if (!u.uconduct.gnostic++)
|
|
livelog_printf(LL_CONDUCT,
|
|
"rejected atheism by offering %s on an altar of %s",
|
|
corpse_xname(otmp, (const char *) 0, CXN_ARTICLE),
|
|
a_gname());
|
|
|
|
/* you're handling this corpse, even if it was killed upon the altar
|
|
*/
|
|
feel_cockatrice(otmp, TRUE);
|
|
if (rider_corpse_revival(otmp, FALSE))
|
|
return ECMD_TIME;
|
|
|
|
if (otmp->corpsenm == PM_ACID_BLOB
|
|
|| (gm.moves <= peek_at_iced_corpse_age(otmp) + 50)) {
|
|
value = mons[otmp->corpsenm].difficulty + 1;
|
|
if (otmp->oeaten)
|
|
value = eaten_stat(value, otmp);
|
|
}
|
|
|
|
/* same race or former pet results apply even if the corpse is
|
|
too old (value==0) */
|
|
if (your_race(ptr)) {
|
|
if (is_demon(gy.youmonst.data)) {
|
|
You("find the idea very satisfying.");
|
|
exercise(A_WIS, TRUE);
|
|
} else if (u.ualign.type != A_CHAOTIC) {
|
|
pline("You'll regret this infamous offense!");
|
|
exercise(A_WIS, FALSE);
|
|
}
|
|
|
|
if (highaltar
|
|
&& (altaralign != A_CHAOTIC || u.ualign.type != A_CHAOTIC)) {
|
|
desecrate_high_altar(altaralign);
|
|
return ECMD_TIME;
|
|
} else if (altaralign != A_CHAOTIC && altaralign != A_NONE) {
|
|
/* curse the lawful/neutral altar */
|
|
pline_The("altar is stained with %s blood.", gu.urace.adj);
|
|
levl[u.ux][u.uy].altarmask = AM_CHAOTIC;
|
|
newsym(u.ux, u.uy); /* in case Invisible to self */
|
|
angry_priest();
|
|
} else {
|
|
struct monst *dmon;
|
|
const char *demonless_msg;
|
|
|
|
/* Human sacrifice on a chaotic or unaligned altar */
|
|
/* is equivalent to demon summoning */
|
|
if (altaralign == A_CHAOTIC && u.ualign.type != A_CHAOTIC) {
|
|
pline(
|
|
"The blood floods the altar, which vanishes in %s cloud!",
|
|
an(hcolor(NH_BLACK)));
|
|
levl[u.ux][u.uy].typ = ROOM;
|
|
levl[u.ux][u.uy].altarmask = 0;
|
|
newsym(u.ux, u.uy);
|
|
angry_priest();
|
|
demonless_msg = "cloud dissipates";
|
|
} else {
|
|
/* either you're chaotic or altar is Moloch's or both */
|
|
pline_The("blood covers the altar!");
|
|
change_luck(altaralign == A_NONE ? -2 : 2);
|
|
demonless_msg = "blood coagulates";
|
|
}
|
|
if ((pm = dlord(altaralign)) != NON_PM
|
|
&& (dmon = makemon(&mons[pm], u.ux, u.uy, MM_NOMSG))
|
|
!= 0) {
|
|
char dbuf[BUFSZ];
|
|
|
|
Strcpy(dbuf, a_monnam(dmon));
|
|
if (!strcmpi(dbuf, "it"))
|
|
Strcpy(dbuf, "something dreadful");
|
|
else
|
|
dmon->mstrategy &= ~STRAT_APPEARMSG;
|
|
You("have summoned %s!", dbuf);
|
|
if (sgn(u.ualign.type) == sgn(dmon->data->maligntyp))
|
|
dmon->mpeaceful = TRUE;
|
|
You("are terrified, and unable to move.");
|
|
nomul(-3);
|
|
gm.multi_reason = "being terrified of a demon";
|
|
gn.nomovemsg = 0;
|
|
} else
|
|
pline_The("%s.", demonless_msg);
|
|
}
|
|
|
|
if (u.ualign.type != A_CHAOTIC) {
|
|
adjalign(-5);
|
|
u.ugangr += 3;
|
|
(void) adjattrib(A_WIS, -1, TRUE);
|
|
if (!Inhell)
|
|
angrygods(u.ualign.type);
|
|
change_luck(-5);
|
|
} else
|
|
adjalign(5);
|
|
if (carried(otmp))
|
|
useup(otmp);
|
|
else
|
|
useupf(otmp, 1L);
|
|
return ECMD_TIME;
|
|
} else if (has_omonst(otmp)
|
|
&& (mtmp = get_mtraits(otmp, FALSE)) != 0
|
|
&& mtmp->mtame) {
|
|
/* mtmp is a temporary pointer to a tame monster's attributes,
|
|
* not a real monster */
|
|
pline("So this is how you repay loyalty?");
|
|
adjalign(-3);
|
|
value = -1;
|
|
HAggravate_monster |= FROMOUTSIDE;
|
|
} else if (!value) {
|
|
; /* too old; don't give undead or unicorn bonus or penalty */
|
|
} else if (is_undead(ptr)) { /* Not demons--no demon corpses */
|
|
/* most undead that leave a corpse yield 'human' (or other race)
|
|
corpse so won't get here; the exception is wraith; give the
|
|
bonus for wraith to chaotics too because they are sacrificing
|
|
something valuable (unless hero refuses to eat such things) */
|
|
if (u.ualign.type != A_CHAOTIC
|
|
/* reaching this side of the 'or' means hero is chaotic */
|
|
|| (ptr == &mons[PM_WRAITH] && u.uconduct.unvegetarian))
|
|
value += 1;
|
|
} else if (is_unicorn(ptr)) {
|
|
int unicalign = sgn(ptr->maligntyp);
|
|
|
|
if (unicalign == altaralign) {
|
|
/* When same as altar, always a very bad action.
|
|
*/
|
|
pline("Such an action is an insult to %s!",
|
|
(unicalign == A_CHAOTIC) ? "chaos"
|
|
: unicalign ? "law" : "balance");
|
|
(void) adjattrib(A_WIS, -1, TRUE);
|
|
value = -5;
|
|
} else if (u.ualign.type == altaralign) {
|
|
/* When different from altar, and altar is same as yours,
|
|
* it's a very good action.
|
|
*/
|
|
if (u.ualign.record < ALIGNLIM)
|
|
You_feel("appropriately %s.", align_str(u.ualign.type));
|
|
else
|
|
You_feel("you are thoroughly on the right path.");
|
|
adjalign(5);
|
|
value += 3;
|
|
} else if (unicalign == u.ualign.type) {
|
|
/* When sacrificing unicorn of your alignment to altar not of
|
|
* your alignment, your god gets angry and it's a conversion.
|
|
*/
|
|
u.ualign.record = -1;
|
|
value = 1;
|
|
} else {
|
|
/* Otherwise, unicorn's alignment is different from yours
|
|
* and different from the altar's. It's an ordinary (well,
|
|
* with a bonus) sacrifice on a cross-aligned altar.
|
|
*/
|
|
value += 3;
|
|
}
|
|
}
|
|
} /* corpse */
|
|
|
|
if (otmp->otyp == AMULET_OF_YENDOR) {
|
|
if (!highaltar) {
|
|
offer_too_soon(altaralign);
|
|
return ECMD_TIME;
|
|
} else {
|
|
offer_real_amulet(otmp, altaralign);
|
|
/*NOTREACHED*/
|
|
}
|
|
} /* real Amulet */
|
|
|
|
if (otmp->otyp == FAKE_AMULET_OF_YENDOR) {
|
|
if (!highaltar && !otmp->known) {
|
|
offer_too_soon(altaralign);
|
|
return ECMD_TIME;
|
|
}
|
|
Soundeffect(se_thunderclap, 100);
|
|
You_hear("a nearby thunderclap.");
|
|
if (!otmp->known) {
|
|
You("realize you have made a %s.",
|
|
Hallucination ? "boo-boo" : "mistake");
|
|
otmp->known = TRUE;
|
|
change_luck(-1);
|
|
return ECMD_TIME;
|
|
} else {
|
|
/* don't you dare try to fool the gods */
|
|
if (Deaf)
|
|
pline("Oh, no."); /* didn't hear thunderclap */
|
|
change_luck(-3);
|
|
adjalign(-1);
|
|
u.ugangr += 3;
|
|
value = -3;
|
|
}
|
|
} /* fake Amulet */
|
|
|
|
if (value == 0) {
|
|
pline1(nothing_happens);
|
|
return ECMD_TIME;
|
|
}
|
|
|
|
if (altaralign != u.ualign.type && highaltar) {
|
|
desecrate_high_altar(altaralign);
|
|
} else if (value < 0) { /* don't think the gods are gonna like this... */
|
|
gods_upset(altaralign);
|
|
} else if (u.ualign.type != altaralign) {
|
|
/* Sacrificing at an altar of a different alignment */
|
|
offer_different_alignment_altar(otmp, altaralign);
|
|
return ECMD_TIME;
|
|
} else {
|
|
int saved_anger = u.ugangr;
|
|
int saved_cnt = u.ublesscnt;
|
|
int saved_luck = u.uluck;
|
|
|
|
consume_offering(otmp);
|
|
/* OK, you get brownie points. */
|
|
if (u.ugangr) {
|
|
u.ugangr -= ((value * (u.ualign.type == A_CHAOTIC ? 2 : 3))
|
|
/ MAXVALUE);
|
|
if (u.ugangr < 0)
|
|
u.ugangr = 0;
|
|
if (u.ugangr != saved_anger) {
|
|
if (u.ugangr) {
|
|
pline("%s seems %s.", u_gname(),
|
|
Hallucination ? "groovy" : "slightly mollified");
|
|
|
|
if ((int) u.uluck < 0)
|
|
change_luck(1);
|
|
} else {
|
|
pline("%s seems %s.", u_gname(),
|
|
Hallucination ? "cosmic (not a new fact)"
|
|
: "mollified");
|
|
|
|
if ((int) u.uluck < 0)
|
|
u.uluck = 0;
|
|
}
|
|
} else { /* not satisfied yet */
|
|
if (Hallucination)
|
|
pline_The("gods seem tall.");
|
|
else
|
|
You("have a feeling of inadequacy.");
|
|
}
|
|
} else if (ugod_is_angry()) {
|
|
if (value > MAXVALUE)
|
|
value = MAXVALUE;
|
|
if (value > -u.ualign.record)
|
|
value = -u.ualign.record;
|
|
adjalign(value);
|
|
You_feel("partially absolved.");
|
|
} else if (u.ublesscnt > 0) {
|
|
u.ublesscnt -= ((value * (u.ualign.type == A_CHAOTIC ? 500 : 300))
|
|
/ MAXVALUE);
|
|
if (u.ublesscnt < 0)
|
|
u.ublesscnt = 0;
|
|
if (u.ublesscnt != saved_cnt) {
|
|
if (u.ublesscnt) {
|
|
if (Hallucination)
|
|
You("realize that the gods are not like you and I.");
|
|
else
|
|
You("have a hopeful feeling.");
|
|
if ((int) u.uluck < 0)
|
|
change_luck(1);
|
|
} else {
|
|
if (Hallucination)
|
|
pline("Overall, there is a smell of fried onions.");
|
|
else
|
|
You("have a feeling of reconciliation.");
|
|
if ((int) u.uluck < 0)
|
|
u.uluck = 0;
|
|
}
|
|
}
|
|
} else {
|
|
int nartifacts = nartifact_exist();
|
|
|
|
/* you were already in pretty good standing */
|
|
/* The player can gain an artifact */
|
|
/* The chance goes down as the number of artifacts goes up */
|
|
if (u.ulevel > 2 && u.uluck >= 0
|
|
&& !rn2(10 + (2 * u.ugifts * nartifacts))) {
|
|
otmp = mk_artifact((struct obj *) 0, a_align(u.ux, u.uy));
|
|
if (otmp) {
|
|
char buf[BUFSZ];
|
|
|
|
artifact_origin(otmp, ONAME_GIFT | ONAME_KNOW_ARTI);
|
|
if (otmp->spe < 0)
|
|
otmp->spe = 0;
|
|
if (otmp->cursed)
|
|
uncurse(otmp);
|
|
otmp->oerodeproof = TRUE;
|
|
Strcpy(buf, (Hallucination ? "a doodad"
|
|
: Blind ? "an object"
|
|
: ansimpleoname(otmp)));
|
|
if (!Blind)
|
|
Sprintf(eos(buf), " named %s",
|
|
bare_artifactname(otmp));
|
|
at_your_feet(upstart(buf));
|
|
dropy(otmp);
|
|
godvoice(u.ualign.type, "Use my gift wisely!");
|
|
u.ugifts++;
|
|
u.ublesscnt = rnz(300 + (50 * nartifacts));
|
|
exercise(A_WIS, TRUE);
|
|
livelog_printf (LL_DIVINEGIFT | LL_ARTIFACT,
|
|
"was bestowed with %s by %s",
|
|
artiname(otmp->oartifact),
|
|
align_gname(u.ualign.type));
|
|
/* make sure we can use this weapon */
|
|
unrestrict_weapon_skill(weapon_type(otmp));
|
|
if (!Hallucination && !Blind) {
|
|
otmp->dknown = 1;
|
|
makeknown(otmp->otyp);
|
|
discover_artifact(otmp->oartifact);
|
|
}
|
|
return ECMD_TIME;
|
|
}
|
|
}
|
|
change_luck((value * LUCKMAX) / (MAXVALUE * 2));
|
|
if ((int) u.uluck < 0)
|
|
u.uluck = 0;
|
|
if (u.uluck != saved_luck) {
|
|
if (Blind)
|
|
You("think %s brushed your %s.", something,
|
|
body_part(FOOT));
|
|
else
|
|
You(Hallucination
|
|
? "see crabgrass at your %s. A funny thing in a dungeon."
|
|
: "glimpse a four-leaf clover at your %s.",
|
|
makeplural(body_part(FOOT)));
|
|
}
|
|
}
|
|
}
|
|
return ECMD_TIME;
|
|
}
|
|
|
|
/* determine prayer results in advance; also used for enlightenment */
|
|
boolean
|
|
can_pray(boolean praying) /* false means no messages should be given */
|
|
{
|
|
int alignment;
|
|
|
|
gp.p_aligntyp = on_altar() ? a_align(u.ux, u.uy) : u.ualign.type;
|
|
gp.p_trouble = in_trouble();
|
|
|
|
if (is_demon(gy.youmonst.data) /* ok if chaotic or none (Moloch) */
|
|
&& (gp.p_aligntyp == A_LAWFUL || gp.p_aligntyp != A_NEUTRAL)) {
|
|
if (praying)
|
|
pline_The("very idea of praying to a %s god is repugnant to you.",
|
|
gp.p_aligntyp ? "lawful" : "neutral");
|
|
return FALSE;
|
|
}
|
|
|
|
if (praying)
|
|
You("begin praying to %s.", align_gname(gp.p_aligntyp));
|
|
|
|
if (u.ualign.type && u.ualign.type == -gp.p_aligntyp)
|
|
alignment = -u.ualign.record; /* Opposite alignment altar */
|
|
else if (u.ualign.type != gp.p_aligntyp)
|
|
alignment = u.ualign.record / 2; /* Different alignment altar */
|
|
else
|
|
alignment = u.ualign.record;
|
|
|
|
if (gp.p_aligntyp == A_NONE) /* praying to Moloch */
|
|
gp.p_type = -2;
|
|
else if ((gp.p_trouble > 0) ? (u.ublesscnt > 200) /* big trouble */
|
|
: (gp.p_trouble < 0) ? (u.ublesscnt > 100) /* minor difficulties */
|
|
: (u.ublesscnt > 0)) /* not in trouble */
|
|
gp.p_type = 0; /* too soon... */
|
|
else if ((int) Luck < 0 || u.ugangr || alignment < 0)
|
|
gp.p_type = 1; /* too naughty... */
|
|
else /* alignment >= 0 */ {
|
|
if (on_altar() && u.ualign.type != gp.p_aligntyp)
|
|
gp.p_type = 2;
|
|
else
|
|
gp.p_type = 3;
|
|
}
|
|
|
|
if (is_undead(gy.youmonst.data) && !Inhell
|
|
&& (gp.p_aligntyp == A_LAWFUL
|
|
|| (gp.p_aligntyp == A_NEUTRAL && !rn2(10))))
|
|
gp.p_type = -1;
|
|
/* Note: when !praying, the random factor for neutrals makes the
|
|
return value a non-deterministic approximation for enlightenment.
|
|
This case should be uncommon enough to live with... */
|
|
|
|
return !praying ? (boolean) (gp.p_type == 3 && !Inhell) : TRUE;
|
|
}
|
|
|
|
/* return TRUE if praying revived a pet corpse */
|
|
static boolean
|
|
pray_revive(void)
|
|
{
|
|
struct obj *otmp;
|
|
|
|
for (otmp = gl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere)
|
|
if (otmp->otyp == CORPSE && has_omonst(otmp)
|
|
&& OMONST(otmp)->mtame && !OMONST(otmp)->isminion)
|
|
break;
|
|
|
|
if (!otmp)
|
|
return FALSE;
|
|
|
|
return (revive(otmp, TRUE) != NULL);
|
|
}
|
|
|
|
/* #pray commmand */
|
|
int
|
|
dopray(void)
|
|
{
|
|
/*
|
|
* If ParanoidPray is set, confirm prayer to avoid accidental slips
|
|
* of Alt+p.
|
|
* YN(): don't save response in do-again buffer since if it is 'y',
|
|
* ^A would bypass confirmation, or if 'n', ^A would be pointless.
|
|
*/
|
|
if (ParanoidPray && YN("Are you sure you want to pray?") != 'y')
|
|
return ECMD_OK;
|
|
|
|
if (!u.uconduct.gnostic++)
|
|
/* breaking conduct should probably occur in can_pray() at
|
|
* "You begin praying to %s", as demons who find praying repugnant
|
|
* should not break conduct. Also we can add more detail to the
|
|
* livelog message as p_aligntyp will be known.
|
|
*/
|
|
livelog_printf(LL_CONDUCT, "rejected atheism with a prayer");
|
|
|
|
/* set up p_type and p_alignment */
|
|
if (!can_pray(TRUE))
|
|
return ECMD_OK;
|
|
|
|
if (wizard && gp.p_type >= 0) {
|
|
static const char forcesuccess[] = "Force the gods to be pleased?";
|
|
|
|
/* if we asked "are you sure?" above we suppressed the response
|
|
from the do-again buffer, so need to suppress this response too;
|
|
otherwise subsequent ^A would use this answer for "are you sure?"
|
|
and bypass confirmation */
|
|
if ((ParanoidPray ? YN(forcesuccess) : y_n(forcesuccess)) == 'y') {
|
|
u.ublesscnt = 0;
|
|
if (u.uluck < 0)
|
|
u.uluck = 0;
|
|
if (u.ualign.record <= 0)
|
|
u.ualign.record = 1;
|
|
u.ugangr = 0;
|
|
if (gp.p_type < 2)
|
|
gp.p_type = 3;
|
|
}
|
|
}
|
|
nomul(-3);
|
|
gm.multi_reason = "praying";
|
|
gn.nomovemsg = "You finish your prayer.";
|
|
ga.afternmv = prayer_done;
|
|
|
|
if (gp.p_type == 3 && !Inhell) {
|
|
/* if you've been true to your god you can't die while you pray */
|
|
if (!Blind)
|
|
You("are surrounded by a shimmering light.");
|
|
u.uinvulnerable = TRUE;
|
|
}
|
|
|
|
return ECMD_TIME;
|
|
}
|
|
|
|
static int
|
|
prayer_done(void) /* M. Stephenson (1.0.3b) */
|
|
{
|
|
aligntyp alignment = gp.p_aligntyp;
|
|
|
|
u.uinvulnerable = FALSE;
|
|
if (gp.p_type == -2) {
|
|
/* praying at an unaligned altar, not necessarily in Gehennom */
|
|
You("%s diabolical laughter all around you...",
|
|
!Deaf ? "hear" : "intuit");
|
|
wake_nearby();
|
|
adjalign(-2);
|
|
exercise(A_WIS, FALSE);
|
|
if (!Inhell) {
|
|
/* hero's god[dess] seems to be keeping his/her head down */
|
|
pline("Nothing else happens."); /* not actually true... */
|
|
return 1;
|
|
} /* else use regular Inhell result below */
|
|
} else if (gp.p_type == -1) {
|
|
/* praying while poly'd into an undead creature while non-chaotic */
|
|
godvoice(alignment,
|
|
(alignment == A_LAWFUL)
|
|
? "Vile creature, thou durst call upon me?"
|
|
: "Walk no more, perversion of nature!");
|
|
You_feel("like you are falling apart.");
|
|
/* KMH -- Gods have mastery over unchanging */
|
|
rehumanize();
|
|
/* no Half_physical_damage adjustment here */
|
|
losehp(rnd(20), "residual undead turning effect", KILLED_BY_AN);
|
|
exercise(A_CON, FALSE);
|
|
return 1;
|
|
}
|
|
if (Inhell) {
|
|
pline("Since you are in Gehennom, %s can't help you.",
|
|
align_gname(alignment));
|
|
/* haltingly aligned is least likely to anger */
|
|
if (u.ualign.record <= 0 || rnl(u.ualign.record))
|
|
angrygods(u.ualign.type);
|
|
return 0;
|
|
}
|
|
|
|
if (gp.p_type == 0) {
|
|
if (on_altar() && u.ualign.type != alignment)
|
|
(void) water_prayer(FALSE);
|
|
u.ublesscnt += rnz(250);
|
|
change_luck(-3);
|
|
gods_upset(u.ualign.type);
|
|
} else if (gp.p_type == 1) {
|
|
if (on_altar() && u.ualign.type != alignment)
|
|
(void) water_prayer(FALSE);
|
|
angrygods(u.ualign.type); /* naughty */
|
|
} else if (gp.p_type == 2) {
|
|
if (water_prayer(FALSE)) {
|
|
/* attempted water prayer on a non-coaligned altar */
|
|
u.ublesscnt += rnz(250);
|
|
change_luck(-3);
|
|
gods_upset(u.ualign.type);
|
|
} else
|
|
pleased(alignment);
|
|
} else {
|
|
/* coaligned */
|
|
if (on_altar()) {
|
|
(void) pray_revive();
|
|
(void) water_prayer(TRUE);
|
|
}
|
|
pleased(alignment); /* nice */
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* #turn command */
|
|
int
|
|
doturn(void)
|
|
{
|
|
/* Knights & Priest(esse)s only please */
|
|
struct monst *mtmp, *mtmp2;
|
|
const char *Gname;
|
|
int once, range, xlev;
|
|
|
|
if (!Role_if(PM_CLERIC) && !Role_if(PM_KNIGHT)) {
|
|
/* Try to use the "turn undead" spell. */
|
|
if (known_spell(SPE_TURN_UNDEAD))
|
|
return spelleffects(SPE_TURN_UNDEAD, FALSE, FALSE);
|
|
You("don't know how to turn undead!");
|
|
return ECMD_OK;
|
|
}
|
|
if (!u.uconduct.gnostic++)
|
|
livelog_printf(LL_CONDUCT, "rejected atheism by turning undead");
|
|
|
|
Gname = halu_gname(u.ualign.type);
|
|
|
|
/* [What about needing free hands (does #turn involve any gesturing)?] */
|
|
if (!can_chant(&gy.youmonst)) {
|
|
/* "evilness": "demons and undead" is too verbose and too precise */
|
|
You("are %s upon %s to turn aside evilness.",
|
|
Strangled ? "not able to call" : "incapable of calling", Gname);
|
|
/* violates agnosticism due to intent; conduct tracking is not
|
|
supposed to affect play but we make an exception here: use a
|
|
move if this is the first time agnostic conduct has been broken */
|
|
return (u.uconduct.gnostic == 1) ? ECMD_TIME : ECMD_OK;
|
|
}
|
|
if ((u.ualign.type != A_CHAOTIC
|
|
&& (is_demon(gy.youmonst.data)
|
|
|| is_undead(gy.youmonst.data) || is_vampshifter(&gy.youmonst)))
|
|
|| u.ugangr > 6) { /* "Die, mortal!" */
|
|
pline("For some reason, %s seems to ignore you.", Gname);
|
|
aggravate();
|
|
exercise(A_WIS, FALSE);
|
|
return ECMD_TIME;
|
|
}
|
|
if (Inhell) {
|
|
pline("Since you are in Gehennom, %s %s help you.",
|
|
/* not actually calling upon Moloch but use alternate
|
|
phrasing anyway if hallucinatory feedback says it's him */
|
|
Gname, !strcmp(Gname, Moloch) ? "won't" : "can't");
|
|
aggravate();
|
|
return ECMD_TIME;
|
|
}
|
|
pline("Calling upon %s, you chant an arcane formula.", Gname);
|
|
exercise(A_WIS, TRUE);
|
|
|
|
/* note: does not perform unturn_dead() on victims' inventories */
|
|
range = BOLT_LIM + (u.ulevel / 5); /* 8 to 14 */
|
|
range *= range;
|
|
once = 0;
|
|
for (mtmp = fmon; mtmp; mtmp = mtmp2) {
|
|
mtmp2 = mtmp->nmon;
|
|
if (DEADMONSTER(mtmp))
|
|
continue;
|
|
/* 3.6.3: used to use cansee() here but the purpose is to prevent
|
|
#turn operating through walls, not to require that the hero be
|
|
able to see the target location */
|
|
if (!couldsee(mtmp->mx, mtmp->my)
|
|
|| mdistu(mtmp) > range)
|
|
continue;
|
|
|
|
if (!mtmp->mpeaceful
|
|
&& (is_undead(mtmp->data) || is_vampshifter(mtmp)
|
|
|| (is_demon(mtmp->data) && (u.ulevel > (MAXULEV / 2))))) {
|
|
mtmp->msleeping = 0;
|
|
if (Confusion) {
|
|
if (!once++)
|
|
pline("Unfortunately, your voice falters.");
|
|
mtmp->mflee = 0;
|
|
mtmp->mfrozen = 0;
|
|
mtmp->mcanmove = 1;
|
|
} else if (!resist(mtmp, '\0', 0, TELL)) {
|
|
xlev = 6;
|
|
switch (mtmp->data->mlet) {
|
|
/* this is intentional, lichs are tougher
|
|
than zombies. */
|
|
case S_LICH:
|
|
xlev += 2;
|
|
/*FALLTHRU*/
|
|
case S_GHOST:
|
|
xlev += 2;
|
|
/*FALLTHRU*/
|
|
case S_VAMPIRE:
|
|
xlev += 2;
|
|
/*FALLTHRU*/
|
|
case S_WRAITH:
|
|
xlev += 2;
|
|
/*FALLTHRU*/
|
|
case S_MUMMY:
|
|
xlev += 2;
|
|
/*FALLTHRU*/
|
|
case S_ZOMBIE:
|
|
if (u.ulevel >= xlev && !resist(mtmp, '\0', 0, NOTELL)) {
|
|
if (u.ualign.type == A_CHAOTIC) {
|
|
mtmp->mpeaceful = 1;
|
|
set_malign(mtmp);
|
|
} else { /* damn them */
|
|
killed(mtmp);
|
|
}
|
|
break;
|
|
} /* else flee */
|
|
/*FALLTHRU*/
|
|
default:
|
|
monflee(mtmp, 0, FALSE, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* There is no detrimental effect on self for successful #turn
|
|
* while in demon or undead form. That can only be done while
|
|
* chaotic oneself (see "For some reason" above) and chaotic
|
|
* turning only makes targets peaceful.
|
|
*
|
|
* Paralysis duration probably ought to be based on the strengh
|
|
* of turned creatures rather than on turner's level.
|
|
* Why doesn't this honor Free_action? [Because being able to
|
|
* repeat #turn every turn would be too powerful. Maybe instead
|
|
* of nomul(-N) we should add the equivalent of mon->mspec_used
|
|
* for the hero and refuse to #turn when it's non-zero? Or have
|
|
* both and u.uspec_used only matters when Free_action prevents
|
|
* the brief paralysis?]
|
|
*/
|
|
nomul(-(5 - ((u.ulevel - 1) / 6))); /* -5 .. -1 */
|
|
gm.multi_reason = "trying to turn the monsters";
|
|
gn.nomovemsg = You_can_move_again;
|
|
return ECMD_TIME;
|
|
}
|
|
|
|
int
|
|
altarmask_at(coordxy x, coordxy y)
|
|
{
|
|
int res = 0;
|
|
|
|
if (isok(x, y)) {
|
|
struct monst *mon = m_at(x, y);
|
|
|
|
if (mon && M_AP_TYPE(mon) == M_AP_FURNITURE
|
|
&& mon->mappearance == S_altar)
|
|
res = has_mcorpsenm(mon) ? MCORPSENM(mon) : 0;
|
|
else if (IS_ALTAR(levl[x][y].typ))
|
|
res = levl[x][y].altarmask;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
const char *
|
|
a_gname(void)
|
|
{
|
|
return a_gname_at(u.ux, u.uy);
|
|
}
|
|
|
|
/* returns the name of an altar's deity */
|
|
const char *
|
|
a_gname_at(coordxy x, coordxy y)
|
|
{
|
|
if (!IS_ALTAR(levl[x][y].typ))
|
|
return (char *) 0;
|
|
|
|
return align_gname(a_align(x, y));
|
|
}
|
|
|
|
/* returns the name of the hero's deity */
|
|
const char *
|
|
u_gname(void)
|
|
{
|
|
return align_gname(u.ualign.type);
|
|
}
|
|
|
|
const char *
|
|
align_gname(aligntyp alignment)
|
|
{
|
|
const char *gnam;
|
|
|
|
switch (alignment) {
|
|
case A_NONE:
|
|
gnam = Moloch;
|
|
break;
|
|
case A_LAWFUL:
|
|
gnam = gu.urole.lgod;
|
|
break;
|
|
case A_NEUTRAL:
|
|
gnam = gu.urole.ngod;
|
|
break;
|
|
case A_CHAOTIC:
|
|
gnam = gu.urole.cgod;
|
|
break;
|
|
default:
|
|
impossible("unknown alignment.");
|
|
gnam = "someone";
|
|
break;
|
|
}
|
|
if (*gnam == '_')
|
|
++gnam;
|
|
return gnam;
|
|
}
|
|
|
|
static const char *const hallu_gods[] = {
|
|
"the Flying Spaghetti Monster", /* Church of the FSM */
|
|
"Eris", /* Discordianism */
|
|
"the Martians", /* every science fiction ever */
|
|
"Xom", /* Crawl */
|
|
"AnDoR dRaKoN", /* ADOM */
|
|
"the Central Bank of Yendor", /* economics */
|
|
"Tooth Fairy", /* real world(?) */
|
|
"Om", /* Discworld */
|
|
"Yawgmoth", /* Magic: the Gathering */
|
|
"Morgoth", /* LoTR */
|
|
"Cthulhu", /* Lovecraft */
|
|
"the Ori", /* Stargate */
|
|
"destiny", /* why not? */
|
|
"your Friend the Computer", /* Paranoia */
|
|
};
|
|
|
|
/* hallucination handling for priest/minion names: select a random god
|
|
iff character is hallucinating */
|
|
const char *
|
|
halu_gname(aligntyp alignment)
|
|
{
|
|
const char *gnam = NULL;
|
|
int which;
|
|
|
|
if (!Hallucination)
|
|
return align_gname(alignment);
|
|
|
|
/* Some roles (Priest) don't have a pantheon unless we're playing as
|
|
that role, so keep trying until we get a role which does have one.
|
|
[If playing a Priest, the current pantheon will be twice as likely
|
|
to get picked as any of the others. That's not significant enough
|
|
to bother dealing with.] */
|
|
do
|
|
which = randrole(TRUE);
|
|
while (!roles[which].lgod);
|
|
|
|
switch (rn2_on_display_rng(9)) {
|
|
case 0:
|
|
case 1:
|
|
gnam = roles[which].lgod;
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
gnam = roles[which].ngod;
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
gnam = roles[which].cgod;
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
gnam = hallu_gods[rn2_on_display_rng(SIZE(hallu_gods))];
|
|
break;
|
|
case 8:
|
|
gnam = Moloch;
|
|
break;
|
|
default:
|
|
impossible("rn2 broken in halu_gname?!?");
|
|
}
|
|
if (!gnam) {
|
|
impossible("No random god name?");
|
|
gnam = "your Friend the Computer"; /* Paranoia */
|
|
}
|
|
if (*gnam == '_')
|
|
++gnam;
|
|
return gnam;
|
|
}
|
|
|
|
/* deity's title */
|
|
const char *
|
|
align_gtitle(aligntyp alignment)
|
|
{
|
|
const char *gnam, *result = "god";
|
|
|
|
switch (alignment) {
|
|
case A_LAWFUL:
|
|
gnam = gu.urole.lgod;
|
|
break;
|
|
case A_NEUTRAL:
|
|
gnam = gu.urole.ngod;
|
|
break;
|
|
case A_CHAOTIC:
|
|
gnam = gu.urole.cgod;
|
|
break;
|
|
default:
|
|
gnam = 0;
|
|
break;
|
|
}
|
|
if (gnam && *gnam == '_')
|
|
result = "goddess";
|
|
return result;
|
|
}
|
|
|
|
void
|
|
altar_wrath(coordxy x, coordxy y)
|
|
{
|
|
aligntyp altaralign = a_align(x, y);
|
|
|
|
if (u.ualign.type == altaralign && u.ualign.record > -rn2(4)) {
|
|
godvoice(altaralign, "How darest thou desecrate my altar!");
|
|
(void) adjattrib(A_WIS, -1, FALSE);
|
|
u.ualign.record--;
|
|
} else {
|
|
pline("%s %s%s:",
|
|
!Deaf ? "A voice (could it be"
|
|
: "Despite your deafness, you seem to hear",
|
|
align_gname(altaralign),
|
|
!Deaf ? "?) whispers" : " say");
|
|
verbalize("Thou shalt pay, infidel!");
|
|
/* higher luck is more likely to be reduced; as it approaches -5
|
|
the chance to lose another point drops down, eventually to 0 */
|
|
if (Luck > -5 && rn2(Luck + 6))
|
|
change_luck(rn2(20) ? -1 : -2);
|
|
}
|
|
}
|
|
|
|
/* assumes isok() at one space away, but not necessarily at two */
|
|
static boolean
|
|
blocked_boulder(int dx, int dy)
|
|
{
|
|
register struct obj *otmp;
|
|
int nx, ny;
|
|
long count = 0L;
|
|
|
|
for (otmp = gl.level.objects[u.ux + dx][u.uy + dy]; otmp;
|
|
otmp = otmp->nexthere) {
|
|
if (otmp->otyp == BOULDER)
|
|
count += otmp->quan;
|
|
}
|
|
|
|
nx = u.ux + 2 * dx, ny = u.uy + 2 * dy; /* next spot beyond boulder(s) */
|
|
switch (count) {
|
|
case 0:
|
|
/* no boulders--not blocked */
|
|
return FALSE;
|
|
case 1:
|
|
/* possibly blocked depending on if it's pushable */
|
|
break;
|
|
case 2:
|
|
/* this is only approximate since multiple boulders might sink */
|
|
if (is_pool_or_lava(nx, ny)) /* does its own isok() check */
|
|
break; /* still need Sokoban check below */
|
|
/*FALLTHRU*/
|
|
default:
|
|
/* more than one boulder--blocked after they push the top one;
|
|
don't force them to push it first to find out */
|
|
return TRUE;
|
|
}
|
|
|
|
if (dx && dy && Sokoban) /* can't push boulder diagonally in Sokoban */
|
|
return TRUE;
|
|
if (!isok(nx, ny))
|
|
return TRUE;
|
|
if (IS_ROCK(levl[nx][ny].typ))
|
|
return TRUE;
|
|
if (sobj_at(BOULDER, nx, ny))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*pray.c*/
|