iterating gi.invent (github issue #1315)
GitHub issue #1315 points out that it is possible for a downstream function to change an object's nobj field to point to a completely different chain. The cited example by @vultur-cadens was: for (obj = gi.invent; obj; obj = obj->nobj) if (obj->oclass != COIN_CLASS && !obj->cursed && !rn2(5)) { curse(obj); ++buc_changed; } curse() drops the weapon with drop_uswapwep(), which calls dropx(), which calls dropy(), which calls dropz(), which calls place_object(). place_object alters the nobj pointer, to point to the floor chain: otmp->nobj = fobj; fobj = otmp; The result was that the next loop iteration was then using floor objects from the floor chain. This alters several for-loops to use a more consistent approach, particularly when the obj is being handed off to a function, where a downstream function might, or might not, alter the nobj field. References: https://github.com/NetHack/NetHack/issues/1315 https://www.reddit.com/r/nethack/comments/1gkc9ub/even_if_you_drop_an_item_before_drinking_from_the/
This commit is contained in:
21
src/trap.c
21
src/trap.c
@@ -1551,7 +1551,7 @@ trapeffect_rust_trap(
|
||||
struct trap *trap,
|
||||
unsigned int trflags UNUSED)
|
||||
{
|
||||
struct obj *otmp;
|
||||
struct obj *otmp, *nextobj;
|
||||
|
||||
if (mtmp == &gy.youmonst) {
|
||||
seetrap(trap);
|
||||
@@ -1583,10 +1583,12 @@ trapeffect_rust_trap(
|
||||
pline("%s you!", A_gush_of_water_hits);
|
||||
/* note: exclude primary and secondary weapons from splashing
|
||||
because cases 1 and 2 target them [via water_damage()] */
|
||||
for (otmp = gi.invent; otmp; otmp = otmp->nobj)
|
||||
for (otmp = gi.invent; otmp; otmp = nextobj) {
|
||||
nextobj = otmp->nobj;
|
||||
if (otmp->lamplit && otmp != uwep
|
||||
&& (otmp != uswapwep || !u.twoweap))
|
||||
(void) splash_lit(otmp);
|
||||
}
|
||||
if (uarmc)
|
||||
(void) water_damage(uarmc, cloak_simple_name(uarmc), TRUE);
|
||||
else if (uarm)
|
||||
@@ -4764,13 +4766,14 @@ emergency_disrobe(boolean *lostsome)
|
||||
int invc = inv_cnt(TRUE);
|
||||
|
||||
while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) {
|
||||
struct obj *obj, *otmp = (struct obj *) 0;
|
||||
struct obj *obj, *nextobj, *otmp = (struct obj *) 0;
|
||||
int i;
|
||||
|
||||
/* Pick a random object */
|
||||
if (invc > 0) {
|
||||
i = rn2(invc);
|
||||
for (obj = gi.invent; obj; obj = obj->nobj) {
|
||||
for (obj = gi.invent; obj; obj = nextobj) {
|
||||
nextobj = obj->nobj;
|
||||
/*
|
||||
* Undroppables are: body armor, boots, gloves,
|
||||
* amulets, and rings because of the time and effort
|
||||
@@ -6589,7 +6592,7 @@ static const char lava_killer[] = "molten lava";
|
||||
boolean
|
||||
lava_effects(void)
|
||||
{
|
||||
struct obj *obj, *obj2;
|
||||
struct obj *obj, *obj2, *nextobj;
|
||||
boolean usurvive, boil_away;
|
||||
unsigned protect_oid = 0;
|
||||
int burncount = 0, burnmesgcount = 0;
|
||||
@@ -6616,7 +6619,8 @@ lava_effects(void)
|
||||
* emergency save file created before item destruction.
|
||||
*/
|
||||
if (!usurvive) {
|
||||
for (obj = gi.invent; obj; obj = obj->nobj) {
|
||||
for (obj = gi.invent; obj; obj = nextobj) {
|
||||
nextobj = obj->nobj;
|
||||
if (obj->in_use) { /* remove_worn_item() sets in_use */
|
||||
/* one item can be protected from burning up [accommodates
|
||||
steal(AMULET_OF_FLYING) -> remove_worn_item() -> fall
|
||||
@@ -6952,10 +6956,11 @@ trapname(
|
||||
void
|
||||
ignite_items(struct obj *objchn)
|
||||
{
|
||||
struct obj *obj;
|
||||
struct obj *obj, *nextobj;
|
||||
boolean bynexthere = (objchn && objchn->where == OBJ_FLOOR);
|
||||
|
||||
for (obj = objchn; obj; obj = bynexthere ? obj->nexthere : obj->nobj) {
|
||||
for (obj = objchn; obj; obj = bynexthere ? obj->nexthere : nextobj) {
|
||||
nextobj = obj->nobj;
|
||||
/* ignitable items like lamps and candles will catch fire */
|
||||
if (!obj->lamplit && !obj->in_use)
|
||||
catch_lit(obj);
|
||||
|
||||
Reference in New Issue
Block a user