intelligent pets vs cannibalism (trunk only)
Implement a user suggestion that tame humanoids should avoid eating corpses of their own species. Prevent them--except for kobolds, orcs, and ogres--from doing so unless starving. Arbitrary: tame elves won't eat other elves even when starving. A polymorphed character will incur the effects of cannibalism when eating either his/her underlying race _or_ the current one (player orcs and cavemen aren't affected though).
This commit is contained in:
@@ -128,6 +128,7 @@ container cknown flag for container content awareness
|
||||
plname is stored in the save file on all platforms now
|
||||
introduce support for negation of role, race, align, gender values to eliminate
|
||||
them from random selection and the pick list of startup choices
|
||||
some intelligent pets will avoid cannibalism
|
||||
|
||||
|
||||
Platform- and/or Interface-Specific New Features
|
||||
|
||||
@@ -1221,6 +1221,7 @@ E int FDECL(num_horns, (struct permonst *));
|
||||
E struct attack *FDECL(dmgtype_fromattack, (struct permonst *,int,int));
|
||||
E boolean FDECL(dmgtype, (struct permonst *,int));
|
||||
E int FDECL(max_passive_dmg, (struct monst *,struct monst *));
|
||||
E boolean FDECL(same_race, (struct permonst *,struct permonst *));
|
||||
E int FDECL(monsndx, (struct permonst *));
|
||||
E int FDECL(name_to_mon, (const char *));
|
||||
E int FDECL(gender, (struct monst *));
|
||||
|
||||
43
src/dog.c
43
src/dog.c
@@ -1,4 +1,4 @@
|
||||
/* SCCS Id: @(#)dog.c 3.5 2004/11/26 */
|
||||
/* SCCS Id: @(#)dog.c 3.5 2005/01/29 */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -655,10 +655,9 @@ dogfood(mon,obj)
|
||||
struct monst *mon;
|
||||
register struct obj *obj;
|
||||
{
|
||||
boolean carni = carnivorous(mon->data);
|
||||
boolean herbi = herbivorous(mon->data);
|
||||
struct permonst *fptr = &mons[obj->corpsenm];
|
||||
boolean starving;
|
||||
struct permonst *mptr = mon->data, *fptr = &mons[obj->corpsenm];
|
||||
boolean carni = carnivorous(mptr), herbi = herbivorous(mptr),
|
||||
starving;
|
||||
|
||||
if (is_quest_artifact(obj) || obj_resists(obj, 0, 95))
|
||||
return (obj->cursed ? TABU : APPORT);
|
||||
@@ -666,12 +665,12 @@ register struct obj *obj;
|
||||
switch(obj->oclass) {
|
||||
case FOOD_CLASS:
|
||||
if (obj->otyp == CORPSE &&
|
||||
((touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon))
|
||||
((touch_petrifies(fptr) && !resists_ston(mon))
|
||||
|| is_rider(fptr)))
|
||||
return TABU;
|
||||
|
||||
/* Ghouls only eat old corpses... yum! */
|
||||
if (mon->data == &mons[PM_GHOUL])
|
||||
if (mptr == &mons[PM_GHOUL])
|
||||
return (obj->otyp == CORPSE &&
|
||||
peek_at_iced_corpse_age(obj) + 50L <= monstermoves) ?
|
||||
DOGFOOD : TABU;
|
||||
@@ -691,31 +690,38 @@ register struct obj *obj;
|
||||
case HUGE_CHUNK_OF_MEAT:
|
||||
return (carni ? DOGFOOD : MANFOOD);
|
||||
case EGG:
|
||||
if (touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon))
|
||||
if (touch_petrifies(fptr) && !resists_ston(mon))
|
||||
return POISON;
|
||||
return (carni ? CADAVER : MANFOOD);
|
||||
case CORPSE:
|
||||
if ((peek_at_iced_corpse_age(obj) + 50L <= monstermoves
|
||||
&& obj->corpsenm != PM_LIZARD
|
||||
&& obj->corpsenm != PM_LICHEN
|
||||
&& mon->data->mlet != S_FUNGUS) ||
|
||||
(acidic(&mons[obj->corpsenm]) && !resists_acid(mon)) ||
|
||||
(poisonous(&mons[obj->corpsenm]) &&
|
||||
!resists_poison(mon)))
|
||||
&& mptr->mlet != S_FUNGUS) ||
|
||||
(acidic(fptr) && !resists_acid(mon)) ||
|
||||
(poisonous(fptr) && !resists_poison(mon)))
|
||||
return POISON;
|
||||
else if (vegan(fptr))
|
||||
return (herbi ? CADAVER : MANFOOD);
|
||||
else return (carni ? CADAVER : MANFOOD);
|
||||
/* most humanoids will avoid cannibalism unless starving;
|
||||
arbitrary: elves won't eat other elves even then */
|
||||
else if (humanoid(mptr) && same_race(mptr, fptr) &&
|
||||
(!is_undead(mptr) && fptr->mlet != S_KOBOLD &&
|
||||
fptr->mlet != S_ORC && fptr->mlet != S_OGRE))
|
||||
return ((starving && carni && !is_elf(mptr)) ?
|
||||
ACCFOOD : TABU);
|
||||
else
|
||||
return (carni ? CADAVER : MANFOOD);
|
||||
case CLOVE_OF_GARLIC:
|
||||
return ((is_undead(mon->data) || is_vampshifter(mon)) ? TABU :
|
||||
return ((is_undead(mptr) || is_vampshifter(mon)) ? TABU :
|
||||
((herbi || starving) ? ACCFOOD : MANFOOD));
|
||||
case TIN:
|
||||
return (metallivorous(mon->data) ? ACCFOOD : MANFOOD);
|
||||
return (metallivorous(mptr) ? ACCFOOD : MANFOOD);
|
||||
case APPLE:
|
||||
case CARROT:
|
||||
return (herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD);
|
||||
case BANANA:
|
||||
return ((mon->data->mlet == S_YETI) ? DOGFOOD :
|
||||
return ((mptr->mlet == S_YETI) ? DOGFOOD :
|
||||
((herbi || starving) ? ACCFOOD : MANFOOD));
|
||||
default:
|
||||
if (starving) return ACCFOOD;
|
||||
@@ -730,9 +736,10 @@ register struct obj *obj;
|
||||
if (mon_hates_silver(mon) &&
|
||||
objects[obj->otyp].oc_material == SILVER)
|
||||
return(TABU);
|
||||
if (mon->data == &mons[PM_GELATINOUS_CUBE] && is_organic(obj))
|
||||
if (mptr == &mons[PM_GELATINOUS_CUBE] && is_organic(obj))
|
||||
return(ACCFOOD);
|
||||
if (metallivorous(mon->data) && is_metallic(obj) && (is_rustprone(obj) || mon->data != &mons[PM_RUST_MONSTER])) {
|
||||
if (metallivorous(mptr) && is_metallic(obj) &&
|
||||
(is_rustprone(obj) || mptr != &mons[PM_RUST_MONSTER])) {
|
||||
/* Non-rustproofed ferrous based metals are preferred. */
|
||||
return((is_rustprone(obj) && !obj->oerodeproof) ? DOGFOOD :
|
||||
ACCFOOD);
|
||||
|
||||
15
src/eat.c
15
src/eat.c
@@ -1,4 +1,4 @@
|
||||
/* SCCS Id: @(#)eat.c 3.5 2004/11/17 */
|
||||
/* SCCS Id: @(#)eat.c 3.5 2005/01/29 */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -415,14 +415,23 @@ boolean message;
|
||||
context.victual.fullwarn = context.victual.eating = context.victual.doreset = FALSE;
|
||||
}
|
||||
|
||||
/* eating a corpse or egg of one's own species is usually naughty */
|
||||
STATIC_OVL boolean
|
||||
maybe_cannibal(pm, allowmsg)
|
||||
int pm;
|
||||
boolean allowmsg;
|
||||
{
|
||||
if (!CANNIBAL_ALLOWED() && your_race(&mons[pm])) {
|
||||
struct permonst *fptr = &mons[pm]; /* food type */
|
||||
|
||||
if (!CANNIBAL_ALLOWED() &&
|
||||
/* non-cannibalistic heroes shouldn't eat own species ever
|
||||
and also shouldn't eat current species when polymorphed
|
||||
(even if having the form of something which doesn't care
|
||||
about cannibalism--hero's innate traits aren't altered) */
|
||||
(your_race(fptr) ||
|
||||
(Upolyd && same_race(youmonst.data, fptr)))) {
|
||||
if (allowmsg) {
|
||||
if (Upolyd)
|
||||
if (Upolyd && your_race(fptr))
|
||||
You("have a bad feeling deep inside.");
|
||||
You("cannibal! You will regret this!");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* SCCS Id: @(#)mondata.c 3.5 2004/10/20 */
|
||||
/* SCCS Id: @(#)mondata.c 3.5 2005/01/29 */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -252,14 +252,14 @@ struct monst *mon;
|
||||
return (is_vampshifter(mon) || hates_silver(mon->data));
|
||||
}
|
||||
|
||||
/* TRUE if monster is especially affected by silver weapons */
|
||||
boolean
|
||||
hates_silver(ptr)
|
||||
register struct permonst *ptr;
|
||||
/* returns TRUE if monster is especially affected by silver weapons */
|
||||
{
|
||||
return((boolean)(is_were(ptr) || ptr->mlet==S_VAMPIRE || is_demon(ptr) ||
|
||||
ptr == &mons[PM_SHADE] ||
|
||||
(ptr->mlet==S_IMP && ptr != &mons[PM_TENGU])));
|
||||
return (boolean)(is_were(ptr) || ptr->mlet == S_VAMPIRE ||
|
||||
is_demon(ptr) || ptr == &mons[PM_SHADE] ||
|
||||
(ptr->mlet == S_IMP && ptr != &mons[PM_TENGU]));
|
||||
}
|
||||
|
||||
/* true iff the type of monster pass through iron bars */
|
||||
@@ -392,6 +392,77 @@ max_passive_dmg(mdef, magr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* determine whether two monster types are from the same species */
|
||||
boolean
|
||||
same_race(pm1, pm2)
|
||||
struct permonst *pm1, *pm2;
|
||||
{
|
||||
char let1 = pm1->mlet, let2 = pm2->mlet;
|
||||
|
||||
if (pm1 == pm2) return TRUE; /* exact match */
|
||||
/* player races have their own predicates */
|
||||
if (is_human(pm1)) return is_human(pm2);
|
||||
if (is_elf(pm1)) return is_elf(pm2);
|
||||
if (is_dwarf(pm1)) return is_dwarf(pm2);
|
||||
if (is_gnome(pm1)) return is_gnome(pm2);
|
||||
if (is_orc(pm1)) return is_orc(pm2);
|
||||
/* other creatures are less precise */
|
||||
if (is_giant(pm1)) return is_giant(pm2); /* open to quibbling here */
|
||||
if (is_golem(pm1)) return is_golem(pm2); /* even moreso... */
|
||||
if (is_mind_flayer(pm1)) return is_mind_flayer(pm2);
|
||||
if (let1 == S_KOBOLD ||
|
||||
pm1 == &mons[PM_KOBOLD_ZOMBIE] ||
|
||||
pm1 == &mons[PM_KOBOLD_MUMMY])
|
||||
return (let2 == S_KOBOLD ||
|
||||
pm2 == &mons[PM_KOBOLD_ZOMBIE] ||
|
||||
pm2 == &mons[PM_KOBOLD_MUMMY]);
|
||||
if (let1 == S_OGRE) return (let2 == S_OGRE);
|
||||
if (let1 == S_NYMPH) return (let2 == S_NYMPH);
|
||||
if (let1 == S_CENTAUR) return (let2 == S_CENTAUR);
|
||||
if (is_unicorn(pm1)) return is_unicorn(pm2);
|
||||
if (let1 == S_DRAGON) return (let2 == S_DRAGON);
|
||||
if (let1 == S_NAGA) return (let2 == S_NAGA);
|
||||
/* other critters get steadily messier */
|
||||
if (is_rider(pm1)) return is_rider(pm2); /* debatable */
|
||||
if (is_minion(pm1)) return is_minion(pm2); /* [needs work?] */
|
||||
/* tengu don't match imps (first test handled case of both being tengu) */
|
||||
if (pm1 == &mons[PM_TENGU] || pm2 == &mons[PM_TENGU]) return FALSE;
|
||||
if (let1 == S_IMP) return (let2 == S_IMP);
|
||||
/* and minor demons (imps) don't match major demons */
|
||||
else if (let2 == S_IMP) return FALSE;
|
||||
if (is_demon(pm1)) return is_demon(pm2);
|
||||
if (is_undead(pm1)) {
|
||||
if (let1 == S_ZOMBIE) return (let2 == S_ZOMBIE);
|
||||
if (let1 == S_MUMMY) return (let2 == S_MUMMY);
|
||||
if (let1 == S_VAMPIRE) return (let2 == S_VAMPIRE);
|
||||
if (let1 == S_LICH) return (let2 == S_LICH);
|
||||
if (let1 == S_WRAITH) return (let2 == S_WRAITH);
|
||||
if (let1 == S_GHOST) return (let2 == S_GHOST);
|
||||
} else if (is_undead(pm2)) return FALSE;
|
||||
/* check for monsters--mainly animals--which grow into more mature forms */
|
||||
if (let1 == let2) {
|
||||
int m1 = monsndx(pm1), m2 = monsndx(pm2), prv, nxt;
|
||||
|
||||
/* we know m1 != m2 (very first check above); test all smaller
|
||||
forms of m1 against m2, then all larger ones; don't need to
|
||||
make the corresponding tests for variants of m2 against m1 */
|
||||
for (prv = m1, nxt = big_to_little(m1); nxt != prv;
|
||||
prv = nxt, nxt = big_to_little(nxt)) if (nxt == m2) return TRUE;
|
||||
for (prv = m1, nxt = little_to_big(m1); nxt != prv;
|
||||
prv = nxt, nxt = little_to_big(nxt)) if (nxt == m2) return TRUE;
|
||||
}
|
||||
/* not caught by little/big handling */
|
||||
if (pm1 == &mons[PM_GARGOYLE] || pm1 == &mons[PM_WINGED_GARGOYLE])
|
||||
return (pm2 == &mons[PM_GARGOYLE] || pm2 == &mons[PM_WINGED_GARGOYLE]);
|
||||
if (pm1 == &mons[PM_KILLER_BEE] || pm1 == &mons[PM_QUEEN_BEE])
|
||||
return (pm2 == &mons[PM_KILLER_BEE] || pm2 == &mons[PM_QUEEN_BEE]);
|
||||
if (is_longworm(pm1)) return is_longworm(pm2); /* handles tail */
|
||||
/* [currently there's no reason to bother matching up
|
||||
assorted bugs and blobs with their closest variants] */
|
||||
/* didn't match */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
monsndx(ptr) /* return an index into the mons array */
|
||||
struct permonst *ptr;
|
||||
|
||||
Reference in New Issue
Block a user