-/* 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. */
struct emin {
aligntyp min_align; /* alignment of minion */
+ boolean renegade; /* hostile co-aligned priest or Angel */
};
#define EMIN(mon) ((struct emin *)&(mon)->mextra[0])
-/* 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. */
#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 */
-/* 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. */
* 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"
-/* 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. */
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)) {
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);
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--;
}
}
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));
}
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]))
-/* 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. */
#include "eshk.h"
#include "vault.h"
#include "epri.h"
+#include "emin.h"
#define NO_ATTK {0,0,0,0}
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,
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),
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),
-/* 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. */
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 */
* 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
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);
+ 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;
+
+ 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
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;
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);
}
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);
}
}