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

@@ -20,8 +20,9 @@ staticfn NHFILE *currentlevel_rewrite(void);
staticfn void familiar_level_msg(void);
staticfn void final_level(void);
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 */
int
@@ -709,6 +710,8 @@ drop(struct obj *obj)
return ECMD_FAIL;
if (!canletgo(obj, "drop"))
return ECMD_FAIL;
if (obj->otyp == CORPSE && better_not_try_to_drop_that(obj))
return ECMD_FAIL;
if (obj == uwep) {
if (welded(uwep)) {
weldmsg(obj);
@@ -933,6 +936,23 @@ doddrop(void)
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 */
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 */
staticfn struct obj *maybe_destroy_armor(struct obj *, struct obj *,
boolean *) NONNULLARG3;
staticfn boolean better_not_take_that_off(struct obj *) NONNULLARG1;
/* plural "fingers" or optionally "gloves" */
const char *
@@ -2641,6 +2642,8 @@ select_off(struct obj *otmp)
gloves_simple_name(uarmg));
return 0;
}
if (better_not_take_that_off(otmp))
return 0;
}
/* special boot checks */
if (otmp == uarmf) {
@@ -2886,6 +2889,26 @@ take_off(void)
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' */
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 int itemactions(struct obj *);
staticfn int dispinv_with_action(char *, boolean, const char *);
staticfn struct obj *carrying_cockatrice_corpse(void);
/* enum and structs are defined in wintype.h */
static win_request_info wri_info;
@@ -1231,7 +1232,7 @@ hold_another_object(
obj = addinv_core0(obj, (struct obj *) 0, FALSE);
goto drop_it;
} else if (obj->otyp == CORPSE
&& !u_safe_from_fatal_corpse(obj)
&& !u_safe_from_fatal_corpse(obj, 0xF)
&& obj->wishedfor) {
obj->wishedfor = 0;
obj = addinv_core0(obj, (struct obj *) 0, FALSE);
@@ -1480,6 +1481,18 @@ carrying(int type)
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.
* http://concord.wikia.com/wiki/List_of_Fictional_Currencies
*/

View File

@@ -261,11 +261,20 @@ query_classes(
return TRUE;
}
/*
* tests:
* 1 = gloves
* 2 = is_corpse
* 4 = does corpse petrify
* 8 = stone resistance
*/
boolean
u_safe_from_fatal_corpse(struct obj *obj)
u_safe_from_fatal_corpse(struct obj *obj, int tests)
{
if (uarmg || obj->otyp != CORPSE
|| !touch_petrifies(&mons[obj->corpsenm]) || Stone_resistance)
if (((tests & 1) && uarmg)
|| ((tests & 2) && obj->otyp != CORPSE)
|| ((tests & 4) && !touch_petrifies(&mons[obj->corpsenm]))
|| ((tests & 8) && Stone_resistance))
return TRUE;
return FALSE;
}
@@ -274,7 +283,7 @@ u_safe_from_fatal_corpse(struct obj *obj)
staticfn boolean
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;
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
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;
const char *verb = ((Is_airlevel(&u.uz) || u.uinwater)