follow-up related to #1320

This is additional groundwork related to
https://github.com/NetHack/NetHack/issues/1320

This additional groundwork just puts some safeguards
in place to make it rather tough to end up with an
instant death from handling a cockatrice corpse in
your inventory without appropriate protection.

At this point, still no actual petrification will occur.
This commit is contained in:
nhmall
2024-11-09 23:49:10 -05:00
parent a40d85a430
commit 5cc529efc8
6 changed files with 74 additions and 8 deletions

View File

@@ -1326,6 +1326,7 @@ extern void silly_thing(const char *, struct obj *) NONNULLARG1;
extern void sync_perminvent(void); extern void sync_perminvent(void);
extern void perm_invent_toggled(boolean negated); extern void perm_invent_toggled(boolean negated);
extern void prepare_perminvent(winid window); extern void prepare_perminvent(winid window);
extern struct obj *carrying_stoning_corpse(void);
/* ### ioctl.c ### */ /* ### ioctl.c ### */
@@ -2363,7 +2364,7 @@ extern int loot_mon(struct monst *, int *, boolean *) NO_NNARGS;
extern int dotip(void); extern int dotip(void);
extern struct autopickup_exception *check_autopickup_exceptions(struct obj *) NONNULLARG1; extern struct autopickup_exception *check_autopickup_exceptions(struct obj *) NONNULLARG1;
extern boolean autopick_testobj(struct obj *, boolean) NONNULLARG1; extern boolean autopick_testobj(struct obj *, boolean) NONNULLARG1;
extern boolean u_safe_from_fatal_corpse(struct obj *obj) NONNULLARG1; extern boolean u_safe_from_fatal_corpse(struct obj *obj, int) NONNULLARG1;
/* ### pline.c ### */ /* ### pline.c ### */

View File

@@ -20,8 +20,9 @@ staticfn NHFILE *currentlevel_rewrite(void);
staticfn void familiar_level_msg(void); staticfn void familiar_level_msg(void);
staticfn void final_level(void); staticfn void final_level(void);
staticfn void temperature_change_msg(schar); staticfn void temperature_change_msg(schar);
staticfn boolean better_not_try_to_drop_that(struct obj *);
/* static boolean badspot(coordxy,coordxy); */ /* static boolean badspot(coordxy,coordxy); */
/* the #drop command: drop one inventory item */ /* the #drop command: drop one inventory item */
int int
@@ -709,6 +710,8 @@ drop(struct obj *obj)
return ECMD_FAIL; return ECMD_FAIL;
if (!canletgo(obj, "drop")) if (!canletgo(obj, "drop"))
return ECMD_FAIL; return ECMD_FAIL;
if (obj->otyp == CORPSE && better_not_try_to_drop_that(obj))
return ECMD_FAIL;
if (obj == uwep) { if (obj == uwep) {
if (welded(uwep)) { if (welded(uwep)) {
weldmsg(obj); weldmsg(obj);
@@ -933,6 +936,23 @@ doddrop(void)
return result; return result;
} }
staticfn boolean
better_not_try_to_drop_that(struct obj *otmp)
{
char buf[BUFSZ];
/* u_safe_from_fatal_corpse() with 0xF checks for gloves and stoning
* resistance before bothering to prompt you.
*/
if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, 0xF)) {
Snprintf(
buf, sizeof buf,
"Drop the %s corpse without any protection while handling it?",
obj_pmname(otmp));
return (paranoid_ynq(TRUE, buf, FALSE) != 'y');
}
return FALSE;
}
staticfn int /* check callers */ staticfn int /* check callers */
menudrop_split(struct obj *otmp, long cnt) menudrop_split(struct obj *otmp, long cnt)
{ {

View File

@@ -52,6 +52,7 @@ staticfn int takeoff_ok(struct obj *);
/* maybe_destroy_armor() may return NULL */ /* maybe_destroy_armor() may return NULL */
staticfn struct obj *maybe_destroy_armor(struct obj *, struct obj *, staticfn struct obj *maybe_destroy_armor(struct obj *, struct obj *,
boolean *) NONNULLARG3; boolean *) NONNULLARG3;
staticfn boolean better_not_take_that_off(struct obj *) NONNULLARG1;
/* plural "fingers" or optionally "gloves" */ /* plural "fingers" or optionally "gloves" */
const char * const char *
@@ -2641,6 +2642,8 @@ select_off(struct obj *otmp)
gloves_simple_name(uarmg)); gloves_simple_name(uarmg));
return 0; return 0;
} }
if (better_not_take_that_off(otmp))
return 0;
} }
/* special boot checks */ /* special boot checks */
if (otmp == uarmf) { if (otmp == uarmf) {
@@ -2886,6 +2889,26 @@ take_off(void)
return 1; /* get busy */ return 1; /* get busy */
} }
staticfn boolean
better_not_take_that_off(struct obj *otmp)
{
struct obj *corpse = carrying_stoning_corpse();
char buf[BUFSZ];
/* u_safe_from_fatal_corpse() with 0x4e instead of 0x6
would also check for no stoning resistance before
bothering to prompt, but losing stoning resistance
later, without the gloves on could prove dangerous,
so we won't factor that in */
if (corpse && !u_safe_from_fatal_corpse(corpse, 0x6)) {
Snprintf(buf, sizeof buf,
"Take off your %s despite carrying a dead %s?",
gloves_simple_name(otmp), obj_pmname(corpse));
return (paranoid_ynq(TRUE, buf, FALSE) != 'y');
}
return FALSE;
}
/* clear saved context to avoid inappropriate resumption of interrupted 'A' */ /* clear saved context to avoid inappropriate resumption of interrupted 'A' */
void void
reset_remarm(void) reset_remarm(void)

View File

@@ -49,6 +49,7 @@ staticfn void ia_addmenu(winid, int, char, const char *);
staticfn void itemactions_pushkeys(struct obj *, int); staticfn void itemactions_pushkeys(struct obj *, int);
staticfn int itemactions(struct obj *); staticfn int itemactions(struct obj *);
staticfn int dispinv_with_action(char *, boolean, const char *); staticfn int dispinv_with_action(char *, boolean, const char *);
staticfn struct obj *carrying_cockatrice_corpse(void);
/* enum and structs are defined in wintype.h */ /* enum and structs are defined in wintype.h */
static win_request_info wri_info; static win_request_info wri_info;
@@ -1231,7 +1232,7 @@ hold_another_object(
obj = addinv_core0(obj, (struct obj *) 0, FALSE); obj = addinv_core0(obj, (struct obj *) 0, FALSE);
goto drop_it; goto drop_it;
} else if (obj->otyp == CORPSE } else if (obj->otyp == CORPSE
&& !u_safe_from_fatal_corpse(obj) && !u_safe_from_fatal_corpse(obj, 0xF)
&& obj->wishedfor) { && obj->wishedfor) {
obj->wishedfor = 0; obj->wishedfor = 0;
obj = addinv_core0(obj, (struct obj *) 0, FALSE); obj = addinv_core0(obj, (struct obj *) 0, FALSE);
@@ -1480,6 +1481,18 @@ carrying(int type)
return otmp; return otmp;
} }
/* return inventory object of type that will petrify on touch */
struct obj *
carrying_stoning_corpse(void)
{
struct obj *otmp;
for (otmp = gi.invent; otmp; otmp = otmp->nobj)
if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]))
break;
return otmp;
}
/* Fictional and not-so-fictional currencies. /* Fictional and not-so-fictional currencies.
* http://concord.wikia.com/wiki/List_of_Fictional_Currencies * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
*/ */

View File

@@ -261,11 +261,20 @@ query_classes(
return TRUE; return TRUE;
} }
/*
* tests:
* 1 = gloves
* 2 = is_corpse
* 4 = does corpse petrify
* 8 = stone resistance
*/
boolean boolean
u_safe_from_fatal_corpse(struct obj *obj) u_safe_from_fatal_corpse(struct obj *obj, int tests)
{ {
if (uarmg || obj->otyp != CORPSE if (((tests & 1) && uarmg)
|| !touch_petrifies(&mons[obj->corpsenm]) || Stone_resistance) || ((tests & 2) && obj->otyp != CORPSE)
|| ((tests & 4) && !touch_petrifies(&mons[obj->corpsenm]))
|| ((tests & 8) && Stone_resistance))
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
@@ -274,7 +283,7 @@ u_safe_from_fatal_corpse(struct obj *obj)
staticfn boolean staticfn boolean
fatal_corpse_mistake(struct obj *obj, boolean remotely) fatal_corpse_mistake(struct obj *obj, boolean remotely)
{ {
if (u_safe_from_fatal_corpse(obj) || remotely) if (u_safe_from_fatal_corpse(obj, 0xF) || remotely)
return FALSE; return FALSE;
if (poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM)) { if (poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM)) {

View File

@@ -6189,7 +6189,7 @@ makewish(void)
/* TODO? maybe generate a second event describing what was received since /* TODO? maybe generate a second event describing what was received since
these just echo player's request rather than show actual result */ these just echo player's request rather than show actual result */
if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp)) if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, 0xF))
otmp->wishedfor = 1; otmp->wishedfor = 1;
const char *verb = ((Is_airlevel(&u.uz) || u.uinwater) const char *verb = ((Is_airlevel(&u.uz) || u.uinwater)