Files
nethack/src/priest.c
nethack.rankin 337e158009 #overview enhancements (trunk only)
1) add graves to the dungeon features being tracked;
2) report on known bones (determined by seeing map spot(s) where previous
   hero(es) died since there's no guarantee of graves or ghosts);
3) add automatic annotations for oracle, sokoban, bigroom, rogue level,
   Ft.Ludios, castle, valley, and Moloch's sanctum.  For bigroom and rogue
   level you just need to visit that level, for the others you need to get
   far enough along to learn something specific (oracle: her room, sokoban:
   annotation is either "solved" or "unsolved" depending upon whether all
   the holes and pits have been filled, fort and castle: see the drawbridge,
   valley and sanctum: see inside the tended temple).  Discovering the
   relevant locations via magic mapping counts as "far enough along".

     There should probably also be automatic annotations for Medusa and the
vibrating square but I'm not sure what criteria should be used for the
former or what phrasing to use for the latter.  Demon lord/prince lairs fall
into similar category as Medusa.

     TODO: add final #overview as an end of game disclosure option.  (I was
planning this even before I saw that nitrohack has implemented it....)
2012-02-16 02:40:24 +00:00

829 lines
23 KiB
C

/* NetHack 3.5 priest.c $Date$ $Revision$ */
/* Copyright (c) Izchak Miller, Steve Linhart, 1989. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "mfndpos.h"
/* these match the categorizations shown by enlightenment */
#define ALGN_SINNED (-4) /* worse than strayed (-1..-3) */
#define ALGN_PIOUS 14 /* better than fervent (9..13) */
STATIC_DCL boolean FDECL(histemple_at,(struct monst *,XCHAR_P,XCHAR_P));
STATIC_DCL boolean FDECL(has_shrine,(struct monst *));
void
newepri(mtmp)
struct monst *mtmp;
{
if (!mtmp->mextra) mtmp->mextra = newmextra();
if (!EPRI(mtmp)) {
EPRI(mtmp) = (struct epri *)alloc(sizeof(struct epri));
(void) memset((genericptr_t) EPRI(mtmp), 0, sizeof(struct epri));
}
}
void
free_epri(mtmp)
struct monst *mtmp;
{
if (mtmp->mextra && EPRI(mtmp)) {
free((genericptr_t) EPRI(mtmp));
EPRI(mtmp) = (struct epri *)0;
}
mtmp->ispriest = 0;
}
/*
* Move for priests and shopkeepers. Called from shk_move() and pri_move().
* Valid returns are 1: moved 0: didn't -1: let m_move do it -2: died.
*/
int
move_special(mtmp,in_his_shop,appr,uondoor,avoid,omx,omy,gx,gy)
register struct monst *mtmp;
boolean in_his_shop;
schar appr;
boolean uondoor,avoid;
register xchar omx,omy,gx,gy;
{
register xchar nx,ny,nix,niy;
register schar i;
schar chcnt,cnt;
coord poss[9];
long info[9];
long allowflags;
struct obj *ib = (struct obj *)0;
if(omx == gx && omy == gy)
return(0);
if(mtmp->mconf) {
avoid = FALSE;
appr = 0;
}
nix = omx;
niy = omy;
if (mtmp->isshk) allowflags = ALLOW_SSM;
else allowflags = ALLOW_SSM | ALLOW_SANCT;
if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL);
if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG;
if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
allowflags |= OPENDOOR;
if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
}
if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
cnt = mfndpos(mtmp, poss, info, allowflags);
if(mtmp->isshk && avoid && uondoor) { /* perhaps we cannot avoid him */
for(i=0; i<cnt; i++)
if(!(info[i] & NOTONL)) goto pick_move;
avoid = FALSE;
}
#define GDIST(x,y) (dist2(x,y,gx,gy))
pick_move:
chcnt = 0;
for(i=0; i<cnt; i++) {
nx = poss[i].x;
ny = poss[i].y;
if (IS_ROOM(levl[nx][ny].typ) ||
(mtmp->isshk &&
(!in_his_shop || ESHK(mtmp)->following))) {
if(avoid && (info[i] & NOTONL))
continue;
if((!appr && !rn2(++chcnt)) ||
(appr && GDIST(nx,ny) < GDIST(nix,niy))) {
nix = nx;
niy = ny;
}
}
}
if(mtmp->ispriest && avoid &&
nix == omx && niy == omy && onlineu(omx,omy)) {
/* might as well move closer as long it's going to stay
* lined up */
avoid = FALSE;
goto pick_move;
}
if(nix != omx || niy != omy) {
remove_monster(omx, omy);
place_monster(mtmp, nix, niy);
newsym(nix,niy);
if (mtmp->isshk && !in_his_shop && inhishop(mtmp))
check_special_room(FALSE);
if(ib) {
if (cansee(mtmp->mx,mtmp->my))
pline("%s picks up %s.", Monnam(mtmp),
distant_name(ib,doname));
obj_extract_self(ib);
(void) mpickobj(mtmp, ib);
}
return(1);
}
return(0);
}
char
temple_occupied(array)
register char *array;
{
register char *ptr;
for (ptr = array; *ptr; ptr++)
if (rooms[*ptr - ROOMOFFSET].rtype == TEMPLE)
return(*ptr);
return('\0');
}
STATIC_OVL boolean
histemple_at(priest, x, y)
register struct monst *priest;
register xchar x, y;
{
return((boolean)((EPRI(priest)->shroom == *in_rooms(x, y, TEMPLE)) &&
on_level(&(EPRI(priest)->shrlevel), &u.uz)));
}
boolean
inhistemple(priest)
struct monst *priest;
{
/* make sure we have a priest */
if (!priest || !priest->ispriest) return FALSE;
/* priest must be on right level and in right room */
if (!histemple_at(priest, priest->mx, priest->my)) return FALSE;
/* temple room must still contain properly aligned altar */
return has_shrine(priest);
}
/*
* pri_move: return 1: moved 0: didn't -1: let m_move do it -2: died
*/
int
pri_move(priest)
register struct monst *priest;
{
register xchar gx,gy,omx,omy;
schar temple;
boolean avoid = TRUE;
omx = priest->mx;
omy = priest->my;
if(!histemple_at(priest, omx, omy)) return(-1);
temple = EPRI(priest)->shroom;
gx = EPRI(priest)->shrpos.x;
gy = EPRI(priest)->shrpos.y;
gx += rn1(3,-1); /* mill around the altar */
gy += rn1(3,-1);
if(!priest->mpeaceful ||
(Conflict && !resist(priest, RING_CLASS, 0, 0))) {
if(monnear(priest, u.ux, u.uy)) {
if(Displaced)
Your("displaced image doesn't fool %s!",
mon_nam(priest));
(void) mattacku(priest);
return(0);
} else if(index(u.urooms, temple)) {
/* chase player if inside temple & can see him */
if(priest->mcansee && m_canseeu(priest)) {
gx = u.ux;
gy = u.uy;
}
avoid = FALSE;
}
} else if(Invis) avoid = FALSE;
return(move_special(priest,FALSE,TRUE,FALSE,avoid,omx,omy,gx,gy));
}
/* exclusively for mktemple() */
void
priestini(lvl, sroom, sx, sy, sanctum)
d_level *lvl;
struct mkroom *sroom;
int sx, sy;
boolean sanctum; /* is it the seat of the high priest? */
{
struct monst *priest;
struct obj *otmp;
int cnt;
if(MON_AT(sx+1, sy))
(void) rloc(m_at(sx+1, sy), FALSE); /* insurance */
priest = makemon(&mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST],
sx + 1, sy, MM_EPRI);
if (priest) {
EPRI(priest)->shroom = (schar)((sroom - rooms) + ROOMOFFSET);
EPRI(priest)->shralign = Amask2align(levl[sx][sy].altarmask);
EPRI(priest)->shrpos.x = sx;
EPRI(priest)->shrpos.y = sy;
assign_level(&(EPRI(priest)->shrlevel), lvl);
priest->mtrapseen = ~0; /* traps are known */
priest->mpeaceful = 1;
priest->ispriest = 1;
priest->isminion = 0;
priest->msleeping = 0;
set_malign(priest); /* mpeaceful may have changed */
/* now his/her goodies... */
if(sanctum && EPRI(priest)->shralign == A_NONE &&
on_level(&sanctum_level, &u.uz)) {
(void) mongets(priest, AMULET_OF_YENDOR);
}
/* 2 to 4 spellbooks */
for (cnt = rn1(3,2); cnt > 0; --cnt) {
(void) mpickobj(priest, mkobj(SPBOOK_CLASS, FALSE));
}
/* robe [via makemon()] */
if (rn2(2) && (otmp = which_armor(priest, W_ARMC)) != 0) {
if (p_coaligned(priest))
uncurse(otmp);
else
curse(otmp);
}
}
}
/* get a monster's alignment type without caller needing EPRI & EMIN */
aligntyp
mon_aligntyp(mon)
struct monst *mon;
{
aligntyp algn = mon->ispriest ? EPRI(mon)->shralign :
mon->isminion ? EMIN(mon)->min_align :
mon->data->maligntyp;
if (algn == A_NONE) return A_NONE; /* negative but differs from chaotic */
return (algn > 0) ? A_LAWFUL : (algn < 0) ? A_CHAOTIC : A_NEUTRAL;
}
/*
* Specially aligned monsters are named specially.
* - aligned priests with ispriest and high priests have shrines
* they retain ispriest and epri when polymorphed
* - aligned priests without ispriest are roamers
* they have isminion set and use emin rather than epri
* - minions do not have ispriest but have isminion and emin
* - caller needs to inhibit Hallucination if it wants to force
* the true name even when under that influence
*/
char *
priestname(mon, pname)
register struct monst *mon;
char *pname; /* caller-supplied output buffer */
{
boolean do_hallu = Hallucination,
aligned_priest = mon->data == &mons[PM_ALIGNED_PRIEST],
high_priest = mon->data == &mons[PM_HIGH_PRIEST];
const char *what = do_hallu ? rndmonnam() : mon->data->mname;
if (!mon->ispriest && !mon->isminion) /* should never happen... */
return strcpy(pname, what); /* caller must be confused */
*pname = '\0';
if (!do_hallu || !bogon_is_pname(what)) Strcat(pname, "the ");
if (mon->minvis) Strcat(pname, "invisible ");
if (mon->isminion && EMIN(mon)->renegade)
Strcat(pname, "renegade ");
if (mon->ispriest || aligned_priest) { /* high_priest implies ispriest */
if (!aligned_priest && !high_priest) {
; /* polymorphed priest; use ``what'' as is */
} else {
if (high_priest)
Strcat(pname, "high ");
if (Hallucination)
what = "poohbah";
else if (mon->female)
what = "priestess";
else
what = "priest";
}
} else {
if (mon->mtame && !strcmpi(what, "Angel"))
Strcat(pname, "guardian ");
}
Strcat(pname, what);
/* same as distant_monnam(), more or less... */
if (do_hallu || !high_priest || !Is_astralevel(&u.uz) ||
distu(mon->mx, mon->my) <= 2 || program_state.gameover) {
Strcat(pname, " of ");
Strcat(pname, halu_gname(mon_aligntyp(mon)));
}
return pname;
}
boolean
p_coaligned(priest)
struct monst *priest;
{
return((boolean)(u.ualign.type == ((int)EPRI(priest)->shralign)));
}
STATIC_OVL boolean
has_shrine(pri)
struct monst *pri;
{
struct rm *lev;
struct epri *epri_p;
if (!pri || !pri->ispriest) return FALSE;
epri_p = EPRI(pri);
lev = &levl[epri_p->shrpos.x][epri_p->shrpos.y];
if (!IS_ALTAR(lev->typ) || !(lev->altarmask & AM_SHRINE)) return FALSE;
return (boolean)(epri_p->shralign ==
(Amask2align(lev->altarmask & ~AM_SHRINE)));
}
struct monst *
findpriest(roomno)
char roomno;
{
register struct monst *mtmp;
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp)) continue;
if(mtmp->ispriest && (EPRI(mtmp)->shroom == roomno) &&
histemple_at(mtmp,mtmp->mx,mtmp->my))
return(mtmp);
}
return (struct monst *)0;
}
/* called from check_special_room() when the player enters the temple room */
void
intemple(roomno)
int roomno;
{
struct monst *priest, *mtmp;
struct epri *epri_p;
boolean shrined, sanctum, can_speak;
long *this_time, *other_time;
const char *msg1, *msg2;
char buf[BUFSZ];
/* don't do anything if hero is already in the room */
if (temple_occupied(u.urooms0)) return;
if ((priest = findpriest((char)roomno)) != 0) {
/* tended */
epri_p = EPRI(priest);
shrined = has_shrine(priest);
sanctum = (priest->data == &mons[PM_HIGH_PRIEST] &&
(Is_sanctum(&u.uz) || In_endgame(&u.uz)));
can_speak = (priest->mcanmove && !priest->msleeping);
if (can_speak && !Deaf && moves >= epri_p->intone_time) {
unsigned save_priest = priest->ispriest;
/* don't reveal the altar's owner upon temple entry in
the endgame; for the Sanctum, the next message names
Moloch so suppress the "of Moloch" for him here too */
if (sanctum && !Hallucination) priest->ispriest = 0;
pline("%s intones:",
canseemon(priest) ? Monnam(priest) : "A nearby voice");
priest->ispriest = save_priest;
epri_p->intone_time = moves + (long)d(10, 500); /* ~2505 */
/* make sure that we don't suppress entry message when
we've just given its "priest intones" introduction */
epri_p->enter_time = 0L;
}
msg1 = msg2 = 0;
if (sanctum && Is_sanctum(&u.uz)) {
if (priest->mpeaceful) {
/* first time inside */
msg1 = "Infidel, you have entered Moloch's Sanctum!";
msg2 = "Be gone!";
priest->mpeaceful = 0;
/* became angry voluntarily; no penalty for attacking him */
set_malign(priest);
} else {
/* repeat visit, or attacked priest before entering */
msg1 = "You desecrate this place by your presence!";
}
} else if (moves >= epri_p->enter_time) {
Sprintf(buf, "Pilgrim, you enter a %s place!",
!shrined ? "desecrated" : "sacred");
msg1 = buf;
}
if (msg1 && can_speak && !Deaf) {
verbalize1(msg1);
if (msg2) verbalize1(msg2);
epri_p->enter_time = moves + (long)d(10, 100); /* ~505 */
}
if (!sanctum) {
if (!shrined || !p_coaligned(priest) ||
u.ualign.record <= ALGN_SINNED) {
msg1 = "have a%s forbidding feeling...";
msg2 = (!shrined || !p_coaligned(priest)) ? "" : " strange";
this_time = &epri_p->hostile_time;
other_time = &epri_p->peaceful_time;
} else {
msg1 = "experience %s sense of peace.";
msg2 = (u.ualign.record >= ALGN_PIOUS) ? "a" : "an unusual";
this_time = &epri_p->peaceful_time;
other_time = &epri_p->hostile_time;
}
/* give message if we haven't seen it recently or
if alignment update has caused it to switch from
forbidding to sense-of-peace or vice versa */
if (moves >= *this_time || *other_time >= *this_time) {
You(msg1, msg2);
*this_time = moves + (long)d(10, 20); /* ~55 */
/* avoid being tricked by the RNG: switch might have just
happened and previous random threshold could be larger */
if (*this_time <= *other_time) *other_time = *this_time - 1L;
}
}
#ifdef DUNGEON_OVERVIEW
/* recognize the Valley of the Dead and Moloch's Sanctum
once hero has encountered the temple priest on those levels */
mapseen_temple(priest);
#endif
} else {
/* untended */
switch (rn2(4)) {
case 0: You("have an eerie feeling..."); break;
case 1: You_feel("like you are being watched."); break;
case 2: pline("A shiver runs down your %s.",
body_part(SPINE)); break;
default: break; /* no message; unfortunately there's no
EPRI(priest)->eerie_time available to
make sure we give one the first time */
}
if (!rn2(5) &&
(mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS)) != 0) {
/* [TODO: alter this (at a minimum, by switching from
an exclamation to a simple declaration) if hero has
already killed enough ghosts.] */
if (canspotmon(mtmp))
pline("An enormous ghost appears next to you!");
else
You("sense a presence close by!");
mtmp->mpeaceful = 0;
set_malign(mtmp);
if (flags.verbose)
You("are frightened to death, and unable to move.");
nomul(-3);
nomovemsg = "You regain your composure.";
}
}
}
/* reset the move counters used to limit temple entry feedback;
leaving the level and then returning yields a fresh start */
void
forget_temple_entry(priest)
struct monst *priest;
{
struct epri *epri_p = priest->ispriest ? EPRI(priest) : 0;
if (!epri_p) {
impossible("attempting to manipulate shrine data for non-priest?");
return;
}
epri_p->intone_time = epri_p->enter_time =
epri_p->peaceful_time = epri_p->hostile_time = 0L;
}
void
priest_talk(priest)
register struct monst *priest;
{
boolean coaligned = p_coaligned(priest);
boolean strayed = (u.ualign.record < 0);
/* KMH, conduct */
u.uconduct.gnostic++;
if(priest->mflee || (!priest->ispriest && coaligned && strayed)) {
pline("%s doesn't want anything to do with you!",
Monnam(priest));
priest->mpeaceful = 0;
return;
}
/* priests don't chat unless peaceful and in their own temple */
if(!histemple_at(priest,priest->mx,priest->my) ||
!priest->mpeaceful || !priest->mcanmove || priest->msleeping) {
static const char *cranky_msg[3] = {
"Thou wouldst have words, eh? I'll give thee a word or two!",
"Talk? Here is what I have to say!",
"Pilgrim, I would speak no longer with thee."
};
if(!priest->mcanmove || priest->msleeping) {
pline("%s breaks out of %s reverie!",
Monnam(priest), mhis(priest));
priest->mfrozen = priest->msleeping = 0;
priest->mcanmove = 1;
}
priest->mpeaceful = 0;
verbalize1(cranky_msg[rn2(3)]);
return;
}
/* you desecrated the temple and now you want to chat? */
if(priest->mpeaceful && *in_rooms(priest->mx, priest->my, TEMPLE) &&
!has_shrine(priest)) {
verbalize("Begone! Thou desecratest this holy place with thy presence.");
priest->mpeaceful = 0;
return;
}
#ifndef GOLDOBJ
if(!u.ugold) {
if(coaligned && !strayed) {
if (priest->mgold > 0L) {
/* Note: two bits is actually 25 cents. Hmm. */
pline("%s gives you %s for an ale.", Monnam(priest),
(priest->mgold == 1L) ? "one bit" : "two bits");
if (priest->mgold > 1L)
u.ugold = 2L;
else
u.ugold = 1L;
priest->mgold -= u.ugold;
context.botl = 1;
#else
if(!money_cnt(invent)) {
if(coaligned && !strayed) {
long pmoney = money_cnt(priest->minvent);
if (pmoney > 0L) {
/* Note: two bits is actually 25 cents. Hmm. */
pline("%s gives you %s for an ale.", Monnam(priest),
(pmoney == 1L) ? "one bit" : "two bits");
money2u(priest, pmoney > 1L ? 2 : 1);
#endif
} else
pline("%s preaches the virtues of poverty.", Monnam(priest));
exercise(A_WIS, TRUE);
} else
pline("%s is not interested.", Monnam(priest));
return;
} else {
long offer;
pline("%s asks you for a contribution for the temple.",
Monnam(priest));
if((offer = bribe(priest)) == 0) {
verbalize("Thou shalt regret thine action!");
if(coaligned) adjalign(-1);
} else if(offer < (u.ulevel * 200)) {
#ifndef GOLDOBJ
if(u.ugold > (offer * 2L)) verbalize("Cheapskate.");
#else
if(money_cnt(invent) > (offer * 2L)) verbalize("Cheapskate.");
#endif
else {
verbalize("I thank thee for thy contribution.");
/* give player some token */
exercise(A_WIS, TRUE);
}
} else if(offer < (u.ulevel * 400)) {
verbalize("Thou art indeed a pious individual.");
#ifndef GOLDOBJ
if(u.ugold < (offer * 2L)) {
#else
if(money_cnt(invent) < (offer * 2L)) {
#endif
if (coaligned && u.ualign.record <= ALGN_SINNED)
adjalign(1);
verbalize("I bestow upon thee a blessing.");
incr_itimeout(&HClairvoyant, rn1(500,500));
}
} else if(offer < (u.ulevel * 600) &&
/* u.ublessed is only active when Protection is
enabled via something other than worn gear
(theft by gremlin clears the intrinsic but not
its former magnitude, making it recoverable) */
(!(HProtection & INTRINSIC) ||
(u.ublessed < 20 &&
(u.ublessed < 9 || !rn2(u.ublessed))))) {
verbalize("Thy devotion has been rewarded.");
if (!(HProtection & INTRINSIC)) {
HProtection |= FROMOUTSIDE;
if (!u.ublessed) u.ublessed = rn1(3, 2);
} else u.ublessed++;
} else {
verbalize("Thy selfless generosity is deeply appreciated.");
#ifndef GOLDOBJ
if(u.ugold < (offer * 2L) && coaligned) {
#else
if(money_cnt(invent) < (offer * 2L) && coaligned) {
#endif
if(strayed && (moves - u.ucleansed) > 5000L) {
u.ualign.record = 0; /* cleanse thee */
u.ucleansed = moves;
} else {
adjalign(2);
}
}
}
}
}
struct monst *
mk_roamer(ptr, alignment, x, y, peaceful)
register struct permonst *ptr;
aligntyp alignment;
xchar x, y;
boolean peaceful;
{
register struct monst *roamer;
register boolean coaligned = (u.ualign.type == alignment);
#if 0 /* this was due to permonst's pxlth field which is now gone */
if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL])
return((struct monst *)0);
#endif
if (MON_AT(x, y)) (void) rloc(m_at(x, y), FALSE); /* insurance */
if (!(roamer = makemon(ptr, x, y, MM_ADJACENTOK|MM_EMIN)))
return((struct monst *)0);
EMIN(roamer)->min_align = alignment;
EMIN(roamer)->renegade = (coaligned && !peaceful);
roamer->ispriest = 0;
roamer->isminion = 1;
roamer->mtrapseen = ~0; /* traps are known */
roamer->mpeaceful = peaceful;
roamer->msleeping = 0;
set_malign(roamer); /* peaceful may have changed */
/* MORE TO COME */
return(roamer);
}
void
reset_hostility(roamer)
register struct monst *roamer;
{
if (!roamer->isminion) return;
if (roamer->data != &mons[PM_ALIGNED_PRIEST] &&
roamer->data != &mons[PM_ANGEL]) return;
if (EMIN(roamer)->min_align != u.ualign.type) {
roamer->mpeaceful = roamer->mtame = 0;
set_malign(roamer);
}
newsym(roamer->mx, roamer->my);
}
boolean
in_your_sanctuary(mon, x, y)
struct monst *mon; /* if non-null, <mx,my> overrides <x,y> */
xchar x, y;
{
register char roomno;
register struct monst *priest;
if (mon) {
if (is_minion(mon->data) || is_rider(mon->data)) return FALSE;
x = mon->mx, y = mon->my;
}
if (u.ualign.record <= ALGN_SINNED) /* sinned or worse */
return FALSE;
if ((roomno = temple_occupied(u.urooms)) == 0 ||
roomno != *in_rooms(x, y, TEMPLE))
return FALSE;
if ((priest = findpriest(roomno)) == 0)
return FALSE;
return (boolean)(has_shrine(priest) &&
p_coaligned(priest) &&
priest->mpeaceful);
}
void
ghod_hitsu(priest) /* when attacking "priest" in his temple */
struct monst *priest;
{
int x, y, ax, ay, roomno = (int)temple_occupied(u.urooms);
struct mkroom *troom;
if (!roomno || !has_shrine(priest))
return;
ax = x = EPRI(priest)->shrpos.x;
ay = y = EPRI(priest)->shrpos.y;
troom = &rooms[roomno - ROOMOFFSET];
if ((u.ux == x && u.uy == y) || !linedup(u.ux, u.uy, x, y, 1)) {
if(IS_DOOR(levl[u.ux][u.uy].typ)) {
if(u.ux == troom->lx - 1) {
x = troom->hx;
y = u.uy;
} else if(u.ux == troom->hx + 1) {
x = troom->lx;
y = u.uy;
} else if(u.uy == troom->ly - 1) {
x = u.ux;
y = troom->hy;
} else if(u.uy == troom->hy + 1) {
x = u.ux;
y = troom->ly;
}
} else {
switch(rn2(4)) {
case 0: x = u.ux; y = troom->ly; break;
case 1: x = u.ux; y = troom->hy; break;
case 2: x = troom->lx; y = u.uy; break;
default: x = troom->hx; y = u.uy; break;
}
}
if (!linedup(u.ux, u.uy, x, y, 1)) return;
}
switch(rn2(3)) {
case 0:
pline("%s roars in anger: \"Thou shalt suffer!\"",
a_gname_at(ax, ay));
break;
case 1:
pline("%s voice booms: \"How darest thou harm my servant!\"",
s_suffix(a_gname_at(ax, ay)));
break;
default:
pline("%s roars: \"Thou dost profane my shrine!\"",
a_gname_at(ax, ay));
break;
}
buzz(-10-(AD_ELEC-1), 6, x, y, sgn(tbx), sgn(tby)); /* bolt of lightning */
exercise(A_WIS, FALSE);
}
void
angry_priest()
{
register struct monst *priest;
struct rm *lev;
if ((priest = findpriest(temple_occupied(u.urooms))) != 0) {
struct epri *eprip = EPRI(priest);
wakeup(priest);
/*
* If the altar has been destroyed or converted, let the
* priest run loose.
* (When it's just a conversion and there happens to be
* a fresh corpse nearby, the priest ought to have an
* opportunity to try converting it back; maybe someday...)
*/
lev = &levl[eprip->shrpos.x][eprip->shrpos.y];
if (!IS_ALTAR(lev->typ) ||
((aligntyp)Amask2align(lev->altarmask & AM_MASK) !=
eprip->shralign)) {
if (!EMIN(priest)) newemin(priest);
priest->ispriest = 0; /* now a roaming minion */
priest->isminion = 1;
EMIN(priest)->min_align = eprip->shralign;
EMIN(priest)->renegade = FALSE;
/* discard priest's memory of his former shrine;
if we ever implement the re-conversion mentioned
above, this will need to be removed */
free_epri(priest);
}
}
}
/*
* When saving bones, find priests that aren't on their shrine level,
* and remove them. This avoids big problems when restoring bones.
* [Perhaps we should convert them into roamers instead?]
*/
void
clearpriests()
{
struct monst *mtmp;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp)) continue;
if (mtmp->ispriest && !on_level(&(EPRI(mtmp)->shrlevel), &u.uz))
mongone(mtmp);
}
}
/* munge priest-specific structure when restoring -dlc */
void
restpriest(mtmp, ghostly)
register struct monst *mtmp;
boolean ghostly;
{
if(u.uz.dlevel) {
if (ghostly)
assign_level(&(EPRI(mtmp)->shrlevel), &u.uz);
}
}
/*priest.c*/