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:
Pasi Kallinen
2021-05-23 19:02:38 +03:00
parent 20cbadcf85
commit 8d2407f1f2
8 changed files with 149 additions and 50 deletions

View File

@@ -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
View File

@@ -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)
{

View File

@@ -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)
{