]> granicus.if.org Git - nethack/commitdiff
'sortloot' revamp
authorPatR <rankin@nethack.org>
Sun, 13 Mar 2016 23:23:38 +0000 (16:23 -0700)
committerPatR <rankin@nethack.org>
Sun, 13 Mar 2016 23:23:38 +0000 (16:23 -0700)
Change the sortloot option to use qsort() instead of naive insertion
sort.  After sorting, it reorders the linked list into the sorted
order, so might have some subtle change(s) in behavior since that
wasn't done before.

pickup.c includes some formatting cleanup.

modified:
  include/extern.h, hack.h, obj.h
  src/do.c, do_wear.c, end.c, invent.c, pickup.c

include/extern.h
include/hack.h
include/obj.h
src/do.c
src/do_wear.c
src/end.c
src/invent.c
src/pickup.c

index a85f5ce4e0879d70f87ef5b0c70a3947a6eca8e2..bf0faf578d07f22f3e35a2790964c2d7153fb62c 100644 (file)
@@ -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);
index 816b7fee02685eb858bf65b846fc74ddf5a42cd8..9054e0cf16bb901de561e0a0ff2f994a3cb020d8 100644 (file)
@@ -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
index d03aec2eca67efe8750b4d1da3629f8af4f046b8..a511e1cf65fc2f3f98ff67e3d939d0cbb273153e 100644 (file)
@@ -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
index f6058eabd1b2ab7e1512f9f7dde38148dd773932..734324821c701af3ada9fbdac95c7b2dfad53a78 100644 (file)
--- 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) {
             /*
index 1f84aa6d8d3efc232ebf6502660ba0070760c609..9f2f1fb2de0fb7ff3052d7b71eaa354a18146b3f 100644 (file)
@@ -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++)
index 4db37b71b5e5d5145fae717c1ec844e17bdc122a..09e76812ab0d3ed0157a4ce33d8529401e44fd12 100644 (file)
--- 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)
index 103ee9580b5a1d6897cc178528ff53a028026284..37937b6cf3467aa164918f0a71395fa41e70f053 100644 (file)
@@ -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) */
 
-STATIC_OVL int CFDECLSPEC
-sortloot_cmp(obj1, obj2)
-struct obj *obj1;
-struct obj *obj2;
-{
-    int val1 = 0;
-    int val2 = 0;
+struct sortloot_item {
+    struct obj *obj;
+    int indx;
+};
+unsigned sortlootmode = 0;
 
-    /* Sort object names in lexicographical order, ignoring quantity. */
-    int name_cmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2));
+/* qsort comparison routine for sortloot() */
+STATIC_OVL int CFDECLSPEC
+sortloot_cmp(vptr1, vptr2)
+const genericptr vptr1;
+const genericptr vptr2;
+{
+    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;
+        }
+    }
 
-    if (name_cmp != 0) {
-        return name_cmp;
+    /* 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;
     }
 
-    /* Sort by BUC. Map blessed to 4, uncursed to 2, cursed to 1, and unknown
-     * to 0. */
+    if ((sortlootmode & SORTLOOT_LOOT) == 0)
+        goto tiebreak;
+
+    /* Sort object names in lexicographical order, ignoring quantity. */
+    if ((namcmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2))) != 0)
+        return namcmp;
+
+    /* 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 ->spe. */
-    val1 = obj1->known ? obj1->spe : -1000;
-    val2 = obj2->known ? obj2->spe : -1000;
-    if (val1 != val2) {
-        return val2 - val1; /* Because 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 */
     }
 
-    /* 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;
-{
-    if (dosort) {
-        int j;
-        for (j = idx; j; j--) {
-            if (sortloot_cmp(otmp, oarray[j - 1]) > 0)
-                break;
-            oarray[j] = oarray[j - 1];
+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 */
+{
+    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;
         }
-        oarray[j] = otmp;
-    } else {
-        oarray[idx] = otmp;
+        *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;
     }
index 38c7aeea75cff65450b0ffb2542f7d9e2281cad1..39effd261cca45228f0c8df7277a5b0a862f175f 100644 (file)
@@ -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) {