diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 7e8b6bb5c..7d0f52210 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -438,6 +438,10 @@ magic mapping performed while engulfed or underwater would display whole map but then not switch back to the engulfed or underwater restricted view #overview used hardcoded bold and inverse for highlighting; switch to the 'menu_headings' option value so player has some control +for menustyle:full, the 'A' menu choice to auto-select everything now only + does so if no other choices have been picked; when any have (object + class or BUCX state or both), it auto-selects every item that matches + those choices (so still skips the second menu) rather than every item Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/do.c b/src/do.c index 647225519..74333dd89 100644 --- a/src/do.c +++ b/src/do.c @@ -819,8 +819,7 @@ menu_drop(int retry) long cnt; struct obj *otmp, *otmp2; menu_item *pick_list; - boolean all_categories = TRUE; - boolean drop_everything = FALSE; + boolean all_categories = TRUE, drop_everything = FALSE, autopick = FALSE; if (retry) { all_categories = (retry == -2); @@ -834,12 +833,14 @@ menu_drop(int retry) if (!n) goto drop_done; for (i = 0; i < n; i++) { - if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) + if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) { all_categories = TRUE; - else if (pick_list[i].item.a_int == 'A') - drop_everything = TRUE; - else + } else if (pick_list[i].item.a_int == 'A') { + drop_everything = autopick = TRUE; + } else { add_valid_menu_class(pick_list[i].item.a_int); + drop_everything = FALSE; + } } free((genericptr_t) pick_list); } else if (flags.menu_style == MENU_COMBINATION) { @@ -856,7 +857,7 @@ menu_drop(int retry) } } - if (drop_everything) { + if (autopick) { /* * Dropping a burning potion of oil while levitating can cause * an explosion which might destroy some of hero's inventory, @@ -870,10 +871,16 @@ menu_drop(int retry) * Use the bypass bit to mark items already processed (hence * not droppable) and rescan inventory until no unbypassed * items remain. + * + * FIXME? if something explodes, or even breaks, we probably + * ought to halt the traversal or perhaps ask player whether + * to halt it. */ bypass_objlist(g.invent, FALSE); /* clear bypass bit for invent */ - while ((otmp = nxt_unbypassed_obj(g.invent)) != 0) - n_dropped += drop(otmp); + while ((otmp = nxt_unbypassed_obj(g.invent)) != 0) { + if (drop_everything || all_categories || allow_category(otmp)) + n_dropped += drop(otmp); + } /* we might not have dropped everything (worn armor, welded weapon, cursed loadstones), so reset any remaining inventory to normal */ bypass_objlist(g.invent, FALSE); diff --git a/src/invent.c b/src/invent.c index 5710fadc9..7a4c118e5 100644 --- a/src/invent.c +++ b/src/invent.c @@ -289,14 +289,15 @@ loot_xname(struct obj *obj) return res; } +/* '$'==1, 'a'-'z'==2..27, 'A'-'Z'==28..53, '#'==54, catchall 55 */ static int invletter_value(char c) { return ('a' <= c && c <= 'z') ? (c - 'a' + 2) - : ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26) - : (c == '$') ? 1 - : (c == '#') ? 1 + 52 + 1 - : 1 + 52 + 1 + 1; /* none of the above */ + : ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26) + : (c == '$') ? 1 + : (c == '#') ? 1 + 52 + 1 + : 1 + 52 + 1 + 1; /* none of the above (shouldn't happen) */ } /* qsort comparison routine for sortloot() */ @@ -467,10 +468,11 @@ sortloot_cmp(const genericptr vptr1, const genericptr vptr2) * instead of simple 'struct obj *' entries. */ Loot * -sortloot(struct obj **olist, /* previous version might have changed *olist, we don't */ - unsigned mode, /* flags for sortloot_cmp() */ - boolean by_nexthere, /* T: traverse via obj->nexthere, F: via obj->nobj */ - boolean (*filterfunc)(OBJ_P)) +sortloot( + struct obj **olist, /* old version might have changed *olist, we don't */ + unsigned mode, /* flags for sortloot_cmp() */ + boolean by_nexthere, /* T: traverse via obj->nexthere, F: via obj->nobj */ + boolean (*filterfunc)(struct obj *)) /* optional filter */ { Loot *sliarray; struct obj *o; @@ -527,11 +529,12 @@ unsortloot(Loot **loot_array_p) free((genericptr_t) *loot_array_p), *loot_array_p = (Loot *) 0; } -#if 0 /* 3.6.0 'revamp' */ +#if 0 /* 3.6.0 'revamp' -- simpler than current, but ultimately too simple */ void -sortloot(struct obj **olist, unsigned mode, /* flags for sortloot_cmp() */ - boolean by_nexthere) /* T: traverse via obj->nexthere, - F: via obj->nobj */ +sortloot( + struct obj **olist, + unsigned mode, /* flags for sortloot_cmp() */ + boolean by_nexthere) /* T: traverse via obj->nexthere, F: via obj->nobj */ { struct sortloot_item *sliarray, osli, nsli; struct obj *o, **nxt_p; @@ -623,7 +626,7 @@ reorder_invent(void) * isn't nearly as inefficient as it may first appear. */ need_more_sorting = FALSE; - for (otmp = g.invent, prev = 0; otmp;) { + for (otmp = g.invent, prev = 0; otmp; ) { next = otmp->nobj; if (next && inv_rank(next) < inv_rank(otmp)) { need_more_sorting = TRUE; diff --git a/src/pickup.c b/src/pickup.c index 25a860671..d781f2276 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1143,7 +1143,7 @@ query_category(const char *qstr, /* query string */ itemflags = MENU_ITEMFLAGS_SKIPINVERT; add_menu(win, &nul_glyphinfo, &any, invlet, 0, ATR_NONE, (qflags & WORN_TYPES) ? "Auto-select every item being worn" - : "Auto-select every item", + : "Auto-select every relevant item", itemflags); any = cg.zeroany; @@ -2899,7 +2899,7 @@ static int menu_loot(int retry, boolean put_in) { int n, i, n_looted = 0; - boolean all_categories = TRUE, loot_everything = FALSE; + boolean all_categories = TRUE, loot_everything = FALSE, autopick = FALSE; char buf[BUFSZ]; const char *action = put_in ? "Put in" : "Take out"; struct obj *otmp, *otmp2; @@ -2918,30 +2918,41 @@ menu_loot(int retry, boolean put_in) if (!n) return 0; for (i = 0; i < n; i++) { - if (pick_list[i].item.a_int == 'A') - loot_everything = TRUE; - else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) + if (pick_list[i].item.a_int == 'A') { + loot_everything = autopick = TRUE; + } else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) { all_categories = TRUE; - else + } else { add_valid_menu_class(pick_list[i].item.a_int); + loot_everything = FALSE; + } } free((genericptr_t) pick_list); } - if (loot_everything) { + if (autopick) { + int (*inout_func)(struct obj *); /* in_container or out_container */ + struct obj *firstobj; + if (!put_in) { g.current_container->cknown = 1; - for (otmp = g.current_container->cobj; otmp; otmp = otmp2) { - otmp2 = otmp->nobj; - res = out_container(otmp); - if (res < 0) - break; - n_looted += res; - } + inout_func = out_container; + firstobj = g.current_container->cobj; } else { - for (otmp = g.invent; otmp && g.current_container; otmp = otmp2) { - otmp2 = otmp->nobj; - res = in_container(otmp); + inout_func = in_container; + firstobj = g.invent; + } + /* + * Note: for put_in, current_container might be destroyed during + * mid-traversal by a magic bag explosion. + * Note too: items are processed in internal list order rather + * than menu display order ('sortpack') or 'sortloot' order; + * for put_in that should be item->invlet order so reasonable. + */ + for (otmp = firstobj; otmp && g.current_container; otmp = otmp2) { + otmp2 = otmp->nobj; + if (loot_everything || all_categories || allow_category(otmp)) { + res = (*inout_func)(otmp); if (res < 0) break; n_looted += res;