Monsters can gain resistances by eating corpses
This is based on both the EvilHack implementation by k21971 <keith.simpson1971@gmail.com>, and xNetHack implementation by copperwater <aosdict@gmail.com>.
This commit is contained in:
@@ -1010,6 +1010,7 @@ using 'f' while quiver is empty and 'autoquiver' is Off when wielding a
|
||||
3.6's tribute: add one new passage to Sourcery, three to Small Gods, one to
|
||||
Lords and Ladies, two to Soul Music, three to Interesting Times
|
||||
monsters can see and remember hero resistances
|
||||
monsters can gain resistances by eating corpses
|
||||
|
||||
|
||||
Platform- and/or Interface-Specific New Features
|
||||
|
||||
@@ -655,6 +655,7 @@ extern void morehungry(int);
|
||||
extern void lesshungry(int);
|
||||
extern boolean is_fainted(void);
|
||||
extern void reset_faint(void);
|
||||
extern int corpse_intrinsic(struct permonst *);
|
||||
extern void violated_vegetarian(void);
|
||||
extern void newuhs(boolean);
|
||||
extern struct obj *floorfood(const char *, int);
|
||||
@@ -665,6 +666,7 @@ extern void food_substitution(struct obj *, struct obj *);
|
||||
extern void eating_conducts(struct permonst *);
|
||||
extern int eat_brains(struct monst *, struct monst *, boolean, int *);
|
||||
extern void fix_petrification(void);
|
||||
extern boolean should_givit(int, struct permonst *);
|
||||
extern void consume_oeaten(struct obj *, int);
|
||||
extern boolean maybe_finished_meal(boolean);
|
||||
extern void set_tin_variety(struct obj *, int);
|
||||
@@ -1392,6 +1394,7 @@ extern int movemon(void);
|
||||
extern int meatmetal(struct monst *);
|
||||
extern int meatobj(struct monst *);
|
||||
extern int meatcorpse(struct monst *);
|
||||
extern void mon_givit(struct monst *, struct permonst *);
|
||||
extern void mpickgold(struct monst *);
|
||||
extern boolean mpickstuff(struct monst *, const char *);
|
||||
extern int curr_mon_load(struct monst *);
|
||||
|
||||
@@ -10,22 +10,24 @@
|
||||
|
||||
#define pm_resistance(ptr, typ) (((ptr)->mresists & (typ)) != 0)
|
||||
|
||||
#define mon_resistancebits(mon) \
|
||||
((mon)->data->mresists | (mon)->mextrinsics | (mon)->mintrinsics)
|
||||
#define resists_fire(mon) \
|
||||
((((mon)->data->mresists | (mon)->mextrinsics) & MR_FIRE) != 0)
|
||||
((mon_resistancebits(mon) & MR_FIRE) != 0)
|
||||
#define resists_cold(mon) \
|
||||
((((mon)->data->mresists | (mon)->mextrinsics) & MR_COLD) != 0)
|
||||
((mon_resistancebits(mon) & MR_COLD) != 0)
|
||||
#define resists_sleep(mon) \
|
||||
((((mon)->data->mresists | (mon)->mextrinsics) & MR_SLEEP) != 0)
|
||||
((mon_resistancebits(mon) & MR_SLEEP) != 0)
|
||||
#define resists_disint(mon) \
|
||||
((((mon)->data->mresists | (mon)->mextrinsics) & MR_DISINT) != 0)
|
||||
((mon_resistancebits(mon) & MR_DISINT) != 0)
|
||||
#define resists_elec(mon) \
|
||||
((((mon)->data->mresists | (mon)->mextrinsics) & MR_ELEC) != 0)
|
||||
((mon_resistancebits(mon) & MR_ELEC) != 0)
|
||||
#define resists_poison(mon) \
|
||||
((((mon)->data->mresists | (mon)->mextrinsics) & MR_POISON) != 0)
|
||||
((mon_resistancebits(mon) & MR_POISON) != 0)
|
||||
#define resists_acid(mon) \
|
||||
((((mon)->data->mresists | (mon)->mextrinsics) & MR_ACID) != 0)
|
||||
((mon_resistancebits(mon) & MR_ACID) != 0)
|
||||
#define resists_ston(mon) \
|
||||
((((mon)->data->mresists | (mon)->mextrinsics) & MR_STONE) != 0)
|
||||
((mon_resistancebits(mon) & MR_STONE) != 0)
|
||||
|
||||
#define immune_poisongas(ptr) ((ptr) == &mons[PM_HEZROU])
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ struct monst {
|
||||
uchar m_ap_type; /* what mappearance is describing, m_ap_types */
|
||||
|
||||
schar mtame; /* level of tameness, implies peaceful */
|
||||
unsigned short mintrinsics; /* low 8 correspond to mresists */
|
||||
unsigned short mextrinsics; /* low 8 correspond to mresists */
|
||||
unsigned long seen_resistance; /* M_SEEN_x; saw you resist an effect */
|
||||
int mspec_used; /* monster's special ability attack timeout */
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Incrementing EDITLEVEL can be used to force invalidation of old bones
|
||||
* and save files.
|
||||
*/
|
||||
#define EDITLEVEL 34
|
||||
#define EDITLEVEL 35
|
||||
|
||||
/*
|
||||
* Development status possibilities.
|
||||
|
||||
@@ -204,7 +204,7 @@ dog_eat(struct monst *mtmp,
|
||||
{
|
||||
register struct edog *edog = EDOG(mtmp);
|
||||
boolean poly, grow, heal, eyes, slimer, deadmimic;
|
||||
int nutrit, res;
|
||||
int nutrit, res, corpsenm;
|
||||
long oprice;
|
||||
char objnambuf[BUFSZ];
|
||||
|
||||
@@ -221,6 +221,7 @@ dog_eat(struct monst *mtmp,
|
||||
grow = mlevelgain(obj);
|
||||
heal = mhealup(obj);
|
||||
eyes = (obj->otyp == CARROT);
|
||||
corpsenm = (obj->otyp == CORPSE ? obj->corpsenm : NON_PM);
|
||||
|
||||
if (devour) {
|
||||
if (mtmp->meating > 1)
|
||||
@@ -347,6 +348,8 @@ dog_eat(struct monst *mtmp,
|
||||
mcureblindness(mtmp, canseemon(mtmp));
|
||||
if (deadmimic)
|
||||
quickmimic(mtmp);
|
||||
if (corpsenm != NON_PM)
|
||||
mon_givit(mtmp, &mons[corpsenm]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
104
src/eat.c
104
src/eat.c
@@ -802,15 +802,15 @@ intrinsic_possible(int type, register struct permonst *ptr)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* givit() tries to give you an intrinsic based on the monster's level
|
||||
* and what type of intrinsic it is trying to give you.
|
||||
/* The "do we or do we not give the intrinsic" logic from givit(), extracted
|
||||
* into its own function. Depends on the monster's level and the type of
|
||||
* intrinsic it is trying to give you.
|
||||
*/
|
||||
static void
|
||||
givit(int type, register struct permonst *ptr)
|
||||
boolean
|
||||
should_givit(int type, struct permonst *ptr)
|
||||
{
|
||||
register int chance;
|
||||
int chance;
|
||||
|
||||
debugpline1("Attempting to give intrinsic %d", type);
|
||||
/* some intrinsics are easier to get than others */
|
||||
switch (type) {
|
||||
case POISON_RES:
|
||||
@@ -834,8 +834,19 @@ givit(int type, register struct permonst *ptr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr->mlevel <= rn2(chance))
|
||||
return; /* failed die roll */
|
||||
return (ptr->mlevel > rn2(chance));
|
||||
}
|
||||
|
||||
/* givit() tries to give you an intrinsic based on the monster's level
|
||||
* and what type of intrinsic it is trying to give you.
|
||||
*/
|
||||
static void
|
||||
givit(int type, register struct permonst *ptr)
|
||||
{
|
||||
debugpline1("Attempting to give intrinsic %d", type);
|
||||
|
||||
if (!should_givit(type, ptr))
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
case FIRE_RES:
|
||||
@@ -1094,8 +1105,6 @@ cpostfx(int pm)
|
||||
/* possibly convey an intrinsic */
|
||||
if (check_intrinsics) {
|
||||
struct permonst *ptr = &mons[pm];
|
||||
boolean conveys_STR = is_giant(ptr);
|
||||
int i, count;
|
||||
|
||||
if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU)
|
||||
|| pm == PM_VIOLET_FUNGUS) {
|
||||
@@ -1108,36 +1117,8 @@ cpostfx(int pm)
|
||||
if (attacktype(ptr, AT_MAGC) || pm == PM_NEWT)
|
||||
eye_of_newt_buzz();
|
||||
|
||||
/* Check the monster for all of the intrinsics. If this
|
||||
* monster can give more than one, pick one to try to give
|
||||
* from among all it can give.
|
||||
*
|
||||
* Strength from giants is now treated like an intrinsic
|
||||
* rather than being given unconditionally.
|
||||
*/
|
||||
count = 0; /* number of possible intrinsics */
|
||||
tmp = 0; /* which one we will try to give */
|
||||
if (conveys_STR) {
|
||||
count = 1;
|
||||
tmp = -1; /* use -1 as fake prop index for STR */
|
||||
debugpline1("\"Intrinsic\" strength, %d", tmp);
|
||||
}
|
||||
for (i = 1; i <= LAST_PROP; i++) {
|
||||
if (!intrinsic_possible(i, ptr))
|
||||
continue;
|
||||
++count;
|
||||
/* a 1 in count chance of replacing the old choice
|
||||
with this one, and a count-1 in count chance
|
||||
of keeping the old choice (note that 1 in 1 and
|
||||
0 in 1 are what we want for the first candidate) */
|
||||
if (!rn2(count)) {
|
||||
debugpline2("Intrinsic %d replacing %d", i, tmp);
|
||||
tmp = i;
|
||||
}
|
||||
}
|
||||
/* if strength is the only candidate, give it 50% chance */
|
||||
if (conveys_STR && count == 1 && !rn2(2))
|
||||
tmp = 0;
|
||||
tmp = corpse_intrinsic(ptr);
|
||||
|
||||
/* if something was chosen, give it now (givit() might fail) */
|
||||
if (tmp == -1)
|
||||
gainstr((struct obj *) 0, 0, TRUE);
|
||||
@@ -1154,6 +1135,49 @@ cpostfx(int pm)
|
||||
|
||||
RESTORE_WARNING_FORMAT_NONLITERAL
|
||||
|
||||
/* Choose (one of) the intrinsics granted by a corpse, and return it.
|
||||
* If this corpse gives no intrinsics, return 0.
|
||||
* For the special not-real-prop cases of strength gain from giants
|
||||
* return fake prop value of -1.
|
||||
* Non-deterministic; should only be called once per corpse.
|
||||
*/
|
||||
int
|
||||
corpse_intrinsic(struct permonst *ptr)
|
||||
{
|
||||
/* Check the monster for all of the intrinsics. If this
|
||||
* monster can give more than one, pick one to try to give
|
||||
* from among all it can give.
|
||||
*/
|
||||
boolean conveys_STR = is_giant(ptr);
|
||||
int i;
|
||||
int count = 0; /* number of possible intrinsics */
|
||||
int prop = 0; /* which one we will try to give */
|
||||
|
||||
if (conveys_STR) {
|
||||
count = 1;
|
||||
prop = -1; /* use -1 as fake prop index for STR */
|
||||
debugpline1("\"Intrinsic\" strength, %d", prop);
|
||||
}
|
||||
for (i = 1; i <= LAST_PROP; i++) {
|
||||
if (!intrinsic_possible(i, ptr))
|
||||
continue;
|
||||
++count;
|
||||
/* a 1 in count chance of replacing the old choice
|
||||
with this one, and a count-1 in count chance
|
||||
of keeping the old choice (note that 1 in 1 and
|
||||
0 in 1 are what we want for the first candidate) */
|
||||
if (!rn2(count)) {
|
||||
debugpline2("Intrinsic %d replacing %d", i, prop);
|
||||
prop = i;
|
||||
}
|
||||
}
|
||||
/* if strength is the only candidate, give it 50% chance */
|
||||
if (conveys_STR && count == 1 && !rn2(2))
|
||||
prop = 0;
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
void
|
||||
violated_vegetarian(void)
|
||||
{
|
||||
|
||||
65
src/mon.c
65
src/mon.c
@@ -1247,6 +1247,8 @@ meatobj(struct monst* mtmp) /* for gelatinous cubes */
|
||||
if (otmp->oclass == SCROLL_CLASS
|
||||
&& objdescr_is(otmp, "YUM YUM"))
|
||||
pline("Yum%c", otmp->blessed ? '!' : '.');
|
||||
if (otmp->otyp == CORPSE)
|
||||
mon_givit(mtmp, &mons[otmp->corpsenm]);
|
||||
} else {
|
||||
if (flags.verbose)
|
||||
You_hear("a slurping sound.");
|
||||
@@ -1360,6 +1362,8 @@ meatcorpse(struct monst* mtmp) /* for purple worms and other voracious monsters
|
||||
You_hear("a masticating sound.");
|
||||
}
|
||||
|
||||
mon_givit(mtmp, &mons[otmp->corpsenm]);
|
||||
|
||||
/* [should include quickmimic but can't handle that unless this
|
||||
gets changed to set mtmp->meating] */
|
||||
poly = polyfodder(otmp);
|
||||
@@ -1391,6 +1395,67 @@ meatcorpse(struct monst* mtmp) /* for purple worms and other voracious monsters
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Maybe give an intrinsic to a monster from eating a corpse that confers it. */
|
||||
void
|
||||
mon_givit(struct monst* mtmp, struct permonst* ptr)
|
||||
{
|
||||
int prop = corpse_intrinsic(ptr);
|
||||
boolean vis = canseemon(mtmp);
|
||||
const char* msg = NULL;
|
||||
unsigned short intrinsic = 0; /* MR_* constant */
|
||||
|
||||
if (prop == 0)
|
||||
return; /* no intrinsic from this corpse */
|
||||
|
||||
if (!should_givit(prop, ptr))
|
||||
return; /* failed die roll */
|
||||
|
||||
/* Pets don't have all the fields that the hero does, so they can't get all
|
||||
* the same intrinsics. If it happens to choose strength gain or teleport
|
||||
* control or whatever, ignore it. */
|
||||
switch (prop) {
|
||||
case FIRE_RES:
|
||||
intrinsic = MR_FIRE;
|
||||
msg = "%s shivers slightly.";
|
||||
break;
|
||||
case COLD_RES:
|
||||
intrinsic = MR_COLD;
|
||||
msg = "%s looks quite warm.";
|
||||
break;
|
||||
case SLEEP_RES:
|
||||
intrinsic = MR_SLEEP;
|
||||
msg = "%s looks wide awake.";
|
||||
break;
|
||||
case DISINT_RES:
|
||||
intrinsic = MR_DISINT;
|
||||
msg = "%s looks very firm.";
|
||||
break;
|
||||
case SHOCK_RES:
|
||||
intrinsic = MR_ELEC;
|
||||
msg = "%s crackles with static electricity.";
|
||||
break;
|
||||
case POISON_RES:
|
||||
intrinsic = MR_POISON;
|
||||
msg = "%s looks healthy.";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Don't give message if it already had this property intrinsically, but
|
||||
* still do grant the intrinsic if it only had it from mresists.
|
||||
* Do print the message if it only had this property extrinsically, which is
|
||||
* why mon_resistancebits isn't used here. */
|
||||
if ((mtmp->data->mresists | mtmp->mintrinsics) & intrinsic)
|
||||
msg = (const char *) 0;
|
||||
|
||||
if (intrinsic)
|
||||
mtmp->mintrinsics |= intrinsic;
|
||||
|
||||
if (vis && msg)
|
||||
pline(msg, Monnam(mtmp));
|
||||
}
|
||||
|
||||
void
|
||||
mpickgold(register struct monst* mtmp)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user