]> granicus.if.org Git - nethack/commitdiff
Confused #loot (trunk only)
authornethack.rankin <nethack.rankin>
Thu, 25 Jan 2007 05:01:01 +0000 (05:01 +0000)
committernethack.rankin <nethack.rankin>
Thu, 25 Jan 2007 05:01:01 +0000 (05:01 +0000)
     Attempting to loot while suffering from confusion and not on top
of a container will drop gold if hero is carrying some, but it behaved
differently for GOLDOBJ config (gold dropped over a hole or down stairs
always stayed on current level) than for !GOLDOBJ (gold had a chance to
fall to lower level) when done at some location other than a throne.
This makes GOLDOBJ use dropx() instead of dropy(), same as !GOLDOBJ.

     And with access to a throne it can be used to repeatedly summon
monsters until they're extinct.  This makes it check for confusion before
finding containers, but the chest/exchequer code doesn't always kick in
so can't be attempted as many times before confusion expires, throttling
summoning a little.  Also, when placing hero's gold into a chest, it now
clears the contents-known flag and relocks the chest.

doc/fixes35.0
src/pickup.c

index 582ff5513ddac74b42d64ed30a160e704d29884e..998df465716ebbf01abad1a136b01f9b06b844ee 100644 (file)
@@ -30,6 +30,7 @@ class genocide recognizes species name as an example of the class to
 internals: use Is_box rather than explicitly checking what it checks
 fix some unreachable messages (either make then reachable or remove them)
 can quiver coins when GOLDOBJ is defined
+make #loot behave same for GOLDOBJ as for !GOLDOBJ
 grammar, spelling and other typos
 keep various delayed killers separate to avoid mixed up messages
 don't place randomly-placed aquatic monsters in lava on special levels
index 4f795500c77cd7c1ae1f888fc94fad76e564dc08..b67a2de1c1e4166f08346e130d9fff0d3d5f6d99 100644 (file)
@@ -40,6 +40,7 @@ STATIC_DCL char FDECL(in_or_out_menu, (const char *,struct obj *,
                                       BOOLEAN_P,BOOLEAN_P,BOOLEAN_P));
 STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
 STATIC_DCL boolean FDECL(able_to_loot, (int,int,BOOLEAN_P));
+STATIC_DCL boolean NDECL(reverse_loot);
 STATIC_DCL boolean FDECL(mon_beside, (int, int));
 STATIC_DCL void FDECL(tipcontainer, (struct obj *));
 
@@ -1537,6 +1538,13 @@ doloot() /* loot a container on the floor or loot saddle from mon. */
        You("have no hands!");  /* not `body_part(HAND)' */
        return 0;
     }
+    if (Confusion) {
+       if (rn2(6) && reverse_loot()) return 1;
+       if (rn2(2)) {
+           pline("Being confused, you find nothing to loot.");
+           return 1;   /* costs a turn */
+       } /* else fallthrough to normal looting */
+    }
     cc.x = u.ux; cc.y = u.uy;
 
 lootcont:
@@ -1583,63 +1591,6 @@ lootcont:
            }
        }
        if (any) c = 'y';
-    } else if (Confusion) {
-#ifndef GOLDOBJ
-       if (u.ugold){
-           long contribution = rnd((int)min(LARGEST_INT,u.ugold));
-           struct obj *goldob = mkgoldobj(contribution);
-#else
-       struct obj *goldob;
-       /* Find a money object to mess with */
-       for (goldob = invent; goldob; goldob = goldob->nobj) {
-           if (goldob->oclass == COIN_CLASS) break;
-       }
-       if (goldob){
-           long contribution = rnd((int)min(LARGEST_INT, goldob->quan));
-           if (contribution < goldob->quan)
-               goldob = splitobj(goldob, contribution);
-           freeinv(goldob);
-#endif
-           if (IS_THRONE(levl[u.ux][u.uy].typ)){
-               struct obj *coffers;
-               int pass;
-               /* find the original coffers chest, or any chest */
-               for (pass = 2; pass > -1; pass -= 2)
-                   for (coffers = fobj; coffers; coffers = coffers->nobj)
-                       if (coffers->otyp == CHEST && coffers->spe == pass)
-                           goto gotit; /* two level break */
-gotit:
-               if (coffers) {
-           verbalize("Thank you for your contribution to reduce the debt.");
-                   (void) add_to_container(coffers, goldob);
-                   coffers->owt = weight(coffers);
-               } else {
-                   struct monst *mon = makemon(courtmon(),
-                                           u.ux, u.uy, NO_MM_FLAGS);
-                   if (mon) {
-#ifndef GOLDOBJ
-                       mon->mgold += goldob->quan;
-                       delobj(goldob);
-                       pline("The exchequer accepts your contribution.");
-                   } else {
-                       dropx(goldob);
-                   }
-               }
-           } else {
-               dropx(goldob);
-#else
-                       add_to_minv(mon, goldob);
-                       pline("The exchequer accepts your contribution.");
-                   } else {
-                       dropy(goldob);
-                   }
-               }
-           } else {
-               dropy(goldob);
-#endif
-               pline("Ok, now there is loot here.");
-           }
-       }
     } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) {
        You("need to dig up the grave to effectively loot it...");
     }
@@ -1690,6 +1641,87 @@ gotit:
     return (timepassed);
 }
 
+/* called when attempting to #loot while confused */
+STATIC_OVL boolean
+reverse_loot()
+{
+    struct obj *goldob = 0, *coffers, *otmp, boxdummy;
+    struct monst *mon;
+    long contribution;
+    int n, x = u.ux, y = u.uy;
+
+    if (!rn2(3)) {
+       /* n objects: 1/(n+1) chance per object plus 1/(n+1) to fall off end */
+       for (n = inv_cnt(), otmp = invent; otmp; --n, otmp = otmp->nobj)
+           if (!rn2(n + 1)) {
+               prinv("You find old loot:", otmp, 0L);
+               return TRUE;
+           }
+       return FALSE;
+    }
+
+#ifndef GOLDOBJ
+    if (u.ugold) {
+       contribution = ((long)rnd(5) * u.ugold + 4L) / 5L;
+       goldob = mkgoldobj(contribution);
+    }
+#else
+    /* find a money object to mess with */
+    for (goldob = invent; goldob; goldob = goldob->nobj)
+       if (goldob->oclass == COIN_CLASS) {
+           contribution = ((long)rnd(5) * goldob->quan + 4L) / 5L;
+           if (contribution < goldob->quan)
+               goldob = splitobj(goldob, contribution);
+           break;
+       }
+#endif
+    if (!goldob) return FALSE;
+
+    if (!IS_THRONE(levl[x][y].typ)) {
+       dropx(goldob);
+       /* the dropped gold might have fallen to lower level */
+       if (g_at(x, y)) pline("Ok, now there is loot here.");
+    } else {
+       /* find original coffers chest if present, otherwise use nearest one */
+       otmp = 0;
+       for (coffers = fobj; coffers; coffers = coffers->nobj)
+           if (coffers->otyp == CHEST) {
+               if (coffers->spe == 2) break;   /* a throne room chest */
+               if (!otmp ||
+                 distu(coffers->ox, coffers->oy) < distu(otmp->ox, otmp->oy))
+                   otmp = coffers;     /* remember closest ordinary chest */
+           }
+       if (!coffers) coffers = otmp;
+
+       if (coffers) {
+           verbalize("Thank you for your contribution to reduce the debt.");
+#ifdef GOLDOBJ
+           freeinv(goldob);
+#endif
+           (void)add_to_container(coffers, goldob);
+           coffers->owt = weight(coffers);
+           coffers->cknown = 0;
+           if (!coffers->olocked) {
+               boxdummy = zeroobj, boxdummy.otyp = SPE_WIZARD_LOCK;
+               (void)boxlock(coffers, &boxdummy);
+           }
+       } else if ((mon = makemon(courtmon(), x, y, NO_MM_FLAGS)) != 0) {
+#ifndef GOLDOBJ
+           mon->mgold += goldob->quan;
+           delobj(goldob);
+#else
+           freeinv(goldob);
+           add_to_minv(mon, goldob);
+#endif
+           pline("The exchequer accepts your contribution.");
+       } else {
+           You("drop %s.", doname(goldob));
+           dropx(goldob);
+       }
+    }
+    return TRUE;
+}
+
 /* loot_mon() returns amount of time passed.
  */
 int