Fixes #177 The monst struct has 'mintrinsics' field which attempts to handle both mon->data->mresists and extrinsics supplied by worn armor, but polymorph/shape-change was clobbering the extrinsics side of things. Potentially fixing that by changing newcham() to use set_mon_data(...,1) instead of (...,0) solved that but exposed two other bugs. Intrinsics from the old form carried over to the new form along with extrinsics from worn armor, and update_mon_intrinsics() for armor being destroyed or dropped only worked as intended if the armor->owornmask was cleared beforehand--some places were clearing it after, so extrinsics from worn gear could persist even after that gear was gone. So, fixing the set_mon_data() call in newcham() was a no go. This fixes update_mon_intrinsics() and adopts the suggested code from github pull request #177 to have mon->mintrinsics only handle worn gear instead of trying to overload innate intrinsics with that. This is a superset of that; the flag argument to set_mon_data() is gone and mon->mintrinsics has been renamed mon->mextrinsics. (The routine update_mon_intrinsics() ought to be renamed too, but I didn't do that.)
222 lines
5.8 KiB
C
222 lines
5.8 KiB
C
/* NetHack 3.6 were.c $NHDT-Date: 1550524568 2019/02/18 21:16:08 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.23 $ */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/*-Copyright (c) Robert Patrick Rankin, 2011. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h"
|
|
|
|
void
|
|
were_change(mon)
|
|
register struct monst *mon;
|
|
{
|
|
if (!is_were(mon->data))
|
|
return;
|
|
|
|
if (is_human(mon->data)) {
|
|
if (!Protection_from_shape_changers
|
|
&& !rn2(night() ? (flags.moonphase == FULL_MOON ? 3 : 30)
|
|
: (flags.moonphase == FULL_MOON ? 10 : 50))) {
|
|
new_were(mon); /* change into animal form */
|
|
if (!Deaf && !canseemon(mon)) {
|
|
const char *howler;
|
|
|
|
switch (monsndx(mon->data)) {
|
|
case PM_WEREWOLF:
|
|
howler = "wolf";
|
|
break;
|
|
case PM_WEREJACKAL:
|
|
howler = "jackal";
|
|
break;
|
|
default:
|
|
howler = (char *) 0;
|
|
break;
|
|
}
|
|
if (howler)
|
|
You_hear("a %s howling at the moon.", howler);
|
|
}
|
|
}
|
|
} else if (!rn2(30) || Protection_from_shape_changers) {
|
|
new_were(mon); /* change back into human form */
|
|
}
|
|
/* update innate intrinsics (mainly Drain_resistance) */
|
|
set_uasmon(); /* new_were() doesn't do this */
|
|
}
|
|
|
|
int
|
|
counter_were(pm)
|
|
int pm;
|
|
{
|
|
switch (pm) {
|
|
case PM_WEREWOLF:
|
|
return PM_HUMAN_WEREWOLF;
|
|
case PM_HUMAN_WEREWOLF:
|
|
return PM_WEREWOLF;
|
|
case PM_WEREJACKAL:
|
|
return PM_HUMAN_WEREJACKAL;
|
|
case PM_HUMAN_WEREJACKAL:
|
|
return PM_WEREJACKAL;
|
|
case PM_WERERAT:
|
|
return PM_HUMAN_WERERAT;
|
|
case PM_HUMAN_WERERAT:
|
|
return PM_WERERAT;
|
|
default:
|
|
return NON_PM;
|
|
}
|
|
}
|
|
|
|
/* convert monsters similar to werecritters into appropriate werebeast */
|
|
int
|
|
were_beastie(pm)
|
|
int pm;
|
|
{
|
|
switch (pm) {
|
|
case PM_WERERAT:
|
|
case PM_SEWER_RAT:
|
|
case PM_GIANT_RAT:
|
|
case PM_RABID_RAT:
|
|
return PM_WERERAT;
|
|
case PM_WEREJACKAL:
|
|
case PM_JACKAL:
|
|
case PM_FOX:
|
|
case PM_COYOTE:
|
|
return PM_WEREJACKAL;
|
|
case PM_WEREWOLF:
|
|
case PM_WOLF:
|
|
case PM_WARG:
|
|
case PM_WINTER_WOLF:
|
|
return PM_WEREWOLF;
|
|
default:
|
|
break;
|
|
}
|
|
return NON_PM;
|
|
}
|
|
|
|
void
|
|
new_were(mon)
|
|
register struct monst *mon;
|
|
{
|
|
register int pm;
|
|
|
|
pm = counter_were(monsndx(mon->data));
|
|
if (pm < LOW_PM) {
|
|
impossible("unknown lycanthrope %s.", mon->data->mname);
|
|
return;
|
|
}
|
|
|
|
if (canseemon(mon) && !Hallucination)
|
|
pline("%s changes into a %s.", Monnam(mon),
|
|
is_human(&mons[pm]) ? "human" : mons[pm].mname + 4);
|
|
|
|
set_mon_data(mon, &mons[pm]);
|
|
if (mon->msleeping || !mon->mcanmove) {
|
|
/* transformation wakens and/or revitalizes */
|
|
mon->msleeping = 0;
|
|
mon->mfrozen = 0; /* not asleep or paralyzed */
|
|
mon->mcanmove = 1;
|
|
}
|
|
/* regenerate by 1/4 of the lost hit points */
|
|
mon->mhp += (mon->mhpmax - mon->mhp) / 4;
|
|
newsym(mon->mx, mon->my);
|
|
mon_break_armor(mon, FALSE);
|
|
possibly_unwield(mon, FALSE);
|
|
}
|
|
|
|
/* were-creature (even you) summons a horde */
|
|
int
|
|
were_summon(ptr, yours, visible, genbuf)
|
|
struct permonst *ptr;
|
|
boolean yours;
|
|
int *visible; /* number of visible helpers created */
|
|
char *genbuf;
|
|
{
|
|
int i, typ, pm = monsndx(ptr);
|
|
struct monst *mtmp;
|
|
int total = 0;
|
|
|
|
*visible = 0;
|
|
if (Protection_from_shape_changers && !yours)
|
|
return 0;
|
|
for (i = rnd(5); i > 0; i--) {
|
|
switch (pm) {
|
|
case PM_WERERAT:
|
|
case PM_HUMAN_WERERAT:
|
|
typ = rn2(3) ? PM_SEWER_RAT
|
|
: rn2(3) ? PM_GIANT_RAT : PM_RABID_RAT;
|
|
if (genbuf)
|
|
Strcpy(genbuf, "rat");
|
|
break;
|
|
case PM_WEREJACKAL:
|
|
case PM_HUMAN_WEREJACKAL:
|
|
typ = rn2(7) ? PM_JACKAL : rn2(3) ? PM_COYOTE : PM_FOX;
|
|
if (genbuf)
|
|
Strcpy(genbuf, "jackal");
|
|
break;
|
|
case PM_WEREWOLF:
|
|
case PM_HUMAN_WEREWOLF:
|
|
typ = rn2(5) ? PM_WOLF : rn2(2) ? PM_WARG : PM_WINTER_WOLF;
|
|
if (genbuf)
|
|
Strcpy(genbuf, "wolf");
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
mtmp = makemon(&mons[typ], u.ux, u.uy, NO_MM_FLAGS);
|
|
if (mtmp) {
|
|
total++;
|
|
if (canseemon(mtmp))
|
|
*visible += 1;
|
|
}
|
|
if (yours && mtmp)
|
|
(void) tamedog(mtmp, (struct obj *) 0);
|
|
}
|
|
return total;
|
|
}
|
|
|
|
void
|
|
you_were()
|
|
{
|
|
char qbuf[QBUFSZ];
|
|
boolean controllable_poly = Polymorph_control && !(Stunned || Unaware);
|
|
|
|
if (Unchanging || u.umonnum == u.ulycn)
|
|
return;
|
|
if (controllable_poly) {
|
|
/* `+4' => skip "were" prefix to get name of beast */
|
|
Sprintf(qbuf, "Do you want to change into %s?",
|
|
an(mons[u.ulycn].mname + 4));
|
|
if (!paranoid_query(ParanoidWerechange, qbuf))
|
|
return;
|
|
}
|
|
(void) polymon(u.ulycn);
|
|
}
|
|
|
|
void
|
|
you_unwere(purify)
|
|
boolean purify;
|
|
{
|
|
boolean controllable_poly = Polymorph_control && !(Stunned || Unaware);
|
|
|
|
if (purify) {
|
|
You_feel("purified.");
|
|
set_ulycn(NON_PM); /* cure lycanthropy */
|
|
}
|
|
if (!Unchanging && is_were(youmonst.data)
|
|
&& (!controllable_poly
|
|
|| !paranoid_query(ParanoidWerechange, "Remain in beast form?")))
|
|
rehumanize();
|
|
else if (is_were(youmonst.data) && !u.mtimedone)
|
|
u.mtimedone = rn1(200, 200); /* 40% of initial were change */
|
|
}
|
|
|
|
/* lycanthropy is being caught or cured, but no shape change is involved */
|
|
void
|
|
set_ulycn(which)
|
|
int which;
|
|
{
|
|
u.ulycn = which;
|
|
/* add or remove lycanthrope's innate intrinsics (Drain_resistance) */
|
|
set_uasmon();
|
|
}
|
|
|
|
/*were.c*/
|