worn/wielded pointer sanity checks
Check the various uarm, uwep, and so forth pointers to make sure that they point to items in hero's inventory and that those items have the corresponding W_ARM, W_WEP, &c bit set in their owornmask field. Also check whether any other items in inventory have the same bit set. [Some of this is already handled by sanity_check_worn() in mkobj.c.] Also validate two-weapon combat mode. I don't recall ever seeing any problems reported about it though. Does not validate ball and chain. Those should have their own sanity checks that validate a bunch of other stuff besides just worn slots. They already get some checking by the normal object tests. This works ok with 'sanity_check' set and items worn and wielded normally. The only insane situation tested was by reverting the confused-looting-with-quivered-gold fix from earlier today. I haven't used a debugger to force other such problems so this isn't very thoroughly tested.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 extern.h $NHDT-Date: 1706213788 2024/01/25 20:16:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1373 $ */
|
||||
/* NetHack 3.7 extern.h $NHDT-Date: 1707547708 2024/02/10 06:48:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1381 $ */
|
||||
/* Copyright (c) Steve Creps, 1988. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -3686,6 +3686,7 @@ extern void setnotworn(struct obj *) NO_NNARGS; /* has tests for obj */
|
||||
extern void allunworn(void);
|
||||
extern struct obj *wearmask_to_obj(long);
|
||||
extern long wearslot(struct obj *) NONNULLARG1;
|
||||
extern void check_wornmask_slots(void);
|
||||
extern void mon_set_minvis(struct monst *) NONNULLARG1;
|
||||
extern void mon_adjust_speed(struct monst *, int, struct obj *) NONNULLARG1;
|
||||
extern void update_mon_extrinsics(struct monst *, struct obj *, boolean,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 cmd.c $NHDT-Date: 1704225560 2024/01/02 19:59:20 $ $NHDT-Branch: keni-luabits2 $:$NHDT-Revision: 1.699 $ */
|
||||
/* NetHack 3.7 cmd.c $NHDT-Date: 1707547723 2024/02/10 06:48:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.704 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2013. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -4255,6 +4255,7 @@ you_sanity_check(void)
|
||||
impossible("sanity_check: you over monster");
|
||||
}
|
||||
|
||||
check_wornmask_slots();
|
||||
(void) check_invent_gold("invent");
|
||||
}
|
||||
|
||||
|
||||
124
src/worn.c
124
src/worn.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 worn.c $NHDT-Date: 1652577035 2022/05/15 01:10:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.84 $ */
|
||||
/* NetHack 3.7 worn.c $NHDT-Date: 1707547726 2024/02/10 06:48:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.100 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2013. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -13,22 +13,23 @@ static int extra_pref(struct monst *, struct obj *) NONNULLARG1;
|
||||
const struct worn {
|
||||
long w_mask;
|
||||
struct obj **w_obj;
|
||||
} worn[] = { { W_ARM, &uarm },
|
||||
{ W_ARMC, &uarmc },
|
||||
{ W_ARMH, &uarmh },
|
||||
{ W_ARMS, &uarms },
|
||||
{ W_ARMG, &uarmg },
|
||||
{ W_ARMF, &uarmf },
|
||||
{ W_ARMU, &uarmu },
|
||||
{ W_RINGL, &uleft },
|
||||
{ W_RINGR, &uright },
|
||||
{ W_WEP, &uwep },
|
||||
{ W_SWAPWEP, &uswapwep },
|
||||
{ W_QUIVER, &uquiver },
|
||||
{ W_AMUL, &uamul },
|
||||
{ W_TOOL, &ublindf },
|
||||
{ W_BALL, &uball },
|
||||
{ W_CHAIN, &uchain },
|
||||
const char *w_what; /* for failing sanity check's feedback */
|
||||
} worn[] = { { W_ARM, &uarm, "suit" },
|
||||
{ W_ARMC, &uarmc, "cloak" },
|
||||
{ W_ARMH, &uarmh, "helmet" },
|
||||
{ W_ARMS, &uarms, "shield" },
|
||||
{ W_ARMG, &uarmg, "gloves" },
|
||||
{ W_ARMF, &uarmf, "boots" },
|
||||
{ W_ARMU, &uarmu, "shirt" },
|
||||
{ W_RINGL, &uleft, "left ring" },
|
||||
{ W_RINGR, &uright, "right ring" },
|
||||
{ W_WEP, &uwep, "weapon" },
|
||||
{ W_SWAPWEP, &uswapwep, "alternate weapon" },
|
||||
{ W_QUIVER, &uquiver, "quiver" },
|
||||
{ W_AMUL, &uamul, "amulet" },
|
||||
{ W_TOOL, &ublindf, "facewear" }, /* blindfold|towel|lenses */
|
||||
{ W_BALL, &uball, "chained ball" },
|
||||
{ W_CHAIN, &uchain, "attached chain" },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@@ -251,6 +252,95 @@ wearslot(struct obj *obj)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* for 'sanity_check' option, called by you_sanity_check() */
|
||||
void
|
||||
check_wornmask_slots(void)
|
||||
{
|
||||
/* we'll skip ball and chain here--they warrant separate sanity check;
|
||||
at present, we also skip 'uskin' because it isn't included in worn[] */
|
||||
#define IGNORE_SLOTS (W_ART | W_ARTI | W_SADDLE | W_BALL| W_CHAIN)
|
||||
char whybuf[BUFSZ];
|
||||
const struct worn *wp;
|
||||
struct obj *o, *otmp;
|
||||
long m;
|
||||
|
||||
for (wp = worn; wp->w_mask; wp++) {
|
||||
o = *wp->w_obj;
|
||||
if (!o)
|
||||
continue;
|
||||
m = wp->w_mask;
|
||||
if ((m & IGNORE_SLOTS) != 0L && (m & ~IGNORE_SLOTS) == 0L)
|
||||
continue;
|
||||
if ((o = *wp->w_obj) != 0) {
|
||||
whybuf[0] = '\0';
|
||||
/* slot pointer (uarm, uwep, &c) is populated; check that object
|
||||
is in inventory and has the relevant owornmask bit set */
|
||||
for (otmp = gi.invent; otmp; otmp = otmp->nobj)
|
||||
if (otmp == o)
|
||||
break;
|
||||
if (!otmp)
|
||||
Sprintf(whybuf, "%s (%s) not found in invent",
|
||||
wp->w_what, fmt_ptr(o));
|
||||
else if ((o->owornmask & m) == 0L)
|
||||
Sprintf(whybuf, "%s bit not set in owornmask [0x%08lx]",
|
||||
wp->w_what, o->owornmask);
|
||||
else if ((o->owornmask & ~(m | IGNORE_SLOTS)) != 0L)
|
||||
Sprintf(whybuf, "%s wrong bit set in owornmask [0x%08lx]",
|
||||
wp->w_what, o->owornmask);
|
||||
if (whybuf[0])
|
||||
impossible("Worn-slot insanity: %s.", whybuf);
|
||||
} /* o != NULL */
|
||||
|
||||
/* check whether any item other than the one in the slot pointer
|
||||
claims to be worn/wielded in this slot; make this test whether
|
||||
'o' is Null or not; [sanity_check_worn(mkobj.c) for object by
|
||||
object checking will most likely have already caught this] */
|
||||
for (otmp = gi.invent; otmp; otmp = otmp->nobj) {
|
||||
if (otmp != o && (otmp->owornmask & wp->w_mask) != 0L) {
|
||||
Sprintf(whybuf, "%s has owornmask 0x%08lx [0x%08lx bit set]",
|
||||
wp->w_what, otmp->owornmask, m);
|
||||
impossible("Worn-slot insanity: %s.", whybuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EXTRA_SANITY_CHECKS
|
||||
/* dual wielding: not a slot but lots of things to verify */
|
||||
if (u.twoweap) {
|
||||
const char *why = NULL;
|
||||
|
||||
if (!uwep || !uswapwep) {
|
||||
Sprintf(whybuf, "without %s%s%s",
|
||||
!uwep ? "uwep" : "",
|
||||
(!uwep && !uswapwep) ? " and without " : "",
|
||||
!uswapwep ? "uswapwep" : "");
|
||||
why = whybuf;
|
||||
} else if (uarms)
|
||||
why = "while wearing shield";
|
||||
else if (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep))
|
||||
why = "uwep is not a weapon";
|
||||
else if (is_launcher(uwep) || is_ammo(uwep) || is_missile(uwep))
|
||||
why = "uwep is not a melee weapon";
|
||||
else if (bimanual(uwep))
|
||||
why = "uwep is two-handed";
|
||||
else if (uswapwep->oclass != WEAPON_CLASS && !is_weptool(uswapwep))
|
||||
why = "uswapwep is not a weapon";
|
||||
else if (is_launcher(uswapwep) || is_ammo(uswapwep)
|
||||
|| is_missile(uswapwep))
|
||||
why = "uswapwep is not a melee weapon";
|
||||
else if (bimanual(uswapwep))
|
||||
why = "uswapwep is two-handed";
|
||||
else if (!could_twoweap(gy.youmonst.data))
|
||||
why = "without two weapon attacks";
|
||||
|
||||
if (why)
|
||||
impossible("Two-weapon insanity: %s.", why);
|
||||
}
|
||||
#endif /* EXTRA_SANITY_CHECKS */
|
||||
return;
|
||||
#undef IGNORE_SLOTS
|
||||
} /* check_wornmask_slots() */
|
||||
|
||||
void
|
||||
mon_set_minvis(struct monst *mon)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user