From 62daa2cdaca98a06ffa54236c06a6ec22c768348 Mon Sep 17 00:00:00 2001 From: jwalz Date: Sat, 5 Jan 2002 21:05:52 +0000 Subject: [PATCH] *** empty log message *** --- src/priest.c | 714 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 714 insertions(+) create mode 100644 src/priest.c diff --git a/src/priest.c b/src/priest.c new file mode 100644 index 000000000..614fd7321 --- /dev/null +++ b/src/priest.c @@ -0,0 +1,714 @@ +/* SCCS Id: @(#)priest.c 3.3 2001/11/07 */ +/* Copyright (c) Izchak Miller, Steve Linhart, 1989. */ +/* NetHack may be freely redistributed. See license for details. */ + +#include "hack.h" +#include "mfndpos.h" +#include "eshk.h" +#include "epri.h" +#include "emin.h" + +/* this matches the categorizations shown by enlightenment */ +#define ALGN_SINNED (-4) /* worse than strayed */ + +#ifdef OVLB + +STATIC_DCL boolean FDECL(histemple_at,(struct monst *,XCHAR_P,XCHAR_P)); +STATIC_DCL boolean FDECL(has_shrine,(struct monst *)); + +/* + * 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) && + (!needspick(mtmp->data) || m_carrying(mtmp, PICK_AXE) || + m_carrying(mtmp, DWARVISH_MATTOCK))) + 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; iispriest && + levl[nx][ny].typ == ALTAR) || + (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); +} + +#endif /* OVLB */ + +#ifdef OVL0 + +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'); +} + +#endif /* OVL0 */ +#ifdef OVLB + +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))); +} + +/* + * 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)) + rloc(m_at(sx+1, sy)); /* insurance */ + + priest = makemon(&mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST], + sx + 1, sy, NO_MM_FLAGS); + if (priest) { + EPRI(priest)->shroom = (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->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); + } + } +} + +/* + * 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 and Angels are roamers + * they retain isminion and access epri as emin when polymorphed + * (coaligned Angels are also created as minions, but they + * use the same naming convention) + * - 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 */ +{ + const char *what = Hallucination ? rndmonnam() : mon->data->mname; + + Strcpy(pname, "the "); + if (mon->minvis) Strcat(pname, "invisible "); + if (mon->ispriest || mon->data == &mons[PM_ALIGNED_PRIEST] || + mon->data == &mons[PM_ANGEL]) { + /* use epri */ + if (mon->mtame && mon->data == &mons[PM_ANGEL]) + Strcat(pname, "guardian "); + if (mon->data != &mons[PM_ALIGNED_PRIEST] && + mon->data != &mons[PM_HIGH_PRIEST]) { + Strcat(pname, what); + Strcat(pname, " "); + } + if (mon->data != &mons[PM_ANGEL]) { + if (!mon->ispriest && EPRI(mon)->renegade) + Strcat(pname, "renegade "); + if (mon->data == &mons[PM_HIGH_PRIEST]) + Strcat(pname, "high "); + if (Hallucination) + Strcat(pname, "poohbah "); + else if (mon->female) + Strcat(pname, "priestess "); + else + Strcat(pname, "priest "); + } + Strcat(pname, "of "); + Strcat(pname, halu_gname((int)EPRI(mon)->shralign)); + return(pname); + } + /* use emin instead of epri */ + Strcat(pname, what); + Strcat(pname, " of "); + Strcat(pname, halu_gname(EMIN(mon)->min_align)); + 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; + + if(!pri) + return(FALSE); + lev = &levl[EPRI(pri)->shrpos.x][EPRI(pri)->shrpos.y]; + if (!IS_ALTAR(lev->typ) || !(lev->altarmask & AM_SHRINE)) + return(FALSE); + return((boolean)(EPRI(pri)->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) +register int roomno; +{ + register struct monst *priest = findpriest((char)roomno); + boolean tended = (priest != (struct monst *)0); + boolean shrined, sanctum, can_speak; + const char *msg1, *msg2; + char buf[BUFSZ]; + + if(!temple_occupied(u.urooms0)) { + if(tended) { + 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) + pline("%s intones:", + (!Blind ? Monnam(priest) : "A nearby voice")); + msg2 = 0; + if(sanctum && Is_sanctum(&u.uz)) { + if(priest->mpeaceful) { + msg1 = "Infidel, you entered Moloch's Sanctum!"; + msg2 = "Be gone!"; + priest->mpeaceful = 0; + set_malign(priest); + } else + msg1 = "You desecrate this place by your presence!"; + } else { + Sprintf(buf, "Pilgrim, you enter a %s place!", + !shrined ? "desecrated" : "sacred"); + msg1 = buf; + } + if (can_speak) { + verbalize(msg1); + if (msg2) verbalize(msg2); + } + if(!sanctum) { + /* !tended -> !shrined */ + if (!shrined || !p_coaligned(priest) || + u.ualign.record <= ALGN_SINNED) + You("have a%s forbidding feeling...", + (!shrined) ? "" : " strange"); + else You("experience a strange sense of peace."); + } + } else { + switch(rn2(3)) { + case 0: You("have an eerie feeling..."); break; + case 1: You_feel("like you are being watched."); break; + default: pline("A shiver runs down your %s.", + body_part(SPINE)); break; + } + if(!rn2(5)) { + struct monst *mtmp; + + if(!(mtmp = makemon(&mons[PM_GHOST],u.ux,u.uy,NO_MM_FLAGS))) + return; + pline("An enormous ghost appears next to you!"); + 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."; + } + } + } +} + +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; + verbalize(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; + flags.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 < 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 (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL]) + return((struct monst *)0); + + if (MON_AT(x, y)) rloc(m_at(x, y)); /* insurance */ + + if (!(roamer = makemon(ptr, x, y, NO_MM_FLAGS))) + return((struct monst *)0); + + EPRI(roamer)->shralign = alignment; + if (coaligned && !peaceful) + EPRI(roamer)->renegade = TRUE; + /* roamer->ispriest == FALSE naturally */ + roamer->isminion = TRUE; /* borrowing this bit */ + 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 && (roamer->data == &mons[PM_ALIGNED_PRIEST] || + roamer->data == &mons[PM_ANGEL]))) + return; + + if(EPRI(roamer)->shralign != 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, overrides */ +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)) { + 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)) 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) { + 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[EPRI(priest)->shrpos.x][EPRI(priest)->shrpos.y]; + if (!IS_ALTAR(lev->typ) || + ((aligntyp)Amask2align(lev->altarmask & AM_MASK) != + EPRI(priest)->shralign)) { + priest->ispriest = 0; /* now a roamer */ + priest->isminion = 1; /* but still aligned */ + /* this overloads the `shroom' field, which is now clobbered */ + EPRI(priest)->renegade = 0; + } + } +} + +/* + * When saving bones, find priests that aren't on their shrine level, + * and remove them. This avoids big problems when restoring bones. + */ +void +clearpriests() +{ + register struct monst *mtmp, *mtmp2; + + for(mtmp = fmon; mtmp; mtmp = mtmp2) { + mtmp2 = mtmp->nmon; + if (!DEADMONSTER(mtmp) && 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); + } +} + +#endif /* OVLB */ + +/*priest.c*/