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:
12
src/invent.c
12
src/invent.c
@@ -2224,15 +2224,17 @@ ggetobj(const char *word, int (*fn)(OBJ_P), int mx,
|
||||
return 0;
|
||||
if (strchr(buf, 'i')) {
|
||||
char ailets[1+26+26+1+5+1]; /* $ + a-z + A-Z + # + slop + \0 */
|
||||
struct obj *otmp;
|
||||
struct obj *otmp, *nextobj;
|
||||
|
||||
/* applicable inventory letters; if empty, show entire invent */
|
||||
ailets[0] = '\0';
|
||||
if (ofilter)
|
||||
for (otmp = gi.invent; otmp; otmp = otmp->nobj)
|
||||
for (otmp = gi.invent; otmp; otmp = nextobj) {
|
||||
nextobj = otmp->nobj;
|
||||
/* strchr() check: limit overflow items to one '#' */
|
||||
if ((*ofilter)(otmp) && !strchr(ailets, otmp->invlet))
|
||||
(void) strkitten(ailets, otmp->invlet);
|
||||
}
|
||||
if (display_inventory(ailets, TRUE) == '\033')
|
||||
return 0;
|
||||
} else
|
||||
@@ -3491,7 +3493,7 @@ dispinv_with_action(
|
||||
boolean use_inuse_ordering, /* affects sortloot() and header labels */
|
||||
const char *alt_label) /* alternate value for in-use "Accessories" */
|
||||
{
|
||||
struct obj *otmp;
|
||||
struct obj *otmp, *nextobj;
|
||||
const char *save_accessories = 0;
|
||||
char c, save_sortloot = 0;
|
||||
unsigned len = lets ? (unsigned) strlen(lets) : 0U;
|
||||
@@ -3517,9 +3519,11 @@ dispinv_with_action(
|
||||
iflags.force_invmenu = save_force_invmenu;
|
||||
|
||||
if (c && c != '\033') {
|
||||
for (otmp = gi.invent; otmp; otmp = otmp->nobj)
|
||||
for (otmp = gi.invent; otmp; otmp = nextobj) {
|
||||
nextobj = otmp->nobj;
|
||||
if (otmp->invlet == c)
|
||||
return itemactions(otmp);
|
||||
}
|
||||
}
|
||||
return ECMD_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user