diff --git a/include/extern.h b/include/extern.h index a85f5ce4e..bf0faf578 100644 --- a/include/extern.h +++ b/include/extern.h @@ -891,8 +891,7 @@ E int NDECL(midnight); /* ### invent.c ### */ -E struct obj **FDECL(objarr_init, (int)); -E void FDECL(objarr_set, (struct obj *, int, struct obj **, BOOLEAN_P)); +E void FDECL(sortloot, (struct obj **, unsigned, BOOLEAN_P)); E void FDECL(assigninvlet, (struct obj *)); E struct obj *FDECL(merge_choice, (struct obj *, struct obj *)); E int FDECL(merged, (struct obj **, struct obj **)); @@ -1755,10 +1754,10 @@ E int FDECL(out_container, (struct obj *)); #endif E int FDECL(pickup, (int)); E int FDECL(pickup_object, (struct obj *, long, BOOLEAN_P)); -E int FDECL(query_category, - (const char *, struct obj *, int, menu_item **, int)); -E int FDECL(query_objlist, (const char *, struct obj *, int, menu_item **, - int, boolean (*)(OBJ_P))); +E int FDECL(query_category, (const char *, struct obj *, int, + menu_item **, int)); +E int FDECL(query_objlist, (const char *, struct obj **, int, + menu_item **, int, boolean (*)(OBJ_P))); E struct obj *FDECL(pick_obj, (struct obj *)); E int NDECL(encumber_msg); E int NDECL(doloot); diff --git a/include/hack.h b/include/hack.h index 816b7fee0..9054e0cf1 100644 --- a/include/hack.h +++ b/include/hack.h @@ -318,8 +318,13 @@ NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */ #define BASICENLIGHTENMENT 1 /* show mundane stuff */ #define MAGICENLIGHTENMENT 2 /* show intrinsics and such */ #define ENL_GAMEINPROGRESS 0 -#define ENL_GAMEOVERALIVE 1 /* ascension, escape, quit, trickery */ -#define ENL_GAMEOVERDEAD 2 +#define ENL_GAMEOVERALIVE 1 /* ascension, escape, quit, trickery */ +#define ENL_GAMEOVERDEAD 2 + +/* control flags for sortloot() */ +#define SORTLOOT_PACK 0x01 +#define SORTLOOT_INVLET 0x02 +#define SORTLOOT_LOOT 0x04 /* Macros for messages referring to hands, eyes, feet, etc... */ #define ARM 0 diff --git a/include/obj.h b/include/obj.h index d03aec2ec..a511e1cf6 100644 --- a/include/obj.h +++ b/include/obj.h @@ -40,12 +40,13 @@ struct obj { unsigned owt; long quan; /* number of items */ - schar spe; /* quality of weapon, armor or ring (+ or -) - number of charges for wand ( >= -1 ) - marks your eggs, tin variety and spinach tins - royal coffers for a court ( == 2) - tells which fruit a fruit is - special for uball and amulet + schar spe; /* quality of weapon, armor or ring (+ or -); + number of charges for wand or charged tool ( >= -1 ); + marks your eggs, tin variety and spinach tins; + Schroedinger's Box (1) or royal coffers for a court (2); + tells which fruit a fruit is; + special for uball and amulet; + scroll of mail (normal==0, bones or wishing==1, written==2); historic and gender for statues */ #define STATUE_HISTORIC 0x01 #define STATUE_MALE 0x02 diff --git a/src/do.c b/src/do.c index f6058eabd..734324821 100644 --- a/src/do.c +++ b/src/do.c @@ -813,8 +813,8 @@ int retry; bypass_objlist(invent, FALSE); } else { /* should coordinate with perm invent, maybe not show worn items */ - n = query_objlist("What would you like to drop?", invent, - USE_INVLET | INVORDER_SORT, &pick_list, PICK_ANY, + n = query_objlist("What would you like to drop?", &invent, + (USE_INVLET | INVORDER_SORT), &pick_list, PICK_ANY, all_categories ? allow_all : allow_category); if (n > 0) { /* diff --git a/src/do_wear.c b/src/do_wear.c index 1f84aa6d8..9f2f1fb2d 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -2520,9 +2520,9 @@ int retry; all_worn_categories = TRUE; } - n = query_objlist("What do you want to take off?", invent, - SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT, &pick_list, - PICK_ANY, + n = query_objlist("What do you want to take off?", &invent, + (SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT), + &pick_list, PICK_ANY, all_worn_categories ? is_worn : is_worn_by_type); if (n > 0) { for (i = 0; i < n; i++) diff --git a/src/end.c b/src/end.c index 4db37b71b..09e76812a 100644 --- a/src/end.c +++ b/src/end.c @@ -1329,9 +1329,6 @@ struct obj *list; boolean identified, all_containers, reportempty; { register struct obj *box, *obj; - struct obj **oarray; - int i, n; - char *invlet; char buf[BUFSZ]; boolean cat, deadcat; @@ -1355,43 +1352,24 @@ boolean identified, all_containers, reportempty; } else if (box->cobj) { winid tmpwin = create_nhwindow(NHW_MENU); - /* count the number of items */ - for (n = 0, obj = box->cobj; obj; obj = obj->nobj) - n++; - /* Make a temporary array to store the objects sorted */ - oarray = objarr_init(n); - - /* Add objects to the array */ - i = 0; - invlet = flags.inv_order; - nextclass: - for (obj = box->cobj; obj; obj = obj->nobj) { - if (!flags.sortpack || obj->oclass == *invlet) { - objarr_set( - obj, i++, oarray, - (flags.sortloot == 'f' || flags.sortloot == 'l')); - } - } /* for loop */ - if (flags.sortpack) { - if (*++invlet) - goto nextclass; - } - + sortloot(&box->cobj, + (((flags.sortloot == 'l' || flags.sortloot == 'f') + ? SORTLOOT_LOOT : 0) + | (flags.sortpack ? SORTLOOT_PACK : 0)), + FALSE); Sprintf(buf, "Contents of %s:", the(xname(box))); putstr(tmpwin, 0, buf); putstr(tmpwin, 0, ""); - for (i = 0; i < n; i++) { - obj = oarray[i]; + for (obj = box->cobj; obj; obj = obj->nobj) { if (identified) { makeknown(obj->otyp); - obj->known = obj->bknown = obj->dknown = obj->rknown = - 1; + obj->known = obj->bknown = obj->dknown + = obj->rknown = 1; if (Is_container(obj) || obj->otyp == STATUE) obj->cknown = obj->lknown = 1; } putstr(tmpwin, 0, doname(obj)); } - free(oarray); if (cat) putstr(tmpwin, 0, "Schroedinger's cat"); else if (deadcat) diff --git a/src/invent.c b/src/invent.c index 103ee9580..37937b6cf 100644 --- a/src/invent.c +++ b/src/invent.c @@ -8,7 +8,8 @@ #define CONTAINED_SYM '>' /* designator for inside a container */ #define HANDS_SYM '-' -STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (struct obj *, struct obj *)); +STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (const genericptr, + const genericptr)); STATIC_DCL void NDECL(reorder_invent); STATIC_DCL void FDECL(noarmor, (BOOLEAN_P)); STATIC_DCL void FDECL(invdisp_nothing, (const char *, const char *)); @@ -25,8 +26,8 @@ STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *)); STATIC_DCL char FDECL(display_pickinv, (const char *, const char *, BOOLEAN_P, long *)); STATIC_DCL char FDECL(display_used_invlets, (CHAR_P)); -STATIC_DCL void FDECL(tally_BUCX, - (struct obj *, int *, int *, int *, int *, int *)); +STATIC_DCL void FDECL(tally_BUCX, (struct obj *, + int *, int *, int *, int *, int *)); STATIC_DCL boolean FDECL(this_type_only, (struct obj *)); STATIC_DCL void NDECL(dounpaid); STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **)); @@ -47,96 +48,187 @@ static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */ */ static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */ +struct sortloot_item { + struct obj *obj; + int indx; +}; +unsigned sortlootmode = 0; + +/* qsort comparison routine for sortloot() */ STATIC_OVL int CFDECLSPEC -sortloot_cmp(obj1, obj2) -struct obj *obj1; -struct obj *obj2; +sortloot_cmp(vptr1, vptr2) +const genericptr vptr1; +const genericptr vptr2; { - int val1 = 0; - int val2 = 0; + struct sortloot_item *sli1 = (struct sortloot_item *) vptr1, + *sli2 = (struct sortloot_item *) vptr2; + struct obj *obj1 = sli1->obj, + *obj2 = sli2->obj; + char *cls1, *cls2; + int val1, val2, c, namcmp; + + /* order by object class like inventory display */ + if ((sortlootmode & SORTLOOT_PACK) != 0) { + cls1 = index(flags.inv_order, obj1->oclass); + cls2 = index(flags.inv_order, obj2->oclass); + if (cls1 != cls2) + return (int) (cls1 - cls2); + + /* for armor, group by sub-category */ + if (obj1->oclass == ARMOR_CLASS) { + static int armcat[7 + 1]; + + if (!armcat[7]) { + /* one-time init; we want to control the order */ + armcat[ARM_HELM] = 1; /* [2] */ + armcat[ARM_GLOVES] = 2; /* [3] */ + armcat[ARM_BOOTS] = 3; /* [4] */ + armcat[ARM_SHIELD] = 4; /* [1] */ + armcat[ARM_CLOAK] = 5; /* [5] */ + armcat[ARM_SHIRT] = 6; /* [6] */ + armcat[ARM_SUIT] = 7; /* [0] */ + armcat[7] = 8; + } + val1 = armcat[objects[obj1->otyp].oc_armcat]; + val2 = armcat[objects[obj2->otyp].oc_armcat]; + if (val1 != val2) + return val1 - val2; + + /* for weapons, group by ammo (arrows, bolts), launcher (bows), + missile (dart, boomerang), stackable (daggers, knives, spears), + 'other' (swords, axes, &c), polearm */ + } else if (obj1->oclass == WEAPON_CLASS) { + val1 = objects[obj1->otyp].oc_skill; + val1 = (val1 < 0) + ? (val1 >= -P_CROSSBOW && val1 <= -P_BOW) ? 1 : 3 + : (val1 >= P_BOW && val1 <= P_CROSSBOW) ? 2 + : (val1 == P_SPEAR || val1 == P_DAGGER + || val1 == P_KNIFE) ? 4 : !is_pole(obj1) ? 5 : 6; + val2 = objects[obj2->otyp].oc_skill; + val2 = (val2 < 0) + ? (val2 >= -P_CROSSBOW && val2 <= -P_BOW) ? 1 : 3 + : (val2 >= P_BOW && val2 <= P_CROSSBOW) ? 2 + : (val2 == P_SPEAR || val2 == P_DAGGER + || val2 == P_KNIFE) ? 4 : !is_pole(obj2) ? 5 : 6; + if (val1 != val2) + return val1 - val2; + } + } + + /* order by assigned inventory letter */ + if ((sortlootmode & SORTLOOT_INVLET) != 0) { + c = obj1->invlet; + val1 = ('a' <= c && c <= 'z') ? (c - 'a' + 2) + : ('A' <= c && c <= 'Z') ? (c - 'Z' + 2 + 26) + : (c == '$') ? 1 + : (c == '#') ? 1 + 52 + 1 + : 1 + 52 + 1 + 1; /* none of the above */ + c = obj2->invlet; + val2 = ('a' <= c <= 'z') ? (c - 'a' + 2) + : ('A' <= c <= 'Z') ? (c - 'Z' + 2 + 26) + : (c == '$') ? 1 + : (c == '#') ? 1 + 52 + 1 + : 1 + 52 + 1 + 1; /* none of the above */ + if (val1 != val2) + return val1 - val2; + } + + if ((sortlootmode & SORTLOOT_LOOT) == 0) + goto tiebreak; /* Sort object names in lexicographical order, ignoring quantity. */ - int name_cmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2)); + if ((namcmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2))) != 0) + return namcmp; - if (name_cmp != 0) { - return name_cmp; - } - - /* Sort by BUC. Map blessed to 4, uncursed to 2, cursed to 1, and unknown - * to 0. */ + /* Sort by BUCX. Map blessed to 4, uncursed to 2, cursed to 1, and + unknown to 0. */ val1 = obj1->bknown - ? (obj1->blessed << 2) - + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed - : 0; + ? (obj1->blessed << 2) + + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed + : 0; val2 = obj2->bknown - ? (obj2->blessed << 2) - + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed - : 0; - if (val1 != val2) { - return val2 - val1; /* Because bigger is better. */ - } + ? (obj2->blessed << 2) + + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed + : 0; + if (val1 != val2) + return val2 - val1; /* bigger is better */ - /* Sort by greasing. This will put the objects in degreasing order. */ + /* Sort by greasing. This will put the objects in degreasing order. */ val1 = obj1->greased; val2 = obj2->greased; - if (val1 != val2) { - return val2 - val1; /* Because bigger is better. */ - } + if (val1 != val2) + return val2 - val1; /* bigger is better */ - /* Sort by erosion. The effective amount is what matters. */ + /* Sort by erosion. The effective amount is what matters. */ val1 = greatest_erosion(obj1); val2 = greatest_erosion(obj2); - if (val1 != val2) { - return val1 - val2; /* Because bigger is WORSE. */ - } + if (val1 != val2) + return val1 - val2; /* bigger is WORSE */ - /* Sort by erodeproofing. Map known-invulnerable to 1, and both - * known-vulnerable and unknown-vulnerability to 0, because that's how - * they're displayed. */ + /* Sort by erodeproofing. Map known-invulnerable to 1, and both + known-vulnerable and unknown-vulnerability to 0, because that's + how they're displayed. */ val1 = obj1->rknown && obj1->oerodeproof; val2 = obj2->rknown && obj2->oerodeproof; - if (val1 != val2) { - return val2 - val1; /* Because bigger is better. */ + if (val1 != val2) + return val2 - val1; /* bigger is better */ + + /* Sort by enchantment. Map unknown to -1000, which is comfortably + below the range of obj->spe. oc_uses_known means that obj->known + matters, which usually indirectly means that obj->spe is relevant. + Lots of objects use obj->spe for some other purpose (see obj.h). */ + if (objects[obj1->otyp].oc_uses_known + /* exclude eggs (laid by you) and tins (homemade, pureed, &c) */ + && obj1->oclass != FOOD_CLASS) { + val1 = obj1->known ? obj1->spe : -1000; + val2 = obj2->known ? obj2->spe : -1000; + if (val1 != val2) + return val2 - val1; /* bigger is better */ } - /* Sort by enchantment. Map unknown to -1000, which is comfortably below - * the range of ->spe. */ - val1 = obj1->known ? obj1->spe : -1000; - val2 = obj2->known ? obj2->spe : -1000; - if (val1 != val2) { - return val2 - val1; /* Because bigger is better. */ - } - - /* They're identical, as far as we're concerned, - but we want to force a determistic order between them. */ - return (obj1->o_id > obj2->o_id) ? 1 : -1; -} - -struct obj ** -objarr_init(n) -int n; -{ - return (struct obj **) alloc(n * sizeof(struct obj *)); +tiebreak: + /* They're identical, as far as we're concerned. We want + to force a deterministic order, and do so by producing a + stable sort: maintain the original order of equal items. */ + return (sli2->indx - sli1->indx); } void -objarr_set(otmp, idx, oarray, dosort) -struct obj *otmp; -int idx; -struct obj **oarray; -boolean dosort; +sortloot(olist, mode, by_nexthere) +struct obj **olist; +unsigned mode; /* flags for sortloot_cmp() */ +boolean by_nexthere; /* T: traverse via obj->nexthere, F: via obj->nobj */ { - if (dosort) { - int j; - for (j = idx; j; j--) { - if (sortloot_cmp(otmp, oarray[j - 1]) > 0) - break; - oarray[j] = oarray[j - 1]; - } - oarray[j] = otmp; - } else { - oarray[idx] = otmp; + struct sortloot_item *sliarray, osli, nsli; + struct obj *o, **nxt_p; + unsigned n, i; + boolean already_sorted = TRUE; + + sortlootmode = mode; /* extra input for sortloot_cmp() */ + for (n = osli.indx = 0, osli.obj = *olist; (o = osli.obj) != 0; + osli = nsli) { + nsli.obj = by_nexthere ? o->nexthere : o->nobj; + nsli.indx = (int) ++n; + if (nsli.obj && already_sorted + && sortloot_cmp((genericptr_t) &osli, (genericptr_t) &nsli) > 0) + already_sorted = FALSE; } + if (n > 1 && !already_sorted) { + sliarray = (struct sortloot_item *) alloc(n * sizeof *sliarray); + for (i = 0, o = *olist; o; + ++i, o = by_nexthere ? o->nexthere : o->nobj) + sliarray[i].obj = o, sliarray[i].indx = (int) i; + + qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp); + for (i = 0; i < n; ++i) { + o = sliarray[i].obj; + nxt_p = by_nexthere ? &(o->nexthere) : &(o->nobj); + *nxt_p = (i < n - 1) ? sliarray[i + 1].obj : (struct obj *) 0; + } + *olist = sliarray[0].obj; + free((genericptr_t) sliarray); + } + sortlootmode = 0; } void @@ -1783,8 +1875,8 @@ int id_limit; while (id_limit) { Sprintf(buf, "What would you like to identify %s?", first ? "first" : "next"); - n = query_objlist(buf, invent, SIGNAL_NOMENU | SIGNAL_ESCAPE - | USE_INVLET | INVORDER_SORT, + n = query_objlist(buf, &invent, (SIGNAL_NOMENU | SIGNAL_ESCAPE + | USE_INVLET | INVORDER_SORT), &pick_list, PICK_ANY, not_fully_identified); if (n > 0) { @@ -2021,11 +2113,10 @@ long *out_cnt; struct obj *otmp; char ilet, ret; char *invlet = flags.inv_order; - int i, n, classcount; + int n, classcount; winid win; /* windows being used */ anything any; menu_item *selected; - struct obj **oarray; if (flags.perm_invent && ((lets && *lets) || xtra_choice)) { /* partial inventory in perm_invent setting; don't operate on @@ -2096,19 +2187,10 @@ long *out_cnt; return ret; } - /* count the number of items (preliminary count of 0,1,more was 'more' - and is now obsolete); we have at least 2 items or want to behave as - if we do (full invent and wiz_identify use this even for 1 item) */ - for (n = 0, otmp = invent; otmp; otmp = otmp->nobj) - if (!lets || !*lets || index(lets, otmp->invlet)) - n++; - oarray = objarr_init(n); - /* Add objects to the array */ - i = 0; - for (otmp = invent; otmp; otmp = otmp->nobj) - if (!lets || !*lets || index(lets, otmp->invlet)) { - objarr_set(otmp, i++, oarray, (flags.sortloot == 'f')); - } + sortloot(&invent, + (((flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET) + | (flags.sortpack ? SORTLOOT_PACK : 0)), + FALSE); start_menu(win); any = zeroany; @@ -2133,8 +2215,7 @@ long *out_cnt; } nextclass: classcount = 0; - for (i = 0; i < n; i++) { - otmp = oarray[i]; + for (otmp = invent; otmp; otmp = otmp->nobj) { if (!flags.sortpack || otmp->oclass == *invlet) { any = zeroany; /* all bits zero */ ilet = otmp->invlet; @@ -2158,7 +2239,6 @@ nextclass: goto nextclass; } } - free(oarray); end_menu(win, (char *) 0); n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected); @@ -2627,9 +2707,9 @@ dotypeinv() } this_type = oclass; } - if (query_objlist((char *) 0, invent, - (flags.invlet_constant ? USE_INVLET : 0) - | INVORDER_SORT, + if (query_objlist((char *) 0, &invent, + ((flags.invlet_constant ? USE_INVLET : 0) + | INVORDER_SORT), &pick_list, PICK_NONE, this_type_only) > 0) free((genericptr_t) pick_list); return 0; @@ -3619,8 +3699,8 @@ char *title; */ youmonst.data = mon->data; - n = query_objlist(title ? title : tmp, mon->minvent, - INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0), + n = query_objlist(title ? title : tmp, &(mon->minvent), + (INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0)), &selected, (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE, do_all ? allow_all : worn_wield_only); @@ -3656,8 +3736,8 @@ register struct obj *obj; "that"); if (obj->cobj) { - n = query_objlist(qbuf, obj->cobj, INVORDER_SORT, &selected, - PICK_NONE, allow_all); + n = query_objlist(qbuf, &(obj->cobj), INVORDER_SORT, + &selected, PICK_NONE, allow_all); } else { invdisp_nothing(qbuf, "(empty)"); n = 0; @@ -3707,8 +3787,9 @@ boolean as_if_seen; if (n) { only.x = x; only.y = y; - if (query_objlist("Things that are buried here:", level.buriedobjlist, - INVORDER_SORT, &selected, PICK_NONE, only_here) > 0) + if (query_objlist("Things that are buried here:", + &level.buriedobjlist, INVORDER_SORT, + &selected, PICK_NONE, only_here) > 0) free((genericptr_t) selected); only.x = only.y = 0; } diff --git a/src/pickup.c b/src/pickup.c index 38c7aeea7..39effd261 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -11,9 +11,9 @@ #define CONTAINED_SYM '>' /* from invent.c */ STATIC_DCL void FDECL(simple_look, (struct obj *, BOOLEAN_P)); -STATIC_DCL boolean -FDECL(query_classes, (char *, boolean *, boolean *, const char *, - struct obj *, BOOLEAN_P, int *)); +STATIC_DCL boolean FDECL(query_classes, (char *, boolean *, boolean *, + const char *, struct obj *, + BOOLEAN_P, int *)); STATIC_DCL boolean FDECL(fatal_corpse_mistake, (struct obj *, BOOLEAN_P)); STATIC_DCL void FDECL(check_here, (BOOLEAN_P)); STATIC_DCL boolean FDECL(n_or_more, (struct obj *)); @@ -47,7 +47,7 @@ STATIC_DCL void FDECL(tipcontainer, (struct obj *)); /* define for query_objlist() and autopickup() */ #define FOLLOW(curr, flags) \ - (((flags) &BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj) + (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj) /* * How much the weight of the given container will change when the given @@ -62,9 +62,9 @@ STATIC_DCL void FDECL(tipcontainer, (struct obj *)); /* if you can figure this out, give yourself a hearty pat on the back... */ #define GOLD_CAPACITY(w, n) (((w) * -100L) - ((n) + 50L) - 1L) -/* A variable set in use_container(), to be used by the callback routines */ -/* in_container() and out_container() from askchain() and use_container(). */ -/* Also used by menu_loot() and container_gone(). */ +/* A variable set in use_container(), to be used by the callback routines + in_container() and out_container() from askchain() and use_container(). + Also used by menu_loot() and container_gone(). */ static NEARDATA struct obj *current_container; static NEARDATA boolean abort_looting; #define Icebox (current_container->otyp == ICE_BOX) @@ -221,9 +221,7 @@ int *menu_on_demand; oclasses[oclassct] = '\0'; } else { if (!where) - where = - !strcmp(action, "pick up") - ? "here" + where = !strcmp(action, "pick up") ? "here" : !strcmp(action, "take out") ? "inside" : ""; if (*where) There("are no %c's %s.", sym, where); @@ -384,6 +382,7 @@ struct obj *obj; if (Role_if(PM_PRIEST)) obj->bknown = TRUE; + /* * There are three types of filters possible and the first and * third can have more than one entry: @@ -400,6 +399,7 @@ struct obj *obj; * in accepting all scrolls and potions regardless of bless/curse * state plus all blessed non-scroll, non-potion objects.) */ + /* if class is expected but obj's class is not in the list, reject */ if (class_filter && !index(valid_menu_classes, obj->oclass)) return FALSE; @@ -481,7 +481,8 @@ int what; /* should be a long */ count = 0; if (!u.uswallow) { - struct trap *ttmp = t_at(u.ux, u.uy); + struct trap *ttmp; + /* no auto-pick if no-pick move, nothing there, or in a pool */ if (autopickup && (context.nopick || !OBJ_AT(u.ux, u.uy) || (is_pool(u.ux, u.uy) && !Underwater) @@ -489,11 +490,11 @@ int what; /* should be a long */ read_engr_at(u.ux, u.uy); return 0; } - /* no pickup if levitating & not on air or water level */ if (!can_reach_floor(TRUE)) { if ((multi && !context.run) || (autopickup && !flags.pickup) - || (ttmp && uteetering_at_seen_pit(ttmp))) + || ((ttmp = t_at(u.ux, u.uy)) != 0 + && uteetering_at_seen_pit(ttmp))) read_engr_at(u.ux, u.uy); return 0; } @@ -540,21 +541,20 @@ int what; /* should be a long */ if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) { /* use menus exclusively */ + traverse_how |= AUTOSELECT_SINGLE | INVORDER_SORT; if (count) { /* looking for N of something */ char qbuf[QBUFSZ]; Sprintf(qbuf, "Pick %d of what?", count); val_for_n_or_more = count; /* set up callback selector */ - n = query_objlist(qbuf, objchain, traverse_how | AUTOSELECT_SINGLE - | INVORDER_SORT, + n = query_objlist(qbuf, &objchain, traverse_how, &pick_list, PICK_ONE, n_or_more); /* correct counts, if any given */ for (i = 0; i < n; i++) pick_list[i].count = count; } else { - n = query_objlist("Pick up what?", objchain, - traverse_how | AUTOSELECT_SINGLE | INVORDER_SORT - | FEEL_COCKATRICE, + n = query_objlist("Pick up what?", &objchain, + (traverse_how | FEEL_COCKATRICE), &pick_list, PICK_ANY, all_but_uchain); } menu_pickup: @@ -582,8 +582,7 @@ int what; /* should be a long */ selective = FALSE; /* ask for each item */ /* check for more than one object */ - for (obj = objchain; obj; - obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj) + for (obj = objchain; obj; obj = FOLLOW(obj, traverse_how)) ct++; if (ct == 1 && count) { @@ -601,12 +600,13 @@ int what; /* should be a long */ There("are %s objects here.", (ct <= 10) ? "several" : "many"); if (!query_classes(oclasses, &selective, &all_of_a_type, "pick up", objchain, - traverse_how == BY_NEXTHERE, &via_menu)) { + (traverse_how & BY_NEXTHERE) ? TRUE : FALSE, + &via_menu)) { if (!via_menu) return 0; - n = query_objlist("Pick up what?", objchain, - traverse_how - | (selective ? 0 : INVORDER_SORT), + if (selective) + traverse_how |= INVORDER_SORT; + n = query_objlist("Pick up what?", &objchain, traverse_how, &pick_list, PICK_ANY, (via_menu == -2) ? allow_all : allow_category); @@ -615,15 +615,11 @@ int what; /* should be a long */ } for (obj = objchain; obj; obj = obj2) { - if (traverse_how == BY_NEXTHERE) - obj2 = obj->nexthere; /* perhaps obj will be picked up */ - else - obj2 = obj->nobj; - lcount = -1L; - + obj2 = FOLLOW(obj, traverse_how); if (!selective && oclasses[0] && !index(oclasses, obj->oclass)) continue; + lcount = -1L; if (!all_of_a_type) { char qbuf[BUFSZ]; @@ -648,7 +644,7 @@ int what; /* should be a long */ lcount = (long) yn_number; if (lcount > obj->quan) lcount = obj->quan; - /* fall thru */ + /*FALLTHRU*/ default: /* 'y' */ break; } @@ -779,11 +775,12 @@ menu_item **pick_list; /* list of objects and counts to pick up */ * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow". * SIGNAL_ESCAPE - Return -1 rather than 0 if player uses ESC to * pick nothing. + * FEEL_COCKATRICE - touch corpse. */ int -query_objlist(qstr, olist, qflags, pick_list, how, allow) +query_objlist(qstr, olist_p, qflags, pick_list, how, allow) const char *qstr; /* query string */ -struct obj *olist; /* the list to pick from */ +struct obj **olist_p; /* the list to pick from */ int qflags; /* options to control the query */ menu_item **pick_list; /* return list of items picked */ int how; /* type of query */ @@ -791,12 +788,12 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ { int i, n, actualn; winid win; - struct obj *curr, *last, fake_hero_object; - struct obj **oarray; + struct obj *curr, *last, fake_hero_object, *olist = *olist_p; char *pack; anything any; - boolean printed_type_name, sorted = (qflags & INVORDER_SORT) != 0, - engulfer = (qflags & INCLUDE_HERO) != 0; + boolean printed_type_name, + sorted = (qflags & INVORDER_SORT) != 0, + engulfer = (qflags & INCLUDE_HERO) != 0; *pick_list = (menu_item *) 0; if (!olist && !engulfer) @@ -819,27 +816,26 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ return (qflags & SIGNAL_NOMENU) ? -1 : 0; if (n == 1 && (qflags & AUTOSELECT_SINGLE)) { - *pick_list = (menu_item *) alloc(sizeof(menu_item)); + *pick_list = (menu_item *) alloc(sizeof (menu_item)); (*pick_list)->item.a_obj = last; (*pick_list)->count = last->quan; return 1; } - oarray = objarr_init(actualn); - /* Add objects to the array */ - i = 0; - for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { - if ((*allow)(curr)) { - objarr_set(curr, i++, oarray, (flags.sortloot == 'f' - || (flags.sortloot == 'l' - && !(qflags & USE_INVLET)))); - } + if (sorted) { + sortloot(&olist, + (((flags.sortloot == 'f' + || (flags.sortloot == 'l' && !(qflags & USE_INVLET))) + ? SORTLOOT_LOOT + : (qflags & USE_INVLET) ? SORTLOOT_INVLET : 0) + | (flags.sortpack ? SORTLOOT_PACK : 0)), + (qflags & BY_NEXTHERE) ? TRUE : FALSE); + *olist_p = olist; } win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; - /* * Run through the list and add the objects to the menu. If * INVORDER_SORT is set, we'll run through the list once for @@ -849,22 +845,23 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ pack = flags.inv_order; do { printed_type_name = FALSE; - for (i = 0; i < actualn; i++) { - curr = oarray[i]; + for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { + if (sorted && curr->oclass != *pack) + continue; if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE && will_feel_cockatrice(curr, FALSE)) { destroy_nhwindow(win); /* stop the menu and revert */ (void) look_here(0, FALSE); return 0; } - if ((!sorted || curr->oclass == *pack) && (*allow)(curr)) { + if ((*allow)(curr)) { /* if sorting, print type name (once only) */ if (sorted && !printed_type_name) { any = zeroany; add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, let_to_name(*pack, FALSE, - (how != PICK_NONE) - && iflags.menu_head_objsym), + ((how != PICK_NONE) + && iflags.menu_head_objsym)), MENU_UNSELECTED); printed_type_name = TRUE; } @@ -878,7 +875,6 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ } pack++; } while (sorted && *pack); - free(oarray); if (engulfer) { char buf[BUFSZ]; @@ -1656,7 +1652,6 @@ doloot() cc.y = u.uy; lootcont: - if ((num_conts = container_at(cc.x, cc.y, TRUE)) > 0) { boolean anyfound = FALSE; @@ -1875,11 +1870,12 @@ boolean *prev_loot; */ if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) { long unwornmask; + if (passed_info) *passed_info = 1; - Sprintf( - qbuf, "Do you want to remove the saddle from %s?", - x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE, FALSE)); + Sprintf(qbuf, "Do you want to remove the saddle from %s?", + x_monnam(mtmp, ARTICLE_THE, (char *) 0, + SUPPRESS_SADDLE, FALSE)); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { if (nolimbs(youmonst.data)) { You_cant("do that without limbs."); /* not body_part(HAND) */ @@ -1887,8 +1883,8 @@ boolean *prev_loot; } if (otmp->cursed) { You("can't. The saddle seems to be stuck to %s.", - x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE, - FALSE)); + x_monnam(mtmp, ARTICLE_THE, (char *) 0, + SUPPRESS_SADDLE, FALSE)); /* the attempt costs you time */ return 1; } @@ -1907,8 +1903,7 @@ boolean *prev_loot; return 0; } } - /* 3.4.0 introduced the ability to pick things up from within - swallower's stomach */ + /* 3.4.0 introduced ability to pick things up from swallower's stomach */ if (u.uswallow) { int count = passed_info ? *passed_info : 0; @@ -2091,7 +2086,7 @@ int ck_bag(obj) struct obj *obj; { - return current_container && obj != current_container; + return (current_container && obj != current_container); } /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */ @@ -2218,14 +2213,14 @@ struct obj *box; pline("%s inside the box is still alive!", Monnam(livecat)); (void) christen_monst(livecat, sc); } else { - deadcat = - mk_named_object(CORPSE, &mons[PM_HOUSECAT], box->ox, box->oy, sc); + deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT], + box->ox, box->oy, sc); if (deadcat) { obj_extract_self(deadcat); (void) add_to_container(box, deadcat); } pline_The("%s inside the box is dead!", - Hallucination ? rndmonnam(NULL) : "housecat"); + Hallucination ? rndmonnam((char *) 0) : "housecat"); } box->owt = weight(box); return; @@ -2409,14 +2404,14 @@ boolean more_containers; /* True iff #loot multiple and this isn't last one */ (boolean) (used != 0), more_containers); } } else { /* TRADITIONAL or COMBINATION */ - xbuf[0] = '\0'; /* list of extra acceptable responses */ - Strcpy(pbuf, ":"); /* look inside */ + xbuf[0] = '\0'; /* list of extra acceptable responses */ + Strcpy(pbuf, ":"); /* look inside */ Strcat(outmaybe ? pbuf : xbuf, "o"); /* take out */ Strcat(inokay ? pbuf : xbuf, "i"); /* put in */ Strcat(outmaybe ? pbuf : xbuf, "b"); /* both */ Strcat(inokay ? pbuf : xbuf, "rs"); /* reversed, stash */ - Strcat(pbuf, " "); - Strcat(more_containers ? pbuf : xbuf, "n"); + Strcat(pbuf, " "); /* separator */ + Strcat(more_containers ? pbuf : xbuf, "n"); /* next container */ Strcat(pbuf, "q"); /* quit */ if (iflags.cmdassist) /* this unintentionally allows user to answer with 'o' or @@ -2624,7 +2619,7 @@ boolean put_in; if (!put_in) current_container->cknown = 1; Sprintf(buf, "%s what?", action); - n = query_objlist(buf, put_in ? invent : current_container->cobj, + n = query_objlist(buf, put_in ? &invent : &(current_container->cobj), mflags, &pick_list, PICK_ANY, all_categories ? allow_all : allow_category); if (n) {