chameleon behaviour
- restore intended behaviour of kill_genocided_monsters(). It has been incorrect since the chameleon overhaul in June 2004. - eliminate CHAM_ORDINARY and use NON_PM instead.
This commit is contained in:
@@ -43,7 +43,6 @@ struct monst {
|
||||
unsigned m_id;
|
||||
short mnum; /* permanent monster index number */
|
||||
short cham; /* if shapeshifter, orig mons[] idx goes here */
|
||||
#define CHAM_ORDINARY 0 /* not a shapechanger */
|
||||
short movement; /* movement points (derived from permonst definition and added effects */
|
||||
uchar m_lev; /* adjusted difficulty level of monster */
|
||||
aligntyp malign; /* alignment of this monster, relative to the
|
||||
|
||||
@@ -210,8 +210,7 @@ struct obj {
|
||||
#define MAX_EGG_HATCH_TIME 200 /* longest an egg can remain unhatched */
|
||||
#define stale_egg(egg) ((monstermoves - (egg)->age) > (2*MAX_EGG_HATCH_TIME))
|
||||
#define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN)
|
||||
#define polyfodder(obj) (ofood(obj) && \
|
||||
pm_to_cham((obj)->corpsenm) != CHAM_ORDINARY)
|
||||
#define polyfodder(obj) (ofood(obj) && pm_to_cham((obj)->corpsenm) != NON_PM)
|
||||
#define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH)
|
||||
#define mhealup(obj) (ofood(obj) && (obj)->corpsenm == PM_NURSE)
|
||||
|
||||
|
||||
@@ -979,7 +979,7 @@ finish_meating(mtmp)
|
||||
struct monst *mtmp;
|
||||
{
|
||||
mtmp->meating = 0;
|
||||
if (mtmp->m_ap_type && mtmp->mappearance && mtmp->cham == CHAM_ORDINARY) {
|
||||
if (mtmp->m_ap_type && mtmp->mappearance && mtmp->cham == NON_PM) {
|
||||
/* was eating a mimic and now appearance needs resetting */
|
||||
mtmp->m_ap_type = 0;
|
||||
mtmp->mappearance = 0;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* SCCS Id: @(#)makemon.c 3.5 2005/11/02 */
|
||||
/* SCCS Id: @(#)makemon.c 3.5 2006/03/11 */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -1030,11 +1030,11 @@ register int mmflags;
|
||||
|
||||
if (mndx == PM_VLAD_THE_IMPALER)
|
||||
mitem = CANDELABRUM_OF_INVOCATION;
|
||||
mtmp->cham = CHAM_ORDINARY; /* default is "not a shapechanger" */
|
||||
if ((mcham = pm_to_cham(mndx)) != CHAM_ORDINARY) {
|
||||
mtmp->cham = NON_PM; /* default is "not a shapechanger" */
|
||||
if ((mcham = pm_to_cham(mndx)) != NON_PM) {
|
||||
/* this is a shapechanger after all */
|
||||
if (Protection_from_shape_changers) {
|
||||
; /* stuck in its natural form (CHAM_ORDINARY) */
|
||||
; /* stuck in its natural form (NON_PM) */
|
||||
} else {
|
||||
/* General shapechangers start out with random form
|
||||
(this explicitly picks something from the normal
|
||||
|
||||
@@ -1237,7 +1237,7 @@ mdamagem(magr, mdef, mattk)
|
||||
if (mattk->adtyp == AD_DGST) {
|
||||
/* various checks similar to dog_eat and meatobj.
|
||||
* after monkilled() to provide better message ordering */
|
||||
if (mdef->cham != CHAM_ORDINARY) {
|
||||
if (mdef->cham >= LOW_PM) {
|
||||
(void) newcham(magr, (struct permonst *)0, FALSE, TRUE);
|
||||
} else if (mdef->data == &mons[PM_GREEN_SLIME]) {
|
||||
(void) newcham(magr, &mons[PM_GREEN_SLIME], FALSE, TRUE);
|
||||
|
||||
@@ -469,14 +469,14 @@ mattacku(mtmp)
|
||||
}
|
||||
|
||||
/* Special demon handling code */
|
||||
if((mtmp->cham == CHAM_ORDINARY) && is_demon(mdat) && !range2
|
||||
if((mtmp->cham == NON_PM) && is_demon(mdat) && !range2
|
||||
&& mtmp->data != &mons[PM_BALROG]
|
||||
&& mtmp->data != &mons[PM_SUCCUBUS]
|
||||
&& mtmp->data != &mons[PM_INCUBUS])
|
||||
if (!mtmp->mcan && !rn2(13)) (void)msummon(mtmp);
|
||||
|
||||
/* Special lycanthrope handling code */
|
||||
if((mtmp->cham == CHAM_ORDINARY) && is_were(mdat) && !range2) {
|
||||
if((mtmp->cham == NON_PM) && is_were(mdat) && !range2) {
|
||||
|
||||
if(is_human(mdat)) {
|
||||
if(!rn2(5 - (night() * 2)) && !mtmp->mcan) new_were(mtmp);
|
||||
|
||||
@@ -169,7 +169,7 @@ boolean talk;
|
||||
}
|
||||
}
|
||||
|
||||
#define Athome (Inhell && (mtmp->cham == CHAM_ORDINARY))
|
||||
#define Athome (Inhell && (mtmp->cham == NON_PM))
|
||||
|
||||
int
|
||||
demon_talk(mtmp) /* returns 1 if it won't attack. */
|
||||
|
||||
54
src/mon.c
54
src/mon.c
@@ -119,18 +119,18 @@ int mndx, mode;
|
||||
return mndx;
|
||||
}
|
||||
|
||||
/* return monster index if chameleon, or CHAM_ORDINARY if not */
|
||||
/* return monster index if chameleon, or NON_PM if not */
|
||||
int
|
||||
pm_to_cham(mndx)
|
||||
int mndx;
|
||||
{
|
||||
int mcham = CHAM_ORDINARY;
|
||||
int mcham = NON_PM;
|
||||
|
||||
/*
|
||||
* As of 3.5.0 we just check M2_SHAPESHIFTER instead of having a
|
||||
* big switch statement with hardcoded shapeshifter types here.
|
||||
*/
|
||||
if (mndx > LOW_PM && is_shapeshifter(&mons[mndx])) mcham = mndx;
|
||||
if (mndx >= LOW_PM && is_shapeshifter(&mons[mndx])) mcham = mndx;
|
||||
return mcham;
|
||||
}
|
||||
|
||||
@@ -529,7 +529,7 @@ mcalcdistress()
|
||||
mon_regen(mtmp, FALSE);
|
||||
|
||||
/* possibly polymorph shapechangers and lycanthropes */
|
||||
if (mtmp->cham != CHAM_ORDINARY) {
|
||||
if (mtmp->cham >= LOW_PM) {
|
||||
if (is_vampshifter(mtmp) || mtmp->data->mlet == S_VAMPIRE)
|
||||
decide_to_shapeshift(mtmp,0);
|
||||
else if (!rn2(6))
|
||||
@@ -1470,7 +1470,7 @@ register struct monst *mtmp;
|
||||
int mndx = mtmp->cham;
|
||||
int x = mtmp->mx, y = mtmp->my;
|
||||
/* this only happens if shapeshifted */
|
||||
if (mndx != CHAM_ORDINARY && mndx != monsndx(mtmp->data)) {
|
||||
if (mndx >= LOW_PM && mndx != monsndx(mtmp->data)) {
|
||||
char buf[BUFSZ];
|
||||
boolean in_door = amorphous(mtmp->data) &&
|
||||
closed_door(mtmp->mx,mtmp->my);
|
||||
@@ -1502,7 +1502,7 @@ register struct monst *mtmp;
|
||||
}
|
||||
newcham(mtmp, &mons[mndx], FALSE, FALSE);
|
||||
if (mtmp->data == &mons[mndx])
|
||||
mtmp->cham = CHAM_ORDINARY;
|
||||
mtmp->cham = NON_PM;
|
||||
else
|
||||
mtmp->cham = mndx;
|
||||
if ((!Blind && canseemon(mtmp)) || sensemon(mtmp))
|
||||
@@ -1520,9 +1520,9 @@ register struct monst *mtmp;
|
||||
|
||||
mptr = mtmp->data; /* save this for m_detach() */
|
||||
/* restore chameleon, lycanthropes to true form at death */
|
||||
if (mtmp->cham != CHAM_ORDINARY) {
|
||||
if (mtmp->cham >= LOW_PM) {
|
||||
set_mon_data(mtmp, &mons[mtmp->cham], -1);
|
||||
mtmp->cham = CHAM_ORDINARY;
|
||||
mtmp->cham = NON_PM;
|
||||
}
|
||||
else if (mtmp->data == &mons[PM_WEREJACKAL])
|
||||
set_mon_data(mtmp, &mons[PM_HUMAN_WEREJACKAL], -1);
|
||||
@@ -2231,10 +2231,10 @@ rescham()
|
||||
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
|
||||
if (DEADMONSTER(mtmp)) continue;
|
||||
mcham = (int) mtmp->cham;
|
||||
if (mcham != CHAM_ORDINARY) {
|
||||
if (mcham >= LOW_PM) {
|
||||
(void) newcham(mtmp, &mons[mcham],
|
||||
FALSE, FALSE);
|
||||
mtmp->cham = CHAM_ORDINARY;
|
||||
mtmp->cham = NON_PM;
|
||||
}
|
||||
if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN)
|
||||
new_were(mtmp);
|
||||
@@ -2275,13 +2275,13 @@ struct monst *mon;
|
||||
|
||||
if (Protection_from_shape_changers) {
|
||||
mcham = (int) mon->cham;
|
||||
if (mcham != CHAM_ORDINARY) {
|
||||
mon->cham = CHAM_ORDINARY;
|
||||
if (mcham >= LOW_PM) {
|
||||
mon->cham = NON_PM;
|
||||
(void) newcham(mon, &mons[mcham], FALSE, FALSE);
|
||||
} else if (is_were(mon->data) && !is_human(mon->data)) {
|
||||
new_were(mon);
|
||||
}
|
||||
} else if (mon->cham == CHAM_ORDINARY) {
|
||||
} else if (mon->cham == NON_PM) {
|
||||
mon->cham = pm_to_cham(monsndx(mon->data));
|
||||
}
|
||||
}
|
||||
@@ -2291,7 +2291,7 @@ STATIC_OVL boolean
|
||||
restrap(mtmp)
|
||||
register struct monst *mtmp;
|
||||
{
|
||||
if((mtmp->cham != CHAM_ORDINARY) || mtmp->mcan || mtmp->m_ap_type ||
|
||||
if((mtmp->cham >= LOW_PM) || mtmp->mcan || mtmp->m_ap_type ||
|
||||
cansee(mtmp->mx, mtmp->my) || rn2(3) || (mtmp == u.ustuck) ||
|
||||
(sensemon(mtmp) && distu(mtmp->mx, mtmp->my) <= 2))
|
||||
return(FALSE);
|
||||
@@ -2387,10 +2387,11 @@ int shiftflags;
|
||||
* If we're shifted and getting low on hp, maybe shift back.
|
||||
* If we're not already shifted and in good health, maybe shift.
|
||||
*/
|
||||
if ((mon->mhp <= mon->mhpmax / 6) && rn2(4))
|
||||
if ((mon->mhp <= mon->mhpmax / 6) &&
|
||||
rn2(4) && (mon->cham >= LOW_PM))
|
||||
(void) newcham(mon, &mons[mon->cham], FALSE, msg);
|
||||
} else if (mon->data->mlet == S_VAMPIRE && mon->cham == CHAM_ORDINARY
|
||||
&& !rn2(6) && (mon->mhp > mon->mhpmax - ((mon->mhpmax / 10) + 1))) {
|
||||
} else if (mon->data->mlet == S_VAMPIRE && mon->cham == NON_PM &&
|
||||
!rn2(6) && (mon->mhp > mon->mhpmax - ((mon->mhpmax / 10) + 1))) {
|
||||
(void) newcham(mon, (struct permonst *)0, FALSE, msg);
|
||||
}
|
||||
}
|
||||
@@ -2428,7 +2429,7 @@ struct monst *mon;
|
||||
}
|
||||
mndx = !rn2(4) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT;
|
||||
break;
|
||||
case CHAM_ORDINARY:
|
||||
case NON_PM: /* ordinary */
|
||||
{
|
||||
struct obj *m_armr = which_armor(mon, W_ARM);
|
||||
|
||||
@@ -2749,12 +2750,9 @@ void
|
||||
kill_genocided_monsters()
|
||||
{
|
||||
struct monst *mtmp, *mtmp2;
|
||||
boolean kill_cham[NUMMONS];
|
||||
boolean kill_cham;
|
||||
int mndx;
|
||||
|
||||
kill_cham[CHAM_ORDINARY] = FALSE; /* (this is mndx==0) */
|
||||
for (mndx = LOW_PM; mndx < NUMMONS; mndx++)
|
||||
kill_cham[mndx] = (mvitals[mndx].mvflags & G_GENOD) != 0;
|
||||
/*
|
||||
* Called during genocide, and again upon level change. The latter
|
||||
* catches up with any migrating monsters as they finally arrive at
|
||||
@@ -2766,15 +2764,17 @@ kill_genocided_monsters()
|
||||
* 2) otherwise, force every chameleon which is imitating
|
||||
* any genocided species to take on a new form.
|
||||
*/
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp2) {
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp2, kill_cham = FALSE) {
|
||||
mtmp2 = mtmp->nmon;
|
||||
if (DEADMONSTER(mtmp)) continue;
|
||||
mndx = monsndx(mtmp->data);
|
||||
if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham[mtmp->cham]) {
|
||||
if ((mtmp->cham != CHAM_ORDINARY) && !kill_cham[mtmp->cham])
|
||||
(void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
|
||||
if (mtmp->cham >= LOW_PM && (mvitals[mtmp->cham].mvflags & G_GENOD))
|
||||
kill_cham = TRUE;
|
||||
if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham) {
|
||||
if (mtmp->cham >= LOW_PM && !kill_cham)
|
||||
(void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
|
||||
else
|
||||
mondead(mtmp);
|
||||
mondead(mtmp);
|
||||
}
|
||||
if (mtmp->minvent) kill_eggs(mtmp->minvent);
|
||||
}
|
||||
|
||||
@@ -1506,11 +1506,11 @@ struct monst *mon;
|
||||
struct permonst *ptr;
|
||||
{
|
||||
int reslt = 0;
|
||||
if (mon->cham != CHAM_ORDINARY) {
|
||||
if (mon->cham >= LOW_PM) {
|
||||
if (ptr == &mons[mon->cham])
|
||||
mon->cham = CHAM_ORDINARY;
|
||||
mon->cham = NON_PM;
|
||||
reslt = newcham(mon, ptr, FALSE, FALSE);
|
||||
} else if (mon->cham == CHAM_ORDINARY && ptr != mon->data) {
|
||||
} else if (mon->cham == NON_PM && ptr != mon->data) {
|
||||
mon->cham = monsndx(mon->data);
|
||||
reslt = newcham(mon, ptr, FALSE, FALSE);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,6 @@ NEARDATA struct permonst mons[] = {
|
||||
/*
|
||||
* ants
|
||||
*/
|
||||
/* Never use M2_SHAPESHIFTER for mons[0] as long as CHAM_ORDINARY==0 */
|
||||
MON("giant ant", S_ANT,
|
||||
LVL(2, 18, 3, 0, 0), (G_GENO|G_SGROUP|3),
|
||||
A(ATTK(AT_BITE, AD_PHYS, 1, 4),
|
||||
|
||||
@@ -1586,7 +1586,7 @@ struct monst *mtmp;
|
||||
return FALSE;
|
||||
|
||||
if (!stuck && !immobile &&
|
||||
(mtmp->cham == CHAM_ORDINARY) && monstr[monsndx(mdat)] < 6) {
|
||||
(mtmp->cham == NON_PM) && monstr[monsndx(mdat)] < 6) {
|
||||
boolean ignore_boulders = (verysmall(mdat) ||
|
||||
throws_rocks(mdat) ||
|
||||
passes_walls(mdat));
|
||||
@@ -1657,14 +1657,14 @@ struct monst *mtmp;
|
||||
}
|
||||
nomore(MUSE_WAN_POLYMORPH);
|
||||
if(obj->otyp == WAN_POLYMORPH && obj->spe > 0
|
||||
&& (mtmp->cham == CHAM_ORDINARY)
|
||||
&& (mtmp->cham == NON_PM)
|
||||
&& monstr[monsndx(mdat)] < 6) {
|
||||
m.misc = obj;
|
||||
m.has_misc = MUSE_WAN_POLYMORPH;
|
||||
}
|
||||
nomore(MUSE_POT_POLYMORPH);
|
||||
if(obj->otyp == POT_POLYMORPH
|
||||
&& (mtmp->cham == CHAM_ORDINARY)
|
||||
&& (mtmp->cham == NON_PM)
|
||||
&& monstr[monsndx(mdat)] < 6) {
|
||||
m.misc = obj;
|
||||
m.has_misc = MUSE_POT_POLYMORPH;
|
||||
|
||||
@@ -317,7 +317,7 @@ register struct monst *mtmp;
|
||||
}
|
||||
else if (mtmp->mpeaceful) Strcat(info, ", peaceful");
|
||||
if (mtmp->meating) Strcat(info, ", eating");
|
||||
if (mtmp->meating && (mtmp->cham == CHAM_ORDINARY) &&
|
||||
if (mtmp->meating && (mtmp->cham == NON_PM) &&
|
||||
mtmp->mappearance && mtmp->m_ap_type) {
|
||||
Sprintf(eos(info), ", mimicing %s",
|
||||
(mtmp->m_ap_type == M_AP_FURNITURE) ?
|
||||
|
||||
@@ -2068,7 +2068,7 @@ create_particular()
|
||||
}
|
||||
if (mtmp) {
|
||||
madeany = TRUE;
|
||||
if (mtmp->cham != CHAM_ORDINARY && firstchoice != NON_PM)
|
||||
if (mtmp->cham >= LOW_PM && firstchoice != NON_PM)
|
||||
(void)newcham(mtmp, &mons[firstchoice], FALSE, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,8 +449,8 @@ int *fail_reason;
|
||||
mon = makemon(&mons[PM_DOPPELGANGER], x, y,
|
||||
NO_MINVENT | MM_NOCOUNTBIRTH | MM_ADJACENTOK);
|
||||
/* if hero has protection from shape changers, cham field will
|
||||
be CHAM_ORDINARY; otherwise, set form to match the statue */
|
||||
if (mon && mon->cham != CHAM_ORDINARY)
|
||||
be NON_PM; otherwise, set form to match the statue */
|
||||
if (mon && mon->cham >= LOW_PM)
|
||||
(void) newcham(mon, mptr, FALSE, FALSE);
|
||||
} else
|
||||
mon = makemon(mptr, x, y, (cause == ANIMATE_SPELL) ?
|
||||
|
||||
@@ -229,7 +229,7 @@ struct obj *otmp;
|
||||
/* natural shapechangers aren't affected by system shock
|
||||
(unless protection from shapechangers is interfering
|
||||
with their metabolism...) */
|
||||
if (mtmp->cham == CHAM_ORDINARY && !rn2(25)) {
|
||||
if (mtmp->cham == NON_PM && !rn2(25)) {
|
||||
if (canseemon(mtmp)) {
|
||||
pline("%s shudders!", Monnam(mtmp));
|
||||
learn_it = TRUE;
|
||||
|
||||
Reference in New Issue
Block a user