diff --git a/include/emin.h b/include/emin.h index cbd49efdf..f856a16f9 100644 --- a/include/emin.h +++ b/include/emin.h @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)emin.h 3.5 1997/05/01 */ +/* SCCS Id: @(#)emin.h 3.5 2005/11/02 */ /* Copyright (c) David Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -7,6 +7,7 @@ struct emin { aligntyp min_align; /* alignment of minion */ + boolean renegade; /* hostile co-aligned priest or Angel */ }; #define EMIN(mon) ((struct emin *)&(mon)->mextra[0]) diff --git a/include/epri.h b/include/epri.h index 806c87378..221bb16b1 100644 --- a/include/epri.h +++ b/include/epri.h @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)epri.h 3.5 1997/05/01 */ +/* SCCS Id: @(#)epri.h 3.5 2005/11/02 */ /* Copyright (c) Izchak Miller, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -15,10 +15,7 @@ struct epri { #define EPRI(mon) ((struct epri *)&(mon)->mextra[0]) -/* A priest without ispriest is a roaming priest without a shrine, so - * the fields (except shralign, which becomes only the priest alignment) - * are available for reuse. - */ -#define renegade shroom +/* note: roaming priests (no shrine) switch from ispriest to isminion + (and emin extension) */ #endif /* EPRI_H */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 73b6d6e0f..920b463b1 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)patchlevel.h 3.5 2005/09/12 */ +/* SCCS Id: @(#)patchlevel.h 3.5 2005/11/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -13,7 +13,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 23 +#define EDITLEVEL 24 #define COPYRIGHT_BANNER_A \ "NetHack, Copyright 1985-2005" diff --git a/src/makemon.c b/src/makemon.c index 05945ab6c..c4dd7614f 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)makemon.c 3.5 2005/09/20 */ +/* SCCS Id: @(#)makemon.c 3.5 2005/11/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1098,6 +1098,18 @@ register int mmflags; initworm(mtmp, rn2(5)); if (count_wsegs(mtmp)) place_worm_tail_randomly(mtmp, x, y); } + /* it's possible to create an ordinary monster of some special + types; make sure their extended data is initialized to + something sensible (caller can override these settings) */ + if (mndx == PM_ALIGNED_PRIEST || (mndx == PM_ANGEL && !rn2(3))) { + struct emin *eminp = EMIN(mtmp); + + mtmp->isminion = 1; /* make priest be a roamer */ + eminp->min_align = rn2(3) - 1; /* no A_NONE */ + eminp->renegade = (mmflags & MM_ANGRY) ? 1 : !rn2(3); + mtmp->mpeaceful = (eminp->min_align == u.ualign.type) ? + !eminp->renegade : eminp->renegade; + } set_malign(mtmp); /* having finished peaceful changes */ if(anymon) { if ((ptr->geno & G_SGROUP) && rn2(2)) { diff --git a/src/minion.c b/src/minion.c index c2ca712fb..0480ea1d2 100644 --- a/src/minion.c +++ b/src/minion.c @@ -17,15 +17,14 @@ struct monst *mon; if (mon) { ptr = mon->data; - atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp); - if (mon->ispriest || mon->data == &mons[PM_ALIGNED_PRIEST] - || mon->data == &mons[PM_ANGEL]) - atyp = EPRI(mon)->shralign; + atyp = mon->ispriest ? EPRI(mon)->shralign : + mon->isminion ? EMIN(mon)->min_align : + (ptr->maligntyp == A_NONE) ? A_NONE : sgn(ptr->maligntyp); } else { ptr = &mons[PM_WIZARD_OF_YENDOR]; atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp); } - + if (is_dprince(ptr) || (ptr == &mons[PM_WIZARD_OF_YENDOR])) { dtype = (!rn2(20)) ? dprince(atyp) : (!rn2(4)) ? dlord(atyp) : ndemon(atyp); @@ -78,7 +77,14 @@ struct monst *mon; if (mtmp) { result++; /* an angel's alignment should match the summoner */ - if (dtype == PM_ANGEL) EPRI(mtmp)->shralign = atyp; + if (dtype == PM_ANGEL) { + mtmp->isminion = 1; + EMIN(mtmp)->min_align = atyp; + /* renegade if same alignment but not peaceful + or peaceful but different alignment */ + EMIN(mtmp)->renegade = + (atyp != u.ualign.type) ^ !mtmp->mpeaceful; + } } cnt--; } @@ -111,21 +117,17 @@ boolean talk; } if (mnum == NON_PM) { mon = 0; - } else if (mons[mnum].pxlth == 0) { - struct permonst *pm = &mons[mnum]; - mon = makemon(pm, u.ux, u.uy, MM_EMIN); + } else if (mons[mnum].pxlth == 0 || mnum == PM_ANGEL) { + mon = makemon(&mons[mnum], u.ux, u.uy, + (mnum == PM_ANGEL) ? NO_MM_FLAGS : MM_EMIN); if (mon) { - mon->isminion = TRUE; + mon->isminion = 1; EMIN(mon)->min_align = alignment; + EMIN(mon)->renegade = FALSE; } - } else if (mnum == PM_ANGEL) { - mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS); - if (mon) { - mon->isminion = TRUE; - EPRI(mon)->shralign = alignment; /* always A_LAWFUL here */ - } - } else + } else { mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS); + } if (mon) { if (talk) { pline_The("voice of %s booms:", align_gname(alignment)); @@ -340,8 +342,8 @@ struct monst *mon; /* if null, angel hasn't been created yet */ } mongone(mon); } - /* create 1 to 4 hostile angels to replace the lost guardian */ - for (i = rnd(4); i > 0; --i) { + /* create 2 to 4 hostile angels to replace the lost guardian */ + for (i = rn1(3,2); i > 0; --i) { mm.x = u.ux; mm.y = u.uy; if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) diff --git a/src/monst.c b/src/monst.c index 307298e4f..daf6b840c 100644 --- a/src/monst.c +++ b/src/monst.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)monst.c 3.5 2000/07/14 */ +/* SCCS Id: @(#)monst.c 3.5 2005/11/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,6 +9,7 @@ #include "eshk.h" #include "vault.h" #include "epri.h" +#include "emin.h" #define NO_ATTK {0,0,0,0} @@ -1085,12 +1086,16 @@ NEARDATA struct permonst mons[] = { M1_HUMANOID|M1_SEE_INVIS, M2_MINION|M2_STALK|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_YELLOW), + /* Angels start with the emin extension attached, and usually have + the isminion flag set; however, non-minion Angels can be tamed + and will switch to edog (guardian Angel is handled specially and + always sticks with emin) */ MON("Angel", S_ANGEL, LVL(14, 10, -4, 55, 12), (G_NOHELL|G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_MAGC, AD_MAGM, 2, 6), NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, sizeof(struct epri), MS_CUSS, MZ_HUMAN), + SIZ(WT_HUMAN, 400, sizeof(struct emin), MS_CUSS, MZ_HUMAN), MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, 0, M1_FLY|M1_HUMANOID|M1_SEE_INVIS, M2_NOPOLY|M2_MINION|M2_STALK|M2_STRONG|M2_NASTY|M2_COLLECT, @@ -2391,6 +2396,9 @@ struct permonst _mons2[] = { SIZ(WT_HUMAN, 400, 0, MS_ORACLE, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_FEMALE, M3_INFRAVISIBLE, HI_ZAP), + /* aligned priests always have the epri extension attached; + individual instantiations should always have either ispriest + or isminion set */ MON("aligned priest", S_HUMAN, LVL(12, 12, 10, 50, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_KICK, AD_PHYS, 1, 4), @@ -2399,6 +2407,7 @@ struct permonst _mons2[] = { MR_ELEC, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_LORD|M2_PEACEFUL|M2_COLLECT, M3_INFRAVISIBLE, CLR_WHITE), + /* high priests always have epri and always have ispriest set */ MON("high priest", S_HUMAN, LVL(25, 15, 7, 70, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_KICK, AD_PHYS, 2, 8), diff --git a/src/priest.c b/src/priest.c index f98ba9e32..313b769cd 100644 --- a/src/priest.c +++ b/src/priest.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)priest.c 3.5 2005/10/01 */ +/* SCCS Id: @(#)priest.c 3.5 2005/11/02 */ /* Copyright (c) Izchak Miller, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -199,6 +199,7 @@ boolean sanctum; /* is it the seat of the high priest? */ 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 */ @@ -238,10 +239,8 @@ struct monst *mon; * 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) + * - aligned priests without ispriest are roamers + * they have isminion set and access epri as emin * - 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 @@ -251,41 +250,40 @@ priestname(mon, pname) register struct monst *mon; char *pname; /* caller-supplied output buffer */ { - const char *what = Hallucination ? rndmonnam() : mon->data->mname; + boolean aligned_priest = mon->data == &mons[PM_ALIGNED_PRIEST], + high_priest = mon->data == &mons[PM_HIGH_PRIEST]; + 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); + if (!mon->ispriest && !mon->isminion) /* should never happen... */ + return strcpy(pname, what); /* caller must be confused */ + + Strcpy(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"; } - /* use emin instead of epri */ - Strcat(pname, what); - Strcat(pname, " of "); - Strcat(pname, halu_gname(EMIN(mon)->min_align)); - return(pname); + } else { + if (mon->mtame) + Strcat(pname, "guardian "); + } + + Strcat(pname, what); + Strcat(pname, " of "); + Strcat(pname, halu_gname(mon_aligntyp(mon))); + return pname; } boolean @@ -544,19 +542,20 @@ boolean peaceful; register struct monst *roamer; register boolean coaligned = (u.ualign.type == alignment); + /* Angel's have the emin extension; aligned priests have the epri + extension, we access it as if it were emin */ if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL]) return((struct monst *)0); - + if (MON_AT(x, y)) (void) rloc(m_at(x, y), FALSE); /* insurance */ - if (!(roamer = makemon(ptr, x, y, NO_MM_FLAGS))) + if (!(roamer = makemon(ptr, x, y, MM_ADJACENTOK))) 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 */ + 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; @@ -570,11 +569,11 @@ void reset_hostility(roamer) register struct monst *roamer; { - if(!(roamer->isminion && (roamer->data == &mons[PM_ALIGNED_PRIEST] || - roamer->data == &mons[PM_ANGEL]))) - return; + if (!roamer->isminion) return; + if (roamer->data != &mons[PM_ALIGNED_PRIEST] && + roamer->data != &mons[PM_ANGEL]) return; - if(EPRI(roamer)->shralign != u.ualign.type) { + if (EMIN(roamer)->min_align != u.ualign.type) { roamer->mpeaceful = roamer->mtame = 0; set_malign(roamer); } @@ -686,24 +685,25 @@ angry_priest() 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; + /* this overloads EPRI's shroom field, which is now clobbered */ + EMIN(priest)->renegade = FALSE; } } } /* * When saving bones, find priests that aren't on their shrine level, - * and remove them. This avoids big problems when restoring bones. + * and remove them. This avoids big problems when restoring bones. + * [Perhaps we should convert them into roamers instead?] */ void clearpriests() { - register struct monst *mtmp, *mtmp2; + struct monst *mtmp; - for(mtmp = fmon; mtmp; mtmp = mtmp2) { - mtmp2 = mtmp->nmon; - if (!DEADMONSTER(mtmp) && mtmp->ispriest && !on_level(&(EPRI(mtmp)->shrlevel), &u.uz)) + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if (mtmp->ispriest && !on_level(&(EPRI(mtmp)->shrlevel), &u.uz)) mongone(mtmp); } }