OSDN Git Service

upgrade to 3.6.2
[jnethack/source.git] / src / pickup.c
index 5252fce..0d38b97 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 pickup.c        $NHDT-Date: 1516581051 2018/01/22 00:30:51 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.194 $ */
+/* NetHack 3.6 pickup.c        $NHDT-Date: 1545785547 2018/12/26 00:52:27 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.222 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2012. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -29,6 +29,7 @@ STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *));
 #endif
 STATIC_DCL int FDECL(autopick, (struct obj *, int, menu_item **));
 STATIC_DCL int FDECL(count_categories, (struct obj *, int));
+STATIC_DCL int FDECL(delta_cwt, (struct obj *, struct obj *));
 STATIC_DCL long FDECL(carry_count, (struct obj *, struct obj *, long,
                                     BOOLEAN_P, int *, int *));
 STATIC_DCL int FDECL(lift_object, (struct obj *, struct obj *, long *,
@@ -39,7 +40,6 @@ STATIC_PTR int FDECL(in_container, (struct obj *));
 STATIC_PTR int FDECL(out_container, (struct obj *));
 STATIC_DCL void FDECL(removed_from_icebox, (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(explain_container_prompt, (BOOLEAN_P));
 STATIC_DCL int FDECL(traditional_loot, (BOOLEAN_P));
 STATIC_DCL int FDECL(menu_loot, (int, BOOLEAN_P));
@@ -55,15 +55,6 @@ STATIC_DCL void FDECL(tipcontainer, (struct obj *));
 #define FOLLOW(curr, flags) \
     (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
 
-/*
- *  How much the weight of the given container will change when the given
- *  object is removed from it.  This calculation must match the one used
- *  by weight() in mkobj.c.
- */
-#define DELTA_CWT(cont, obj)                                      \
-    ((cont)->cursed ? (obj)->owt * 2 : (cont)->blessed            \
-                                           ? ((obj)->owt + 3) / 4 \
-                                           : ((obj)->owt + 1) / 2)
 #define GOLD_WT(n) (((n) + 50L) / 100L)
 /* if you can figure this out, give yourself a hearty pat on the back... */
 #define GOLD_CAPACITY(w, n) (((w) * -100L) - ((n) + 50L) - 1L)
@@ -625,7 +616,8 @@ int what; /* should be a long */
 
     if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) {
         /* use menus exclusively */
-        traverse_how |= AUTOSELECT_SINGLE | INVORDER_SORT;
+        traverse_how |= AUTOSELECT_SINGLE
+                        | (flags.sortpack ? INVORDER_SORT : 0);
         if (count) { /* looking for N of something */
             char qbuf[QBUFSZ];
 
@@ -928,6 +920,8 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
     boolean printed_type_name, first,
             sorted = (qflags & INVORDER_SORT) != 0,
             engulfer = (qflags & INCLUDE_HERO) != 0;
+    unsigned sortflags;
+    Loot *sortedolist, *srtoli;
 
     *pick_list = (menu_item *) 0;
     if (!olist && !engulfer)
@@ -955,16 +949,14 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
         return 1;
     }
 
-    if (sorted || flags.sortloot != 'n') {
-        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;
-    }
+    sortflags = (((flags.sortloot == 'f'
+                   || (flags.sortloot == 'l' && !(qflags & USE_INVLET)))
+                  ? SORTLOOT_LOOT
+                  : ((qflags & USE_INVLET) ? SORTLOOT_INVLET : 0))
+                 | (flags.sortpack ? SORTLOOT_PACK : 0)
+                 | ((qflags & FEEL_COCKATRICE) ? SORTLOOT_PETRIFY : 0));
+    sortedolist = sortloot(&olist, sortflags,
+                           (qflags & BY_NEXTHERE) ? TRUE : FALSE, allow);
 
     win = create_nhwindow(NHW_MENU);
     start_menu(win);
@@ -972,14 +964,14 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
     /*
      * Run through the list and add the objects to the menu.  If
      * INVORDER_SORT is set, we'll run through the list once for
-     * each type so we can group them.  The allow function will only
-     * be called once per object in the list.
+     * each type so we can group them.  The allow function was
+     * called by sortloot() and will be called once per item here.
      */
     pack = flags.inv_order;
     first = TRUE;
     do {
         printed_type_name = FALSE;
-        for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
+        for (srtoli = sortedolist; ((curr = srtoli->obj) != 0); ++srtoli) {
             if (sorted && curr->oclass != *pack)
                 continue;
             if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE
@@ -1001,7 +993,7 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
                 }
 
                 any.a_obj = curr;
-                add_menu(win, obj_to_glyph(curr), &any,
+                add_menu(win, obj_to_glyph(curr, rn2_on_display_rng), &any,
                          (qflags & USE_INVLET) ? curr->invlet
                            : (first && curr->oclass == COIN_CLASS) ? '$' : 0,
                          def_oc_syms[(int) objects[curr->otyp].oc_class].sym,
@@ -1011,6 +1003,7 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
         }
         pack++;
     } while (sorted && *pack);
+    unsortloot(&sortedolist);
 
     if (engulfer) {
         char buf[BUFSZ];
@@ -1030,7 +1023,7 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
         fake_hero_object = zeroobj;
         fake_hero_object.quan = 1L; /* not strictly necessary... */
         any.a_obj = &fake_hero_object;
-        add_menu(win, mon_to_glyph(&youmonst), &any,
+        add_menu(win, mon_to_glyph(&youmonst, rn2_on_display_rng), &any,
                  /* fake inventory letter, no group accelerator */
                  CONTAINED_SYM, 0, ATR_NONE, an(self_lookat(buf)),
                  MENU_UNSELECTED);
@@ -1317,6 +1310,37 @@ int qflags;
     return ccount;
 }
 
+/*
+ *  How much the weight of the given container will change when the given
+ *  object is removed from it.  Use before and after weight amounts rather
+ *  than trying to match the calculation used by weight() in mkobj.c.
+ */
+STATIC_OVL int
+delta_cwt(container, obj)
+struct obj *container, *obj;
+{
+    struct obj **prev;
+    int owt, nwt;
+
+    if (container->otyp != BAG_OF_HOLDING)
+        return obj->owt;
+
+    owt = nwt = container->owt;
+    /* find the object so that we can remove it */
+    for (prev = &container->cobj; *prev; prev = &(*prev)->nobj)
+        if (*prev == obj)
+            break;
+    if (!*prev) {
+        panic("delta_cwt: obj not inside container?");
+    } else {
+        /* temporarily remove the object and calculate resulting weight */
+        *prev = obj->nobj;
+        nwt = weight(container);
+        *prev = obj; /* put the object back; obj->nobj is still valid */
+    }
+    return owt - nwt;
+}
+
 /* could we carry `obj'? if not, could we carry some of it/them? */
 STATIC_OVL long
 carry_count(obj, container, count, telekinesis, wt_before, wt_after)
@@ -1348,9 +1372,7 @@ int *wt_before, *wt_after;
     }
     wt = iw + (int) obj->owt;
     if (adjust_wt)
-        wt -= (container->otyp == BAG_OF_HOLDING)
-                  ? (int) DELTA_CWT(container, obj)
-                  : (int) obj->owt;
+        wt -= delta_cwt(container, obj);
     /* This will go with silver+copper & new gold weight */
     if (is_gold) /* merged gold might affect cumulative weight */
         wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count));
@@ -1378,9 +1400,7 @@ int *wt_before, *wt_after;
                 obj->quan = qq;
                 obj->owt = (unsigned) GOLD_WT(qq);
                 ow = (int) GOLD_WT(umoney + qq);
-                ow -= (container->otyp == BAG_OF_HOLDING)
-                          ? (int) DELTA_CWT(container, obj)
-                          : (int) obj->owt;
+                ow -= delta_cwt(container, obj);
                 if (iw + ow >= 0)
                     break;
                 oow = ow;
@@ -1405,9 +1425,7 @@ int *wt_before, *wt_after;
             obj->quan = qq;
             obj->owt = (unsigned) (ow = weight(obj));
             if (adjust_wt)
-                ow -= (container->otyp == BAG_OF_HOLDING)
-                          ? (int) DELTA_CWT(container, obj)
-                          : (int) obj->owt;
+                ow -= delta_cwt(container, obj);
             if (iw + ow >= 0)
                 break;
             wt = iw + ow;
@@ -2342,6 +2360,7 @@ boolean *prev_loot;
 */
             otmp = hold_another_object(otmp, "%s\82ð\97\8e\82Æ\82µ\82½\81I", doname(otmp),
                                        (const char *) 0);
+            nhUse(otmp);
             timepassed = rnd(3);
             if (prev_loot)
                 *prev_loot = TRUE;
@@ -2545,6 +2564,19 @@ register struct obj *obj;
         if (was_unpaid)
             addtobill(obj, FALSE, FALSE, TRUE);
         obfree(obj, (struct obj *) 0);
+        /* if carried, shop goods will be flagged 'unpaid' and obfree() will
+           handle bill issues, but if on floor, we need to put them on bill
+           before deleting them (non-shop items will be flagged 'no_charge') */
+        if (floor_container
+            && costly_spot(current_container->ox, current_container->oy)) {
+            struct obj save_no_charge;
+
+            save_no_charge.no_charge = current_container->no_charge;
+            addtobill(current_container, FALSE, FALSE, FALSE);
+            /* addtobill() clears no charge; we need to set it back
+               so that useupf() doesn't double bill */
+            current_container->no_charge = save_no_charge.no_charge;
+        }
         delete_contents(current_container);
         if (!floor_container)
             useup(current_container);
@@ -2701,59 +2733,84 @@ struct obj *item;
     return loss;
 }
 
-STATIC_OVL void
-observe_quantum_cat(box)
+/* used for #loot/apply, #tip, and final disclosure */
+void
+observe_quantum_cat(box, makecat, givemsg)
 struct obj *box;
+boolean makecat, givemsg;
 {
 /*JP
     static NEARDATA const char sc[] = "Schroedinger's Cat";
 */
     static NEARDATA const char sc[] = "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L";
     struct obj *deadcat;
-    struct monst *livecat;
+    struct monst *livecat = 0;
     xchar ox, oy;
+    boolean itsalive = !rn2(2);
 
-    box->spe = 0; /* box->owt will be updated below */
     if (get_obj_location(box, &ox, &oy, 0))
         box->ox = ox, box->oy = oy; /* in case it's being carried */
 
     /* this isn't really right, since any form of observation
        (telepathic or monster/object/food detection) ought to
-       force the determination of alive vs dead state; but basing
-       it just on opening the box is much simpler to cope with */
-    livecat = rn2(2)
-                  ? makemon(&mons[PM_HOUSECAT], box->ox, box->oy, NO_MINVENT)
-                  : 0;
-    if (livecat) {
-        livecat->mpeaceful = 1;
-        set_malign(livecat);
-        if (!canspotmon(livecat))
-/*JP
-            You("think %s brushed your %s.", something, body_part(FOOT));
-*/
-            You("%s\82ª\82 \82È\82½\82Ì%s\82ð\82­\82·\82®\82Á\82½\81D", something, body_part(FOOT));
-        else
-/*JP
-            pline("%s inside the box is still alive!", Monnam(livecat));
-*/
-            pline("\94 \82Ì\82È\82©\82Ì%s\82Í\82Ü\82¾\90\82«\82Ä\82¢\82é\81I", Monnam(livecat));
-        (void) christen_monst(livecat, sc);
+       force the determination of alive vs dead state; but basing it
+       just on opening or disclosing the box is much simpler to cope with */
+
+    /* SchroedingersBox already has a cat corpse in it */
+    deadcat = box->cobj;
+    if (itsalive) {
+        if (makecat)
+            livecat = makemon(&mons[PM_HOUSECAT], box->ox, box->oy,
+                              NO_MINVENT | MM_ADJACENTOK);
+        if (livecat) {
+            livecat->mpeaceful = 1;
+            set_malign(livecat);
+            if (givemsg) {
+                if (!canspotmon(livecat))
+#if 0 /*JP*/
+                    You("think %s brushed your %s.", something,
+                        body_part(FOOT));
+#else
+                    You("%s\82ª\82 \82È\82½\82Ì%s\82ð\82­\82·\82®\82Á\82½\82Æ\8ev\82Á\82½\81D", something,
+                        body_part(FOOT));
+#endif
+                else
+#if 0 /*JP*/
+                    pline("%s inside the box is still alive!",
+                          Monnam(livecat));
+#else
+                    pline("\94 \82Ì\82È\82©\82Ì%s\82Í\82Ü\82¾\90\82«\82Ä\82¢\82é\81I",
+                          Monnam(livecat));
+#endif
+            }
+            (void) christen_monst(livecat, sc);
+            if (deadcat) {
+                obj_extract_self(deadcat);
+                obfree(deadcat, (struct obj *) 0), deadcat = 0;
+            }
+            box->owt = weight(box);
+            box->spe = 0;
+        }
     } else {
-        deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT],
-                                  box->ox, box->oy, sc);
+        box->spe = 0; /* now an ordinary box (with a cat corpse inside) */
         if (deadcat) {
-            obj_extract_self(deadcat);
-            (void) add_to_container(box, deadcat);
+            /* set_corpsenm() will start the rot timer that was removed
+               when makemon() created SchroedingersBox; start it from
+               now rather than from when this special corpse got created */
+            deadcat->age = monstermoves;
+            set_corpsenm(deadcat, PM_HOUSECAT);
+            deadcat = oname(deadcat, sc);
         }
+        if (givemsg)
 #if 0 /*JP:T*/
-        pline_The("%s inside the box is dead!",
-                  Hallucination ? rndmonnam((char *) 0) : "housecat");
+            pline_The("%s inside the box is dead!",
+                      Hallucination ? rndmonnam((char *) 0) : "housecat");
 #else
-        pline_The("\94 \82Ì\92\86\82Ì%s\82Í\8e\80\82ñ\82Å\82¢\82é\81I",
-                  Hallucination ? rndmonnam((char *) 0) : "\94L");
+            pline_The("\94 \82Ì\92\86\82Ì%s\82Í\8e\80\82ñ\82Å\82¢\82é\81I",
+                      Hallucination ? rndmonnam((char *) 0) : "\94L");
 #endif
     }
-    box->owt = weight(box);
+    nhUse(deadcat);
     return;
 }
 
@@ -2900,7 +2957,7 @@ boolean more_containers; /* True iff #loot multiple and this isn't last one */
     /* check for Schroedinger's Cat */
     quantum_cat = SchroedingersBox(current_container);
     if (quantum_cat) {
-        observe_quantum_cat(current_container);
+        observe_quantum_cat(current_container, TRUE, TRUE);
         used = 1;
     }
 
@@ -3183,9 +3240,7 @@ boolean put_in;
         Sprintf(buf, "%s what type of objects?", action);
 */
         Sprintf(buf, "\82Ç\82Ì\8eí\97Þ\82Ì\82à\82Ì\82ð%s\81H", action);
-        mflags = (ALL_TYPES | UNPAID_TYPES | BUCX_TYPES);
-        if (put_in)
-            mflags |= CHOOSE_ALL;
+        mflags = (ALL_TYPES | UNPAID_TYPES | BUCX_TYPES | CHOOSE_ALL);
         n = query_category(buf, put_in ? invent : current_container->cobj,
                            mflags, &pick_list, PICK_ANY);
         if (!n)
@@ -3202,12 +3257,23 @@ boolean put_in;
     }
 
     if (loot_everything) {
-        current_container->cknown = 1;
-        for (otmp = current_container->cobj; otmp; otmp = otmp2) {
-            otmp2 = otmp->nobj;
-            res = out_container(otmp);
-            if (res < 0)
-                break;
+        if (!put_in) {
+            current_container->cknown = 1;
+            for (otmp = current_container->cobj; otmp; otmp = otmp2) {
+                otmp2 = otmp->nobj;
+                res = out_container(otmp);
+                if (res < 0)
+                    break;
+                n_looted += res;
+            }
+        } else {
+            for (otmp = invent; otmp && current_container; otmp = otmp2) {
+                otmp2 = otmp->nobj;
+                res = in_container(otmp);
+                if (res < 0)
+                    break;
+                n_looted += res;
+            }
         }
     } else {
         mflags = INVORDER_SORT;
@@ -3641,7 +3707,7 @@ struct obj *box; /* or bag */
     } else if (SchroedingersBox(box)) {
         char yourbuf[BUFSZ];
 
-        observe_quantum_cat(box);
+        observe_quantum_cat(box, TRUE, TRUE);
         if (!Has_contents(box)) /* evidently a live cat came out */
             /* container type of "large box" is inferred */
 /*JP
@@ -3707,7 +3773,7 @@ struct obj *box; /* or bag */
 
             if (highdrop) {
                 /* might break or fall down stairs; handles altars itself */
-                hitfloor(otmp);
+                hitfloor(otmp, TRUE);
             } else {
                 if (altarizing) {
                     doaltarobj(otmp);