more exploding magic pointers
My simpler fix for dealing with stale pointers caused by magic bag
explosion didn't handle menu_loot() checking whether to merge a destroyed
object with a stack it had been split from (the case <Someone> didn't attempt to
address either). That only needs a one-line change, but this also removes
the illusiion of generality that menu_loot() tried to maintain. It always
operates on current_container and relies on calling in_container() and
out_container() which do the same, so passing a container argument to it
was not useful. If that had been taken out first, <Someone>'s method of fixing
the original problem would have been simpler than mine but I'm not planning
to back out the earlier change.
Also fix a minor post-3.4.3 bug with a container-contents-known flag
being set incorrectly.
This commit is contained in:
43
src/pickup.c
43
src/pickup.c
@@ -33,7 +33,7 @@ STATIC_PTR int FDECL(ck_bag,(struct obj *));
|
|||||||
STATIC_PTR int FDECL(out_container,(struct obj *));
|
STATIC_PTR int FDECL(out_container,(struct obj *));
|
||||||
STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *));
|
STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *));
|
||||||
STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
|
STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
|
||||||
STATIC_DCL int FDECL(menu_loot, (int, struct obj *, BOOLEAN_P));
|
STATIC_DCL int FDECL(menu_loot, (int,BOOLEAN_P));
|
||||||
STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P));
|
STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P));
|
||||||
STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
|
STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
|
||||||
STATIC_DCL boolean FDECL(able_to_loot, (int,int,BOOLEAN_P));
|
STATIC_DCL boolean FDECL(able_to_loot, (int,int,BOOLEAN_P));
|
||||||
@@ -2169,7 +2169,7 @@ register int held;
|
|||||||
}
|
}
|
||||||
if (loot_out) {
|
if (loot_out) {
|
||||||
add_valid_menu_class(0); /* reset */
|
add_valid_menu_class(0); /* reset */
|
||||||
used |= menu_loot(0, current_container, FALSE) > 0;
|
used |= menu_loot(0, FALSE) > 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* traditional code */
|
/* traditional code */
|
||||||
@@ -2197,15 +2197,14 @@ ask_again2:
|
|||||||
0, "nodot"))
|
0, "nodot"))
|
||||||
used = 1;
|
used = 1;
|
||||||
} else if (menu_on_request < 0) {
|
} else if (menu_on_request < 0) {
|
||||||
used |= menu_loot(menu_on_request,
|
used |= menu_loot(menu_on_request, FALSE) > 0;
|
||||||
current_container, FALSE) > 0;
|
|
||||||
}
|
}
|
||||||
/*FALLTHRU*/
|
/*FALLTHRU*/
|
||||||
case 'n':
|
case 'n':
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
menu_on_request = -2; /* triggers ALL_CLASSES */
|
menu_on_request = -2; /* triggers ALL_CLASSES */
|
||||||
used |= menu_loot(menu_on_request, current_container, FALSE) > 0;
|
used |= menu_loot(menu_on_request, FALSE) > 0;
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
default:
|
default:
|
||||||
@@ -2241,7 +2240,7 @@ ask_again2:
|
|||||||
case 'm':
|
case 'm':
|
||||||
add_valid_menu_class(0); /* reset */
|
add_valid_menu_class(0); /* reset */
|
||||||
menu_on_request = -2; /* triggers ALL_CLASSES */
|
menu_on_request = -2; /* triggers ALL_CLASSES */
|
||||||
used |= menu_loot(menu_on_request, current_container, TRUE) > 0;
|
used |= menu_loot(menu_on_request, TRUE) > 0;
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
default:
|
default:
|
||||||
@@ -2270,7 +2269,7 @@ ask_again2:
|
|||||||
#endif
|
#endif
|
||||||
add_valid_menu_class(0); /* reset */
|
add_valid_menu_class(0); /* reset */
|
||||||
if (flags.menu_style != MENU_TRADITIONAL) {
|
if (flags.menu_style != MENU_TRADITIONAL) {
|
||||||
used |= menu_loot(0, current_container, TRUE) > 0;
|
used |= menu_loot(0, TRUE) > 0;
|
||||||
} else {
|
} else {
|
||||||
/* traditional code */
|
/* traditional code */
|
||||||
menu_on_request = 0;
|
menu_on_request = 0;
|
||||||
@@ -2285,8 +2284,7 @@ ask_again2:
|
|||||||
in_container, ck_bag, 0, "nodot");
|
in_container, ck_bag, 0, "nodot");
|
||||||
used = 1;
|
used = 1;
|
||||||
} else if (menu_on_request < 0) {
|
} else if (menu_on_request < 0) {
|
||||||
used |= menu_loot(menu_on_request,
|
used |= menu_loot(menu_on_request, TRUE) > 0;
|
||||||
current_container, TRUE) > 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2303,17 +2301,16 @@ ask_again2:
|
|||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loot a container (take things out, put things in), using a menu. */
|
/* Loot current_container (take things out, put things in), using a menu. */
|
||||||
STATIC_OVL int
|
STATIC_OVL int
|
||||||
menu_loot(retry, container, put_in)
|
menu_loot(retry, put_in)
|
||||||
int retry;
|
int retry;
|
||||||
struct obj *container;
|
|
||||||
boolean put_in;
|
boolean put_in;
|
||||||
{
|
{
|
||||||
int n, i, n_looted = 0;
|
int n, i, n_looted = 0;
|
||||||
boolean all_categories = TRUE, loot_everything = FALSE;
|
boolean all_categories = TRUE, loot_everything = FALSE;
|
||||||
char buf[BUFSZ];
|
char buf[BUFSZ];
|
||||||
const char *takeout = "Take out", *putin = "Put in";
|
const char *action = put_in ? "Put in" : "Take out";
|
||||||
struct obj *otmp, *otmp2;
|
struct obj *otmp, *otmp2;
|
||||||
menu_item *pick_list;
|
menu_item *pick_list;
|
||||||
int mflags, res;
|
int mflags, res;
|
||||||
@@ -2323,10 +2320,10 @@ boolean put_in;
|
|||||||
all_categories = (retry == -2);
|
all_categories = (retry == -2);
|
||||||
} else if (flags.menu_style == MENU_FULL) {
|
} else if (flags.menu_style == MENU_FULL) {
|
||||||
all_categories = FALSE;
|
all_categories = FALSE;
|
||||||
Sprintf(buf,"%s what type of objects?", put_in ? putin : takeout);
|
Sprintf(buf, "%s what type of objects?", action);
|
||||||
mflags = put_in ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN :
|
mflags = put_in ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN :
|
||||||
ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN;
|
ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN;
|
||||||
n = query_category(buf, put_in ? invent : container->cobj,
|
n = query_category(buf, put_in ? invent : current_container->cobj,
|
||||||
mflags, &pick_list, PICK_ANY);
|
mflags, &pick_list, PICK_ANY);
|
||||||
if (!n) return 0;
|
if (!n) return 0;
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
@@ -2341,8 +2338,8 @@ boolean put_in;
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (loot_everything) {
|
if (loot_everything) {
|
||||||
container->cknown = 1;
|
current_container->cknown = 1;
|
||||||
for (otmp = container->cobj; otmp; otmp = otmp2) {
|
for (otmp = current_container->cobj; otmp; otmp = otmp2) {
|
||||||
otmp2 = otmp->nobj;
|
otmp2 = otmp->nobj;
|
||||||
res = out_container(otmp);
|
res = out_container(otmp);
|
||||||
if (res < 0) break;
|
if (res < 0) break;
|
||||||
@@ -2350,9 +2347,9 @@ boolean put_in;
|
|||||||
} else {
|
} else {
|
||||||
mflags = INVORDER_SORT;
|
mflags = INVORDER_SORT;
|
||||||
if (put_in && flags.invlet_constant) mflags |= USE_INVLET;
|
if (put_in && flags.invlet_constant) mflags |= USE_INVLET;
|
||||||
if (takeout) container->cknown = 1;
|
if (!put_in) current_container->cknown = 1;
|
||||||
Sprintf(buf,"%s what?", put_in ? putin : takeout);
|
Sprintf(buf, "%s what?", action);
|
||||||
n = query_objlist(buf, put_in ? invent : container->cobj,
|
n = query_objlist(buf, put_in ? invent : current_container->cobj,
|
||||||
mflags, &pick_list, PICK_ANY,
|
mflags, &pick_list, PICK_ANY,
|
||||||
all_categories ? allow_all : allow_category);
|
all_categories ? allow_all : allow_category);
|
||||||
if (n) {
|
if (n) {
|
||||||
@@ -2366,7 +2363,11 @@ boolean put_in;
|
|||||||
}
|
}
|
||||||
res = put_in ? in_container(otmp) : out_container(otmp);
|
res = put_in ? in_container(otmp) : out_container(otmp);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
if (otmp != pick_list[i].item.a_obj) {
|
if (!current_container) {
|
||||||
|
/* otmp caused current_container to explode;
|
||||||
|
both are now gone */
|
||||||
|
otmp = 0; /* and break loop */
|
||||||
|
} else if (otmp && otmp != pick_list[i].item.a_obj) {
|
||||||
/* split occurred, merge again */
|
/* split occurred, merge again */
|
||||||
(void) merged(&pick_list[i].item.a_obj, &otmp);
|
(void) merged(&pick_list[i].item.a_obj, &otmp);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user