From 90717ca633685478f5a309fd697a424ac38bf5b4 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 13 Mar 2025 13:54:56 -0700 Subject: [PATCH] more chest->tknown handling Disarming a chest trap was setting obj->tknown = 0 even though the hero just discovered that it isn't trapped. Triggering a chest trap behaved similarly. Since there are no repeating chest traps, hero should know that the chest whose trap just went off is no longer trapped. chest_trap() didn't document its return value but was clearly meant to return True if the chest was destroyed. It didn't handle that correctly when the chest was being carried. However, none of the callers actually use the return value. [This fix tracks whether the chest gets deleted; a better fix would be to destroy an exploding chest even when it is being carried.] --- doc/fixes3-7-0.txt | 3 +++ src/trap.c | 29 +++++++++++++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 1658e9948..bce39a4d1 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2100,6 +2100,9 @@ having a 1% chance of creating rideable monsters with worn saddle gave knights tracked with other objects so produced a trivial memory leak when attacking a displacer beast, using the 'F' forcefight prefix prevented it from swapping places with the hero +successfully disarming a chest trap was clearing the chest's 'tknown' bit + instead of setting it; likewise when failing to disarm triggered and + used up the trap Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/trap.c b/src/trap.c index f309dd595..53fa65f5e 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 trap.c $NHDT-Date: 1720128169 2024/07/04 21:22:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.602 $ */ +/* NetHack 3.7 trap.c $NHDT-Date: 1741926700 2025/03/13 20:31:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.621 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -5711,7 +5711,7 @@ disarm_box(struct obj *box, boolean force, boolean confused) } else { You("disarm it!"); box->otrapped = 0; - box->tknown = 0; + box->tknown = 1; more_experienced(8, 0); newexplevel(); } @@ -6194,7 +6194,8 @@ openfallingtrap( return result; } -/* only called when the player is doing something to the chest directly */ +/* only called when the player is doing something to the chest directly; + returns True if chest is destroyed, False if it remains in play */ boolean chest_trap( struct obj *obj, @@ -6209,9 +6210,9 @@ chest_trap( if (get_obj_location(obj, &cc.x, &cc.y, 0)) /* might be carried */ obj->ox = cc.x, obj->oy = cc.y; - otmp->tknown = 0; + otmp->tknown = 0; /* for xname(); will be set to 1 below */ otmp->otrapped = 0; /* trap is one-shot; clear flag first in case - chest kills you and ends up in bones file */ + * chest kills you and ends up in bones file */ You(disarm ? "set it off!" : "trigger a trap!"); display_nhwindow(WIN_MESSAGE, FALSE); if (Luck > -13 && rn2(13 + Luck) > 7) { /* saved by luck */ @@ -6256,7 +6257,7 @@ chest_trap( case 21: { struct monst *shkp = 0; long loss = 0L; - boolean costly, insider; + boolean costly, insider, chestgone; coordxy ox = obj->ox, oy = obj->oy; /* the obj location need not be that of player */ @@ -6286,28 +6287,35 @@ chest_trap( && uball->ox == ox && uball->oy == oy))) unpunish(); /* destroy everything at the spot (the Amulet, the - invocation tools, and Rider corpses will remain intact) */ + invocation tools, and Rider corpses will remain intact); + usually the chest will be destroyed along with the stuff at + this spot, but not if it is being carried */ + chestgone = FALSE; for (otmp = svl.level.objects[ox][oy]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (costly) loss += stolen_value(otmp, otmp->ox, otmp->oy, (boolean) shkp->mpeaceful, TRUE); + if (otmp == obj) + chestgone = TRUE; delobj(otmp); } wake_nearby(FALSE); losehp(Maybe_Half_Phys(d(6, 6)), buf, KILLED_BY_AN); exercise(A_STR, FALSE); if (costly && loss) { - if (insider) + if (insider) { You("owe %ld %s for objects destroyed.", loss, currency(loss)); - else { + } else { You("caused %ld %s worth of damage!", loss, currency(loss)); make_angry_shk(shkp, ox, oy); } } - return TRUE; + if (chestgone) + return TRUE; + break; /* set tknown and return False */ } /* case 21 */ case 20: case 19: @@ -6392,6 +6400,7 @@ chest_trap( bot(); /* to get immediate botl re-display */ } + otmp->tknown = 1; /* hero knows chest is no longer trapped */ return FALSE; }