]> granicus.if.org Git - nethack/commitdiff
vault guard bug: dropping minvent at <0,0> (trunk only)
authornethack.rankin <nethack.rankin>
Sun, 9 Oct 2011 02:13:01 +0000 (02:13 +0000)
committernethack.rankin <nethack.rankin>
Sun, 9 Oct 2011 02:13:01 +0000 (02:13 +0000)
     From the newsgroup:  after killing a vault guard on a level where
every object had been removed or was held by the hero, object detection
gave feedback about finding something but was unable to show anything.
It was finding the dead guard's inventory at <0,0>, a part of the map
which never gets shown.  A dying guard is sent to that location instead
of being killed and deleted, because the data for his temporary corridor
to/from the vault is kept in the egd structure attached to him.  That's
somewhat obscure but works; dying guards just need to drop inventory
before being transfered there rather than after.

     Depending upon how they're killed, it's possible that the umpteen
places in the code that loop over fmon might have been processing them
as if still in play.  This sets their mhp to 0 so such loops will ignore
them, and teaches dmonsfree() not to release them.  Once the temporary
corridor has been removed, their isgd flag is cleared and they become
ordinary dead monsters and get deleted from the fmon list the next time
it's purged.

     This also lets you throw gold to/at the guard when he tells you to
drop it.  He already would catch it, but now he won't treat the throw as
an attack.  Any gold he carries will eventually disappear when he does,
so dropping it remains a better option for the player.

doc/fixes35.0
src/dokick.c
src/mon.c
src/steal.c
src/vault.c

index 533a2f2539760b039fa355d1f4314ad3c63b233e..3c637f30b7584cae9692d9be329203e33265b67f 100644 (file)
@@ -382,6 +382,8 @@ all statues in a cockatrice nest were for giant ant if 'record' was empty
 when dying outside all shops on a level with multiple shopkeepers and one takes
        hero's stuff, choose one who is owed money over first one on fmon list
 hero poly'd into a critter without hands could still open tins
+if a vault guard was killed, his inventory would be dropped at <0,0>
+throwing gold to/at a vault guard will no longer be treated as an attack
 
 
 Platform- and/or Interface-Specific Fixes
index 0d4babd3a7a4321822f0bb1e261f04762bd9c5e8..d76f1ff6d05556ce45fe7767f3bf6474ebe34723 100644 (file)
@@ -252,8 +252,8 @@ register struct obj *gold;
 {
        boolean msg_given = FALSE;
 
-       if(!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest
-                       && !is_mercenary(mtmp->data)) {
+       if (!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest &&
+                       !mtmp->isgd && !is_mercenary(mtmp->data)) {
                wakeup(mtmp);
        } else if (!mtmp->mcanmove) {
                /* too light to do real damage */
@@ -263,29 +263,23 @@ register struct obj *gold;
                    msg_given = TRUE;
                }
        } else {
-#ifdef GOLDOBJ
-                long value = gold->quan * objects[gold->otyp].oc_cost;
-#endif
+               long umoney, value = gold->quan * objects[gold->otyp].oc_cost;
+
                mtmp->msleeping = 0;
                finish_meating(mtmp);
-               if(!rn2(4)) setmangry(mtmp); /* not always pleasing */
-
+               if (!mtmp->isgd && !rn2(4))     /* not always pleasing */
+                   setmangry(mtmp);
                /* greedy monsters catch gold */
                if (cansee(mtmp->mx, mtmp->my))
                    pline("%s catches the gold.", Monnam(mtmp));
-#ifndef GOLDOBJ
-               mtmp->mgold += gold->quan;
-#endif
+               (void)mpickobj(mtmp, gold);
+               gold = (struct obj *)0; /* obj has been freed */
                if (mtmp->isshk) {
                        long robbed = ESHK(mtmp)->robbed;
 
                        if (robbed) {
-#ifndef GOLDOBJ
-                               robbed -= gold->quan;
-#else
                                robbed -= value;
-#endif
-                               if (robbed < 0) robbed = 0;
+                               if (robbed < 0L) robbed = 0L;
                                pline_The("amount %scovers %s recent losses.",
                                      !robbed ? "" : "partially ",
                                      mhis(mtmp));
@@ -294,11 +288,7 @@ register struct obj *gold;
                                        make_happy_shk(mtmp, FALSE);
                        } else {
                                if(mtmp->mpeaceful) {
-#ifndef GOLDOBJ
-                                   ESHK(mtmp)->credit += gold->quan;
-#else
                                    ESHK(mtmp)->credit += value;
-#endif
                                    You("have %ld %s in credit.",
                                        ESHK(mtmp)->credit,
                                        currency(ESHK(mtmp)->credit));
@@ -308,6 +298,23 @@ register struct obj *gold;
                        if (mtmp->mpeaceful)
                            verbalize("Thank you for your contribution.");
                        else verbalize("Thanks, scum!");
+               } else if (mtmp->isgd) {
+#ifndef GOLDOBJ
+                       umoney = u.ugold;
+#else
+                       umoney = money_cnt(invent);
+#endif
+                       /* Some of these are iffy, because a hostile guard
+                          won't become peaceful and resume leading hero
+                          out of the vault.  If he did do that, player
+                          could try fighting, then weasle out of being
+                          killed by throwing his/her gold when losing. */
+                       verbalize(umoney ? "Drop the rest and follow me." :
+                                 hidden_gold() ?
+                               "You still have hidden gold.  Drop it now." :
+                                 mtmp->mpeaceful ?
+                               "I'll take care of that; please move along." :
+                               "I'll take that; now get moving.");
                } else if (is_mercenary(mtmp->data)) {
                    long goldreqd = 0L;
 
@@ -323,25 +330,19 @@ register struct obj *gold;
 
                        if (goldreqd) {
 #ifndef GOLDOBJ
-                          if (gold->quan > goldreqd +
-                               (u.ugold + u.ulevel*rn2(5))/ACURR(A_CHA))
+                           umoney = u.ugold;
 #else
-                          if (value > goldreqd +
-                               (money_cnt(invent) + u.ulevel*rn2(5))/ACURR(A_CHA))
+                           umoney = money_cnt(invent);
 #endif
-                           mtmp->mpeaceful = TRUE;
+                           if (value > goldreqd +
+                                 (umoney + u.ulevel * rn2(5)) / ACURR(A_CHA))
+                               mtmp->mpeaceful = TRUE;
                        }
                     }
                     if (mtmp->mpeaceful)
                            verbalize("That should do.  Now beat it!");
                     else verbalize("That's not enough, coward!");
                }
-
-#ifndef GOLDOBJ
-               dealloc_obj(gold);
-#else
-               add_to_minv(mtmp, gold);
-#endif
                return TRUE;
        }
 
index e36482dd1a7ea1f07371d8647307d1985c761459..214c2a482cce318ccb0203a0f53ed7114b02c81e 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -1261,17 +1261,17 @@ register int x,y;
 void
 dmonsfree()
 {
-    struct monst **mtmp;
+    struct monst **mtmp, *freetmp;
     int count = 0;
 
     for (mtmp = &fmon; *mtmp;) {
-       if ((*mtmp)->mhp <= 0) {
-           struct monst *freetmp = *mtmp;
-           *mtmp = (*mtmp)->nmon;
+       freetmp = *mtmp;
+       if (freetmp->mhp <= 0 && !freetmp->isgd) {
+           *mtmp = freetmp->nmon;
            dealloc_monst(freetmp);
            count++;
        } else
-           mtmp = &(*mtmp)->nmon;
+           mtmp = &(freetmp->nmon);
     }
 
     if (count != iflags.purge_monsters)
@@ -1534,11 +1534,6 @@ register struct monst *mtmp;
        struct permonst *mptr;
        int tmp;
 
-       if(mtmp->isgd) {
-               /* if we're going to abort the death, it *must* be before
-                * the m_detach or there will be relmon problems later */
-               if(!grddead(mtmp)) return;
-       }
        lifesaved_monster(mtmp);
        if (mtmp->mhp > 0) return;
 
@@ -1588,6 +1583,11 @@ register struct monst *mtmp;
                }
        }
 
+       /* dead vault guard is actually kept at coordinate <0,0> until
+          his temporary corridor to/from the vault has been removed;
+          need to do this after life-saving and before m_detach() */
+       if (mtmp->isgd && !grddead(mtmp)) return;
+
 #ifdef STEED
        /* Player is thrown from his steed when it dies */
        if (mtmp == u.usteed)
index 32ffbf0033adca09269307d28006453add9fb971..64b8deb7b7fbc38d6a05215dbdb543f47b4d02e4 100644 (file)
@@ -490,6 +490,10 @@ register struct obj *otmp;
 {
     int freed_otmp;
 
+    /* if monster is acquiring a thrown or kicked object, the throwing
+       or kicking code shouldn't continue to track and place it */
+    if (otmp == thrownobj) thrownobj = 0;
+    else if (otmp == kickedobj) kickedobj = 0;
 #ifndef GOLDOBJ
     if (otmp->oclass == COIN_CLASS) {
        mtmp->mgold += otmp->quan;
@@ -502,17 +506,13 @@ register struct obj *otmp;
        engulfers won't have external inventories; whirly monsters cause
        the light to be extinguished rather than letting it shine thru */
     if (otmp->lamplit &&  /* hack to avoid function calls for most objs */
-       obj_sheds_light(otmp) &&
+       obj_sheds_light(otmp) &&
        attacktype(mtmp->data, AT_ENGL)) {
        /* this is probably a burning object that you dropped or threw */
        if (u.uswallow && mtmp == u.ustuck && !Blind)
            pline("%s out.", Tobjnam(otmp, "go"));
        snuff_otmp = TRUE;
     }
-    /* if monster is acquiring a thrown or kicked object, the throwing
-       or kicking code shouldn't continue to track and place it */
-    if (otmp == thrownobj) thrownobj = 0;
-    else if (otmp == kickedobj) kickedobj = 0;
     /* for hero owned object on shop floor, mtmp is taking possession
        and if it's eventually dropped in a shop, shk will claim it */
     if (!mtmp->mtame) otmp->no_charge = 0;
@@ -686,6 +686,24 @@ boolean is_pet;            /* If true, pet should keep wielded/worn items */
        struct obj *otmp;
        int omx = mtmp->mx, omy = mtmp->my;
 
+       /* vault guard's gold goes away rather than be dropped... */
+       if (mtmp->isgd &&
+#ifdef GOLDOBJ
+                   (otmp = findgold(mtmp->minvent)) != 0
+#else
+                   mtmp->mgold != 0L
+#endif
+           ) {
+               if (canspotmon(mtmp))
+                   pline("%s gold %s.", s_suffix(Monnam(mtmp)),
+                         canseemon(mtmp) ? "vanishes" : "seems to vanish");
+#ifdef GOLDOBJ
+               obfree(otmp, (struct obj *)0);
+#else
+               mtmp->mgold = 0L;
+#endif
+       } /* isgd && has gold */
+
 #ifndef GOLDOBJ
        /* handle gold first since droppables() would get stuck on it */
        if (mtmp->mgold) {
@@ -704,7 +722,7 @@ boolean is_pet;             /* If true, pet should keep wielded/worn items */
                mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
        }
 
-       if (show & cansee(omx, omy))
+       if (show && cansee(omx, omy))
                newsym(omx, omy);
 }
 
index eefb5f087a2ec9a598fc2a40317cecddf089f811..b46ce50bb1f180c3163ccb5920b56005c07b8f7a 100644 (file)
@@ -92,7 +92,10 @@ restfakecorr(grd)
 register struct monst *grd;
 {
        /* it seems you left the corridor - let the guard disappear */
-       if(clear_fcorr(grd, FALSE)) mongone(grd);
+       if (clear_fcorr(grd, FALSE)) {
+           grd->isgd = 0;      /* dmonsfree() should delete this mon */
+           mongone(grd);
+       }
 }
 
 boolean
@@ -101,7 +104,11 @@ register struct monst *grd;
 {
        register boolean dispose = clear_fcorr(grd, TRUE);
 
-       if(!dispose) {
+       if (!dispose) {
+               /* destroy guard's gold; drop any other inventory */
+               relobj(grd, 0, FALSE);
+               /* guard is dead; monster traversal loops should skip it */
+               grd->mhp = 0;
                /* see comment by newpos in gd_move() */
                remove_monster(grd->mx, grd->my);
                newsym(grd->mx, grd->my);
@@ -110,7 +117,8 @@ register struct monst *grd;
                EGD(grd)->ogy = grd->my;
                dispose = clear_fcorr(grd, TRUE);
        }
-       return(dispose);
+       if (dispose) grd->isgd = 0; /* for dmonsfree() */
+       return dispose;
 }
 
 STATIC_OVL boolean
@@ -175,9 +183,8 @@ invault()
        char buf[BUFSZ];
        register int x, y, dd, gx, gy;
        int lx = 0, ly = 0;
-#ifdef GOLDOBJ
-        long umoney;
-#endif
+       long umoney;
+
        /* first find the goal for the guard */
        for(dd = 2; (dd < ROWNO || dd < COLNO); dd++) {
          for(y = u.uy-dd; y <= u.uy+dd; ly = y, y++) {
@@ -331,29 +338,20 @@ fnd:
        }
        verbalize("I don't know you.");
 #ifndef GOLDOBJ
-       if (Deaf)
+       umoney = u.ugold;
+#else
+       umoney = money_cnt(invent);
+#endif
+       if (Deaf) {
            ;
-       else if (!u.ugold && !hidden_gold())
+       } else if (!umoney && !hidden_gold()) {
            verbalize("Please follow me.");
-       else {
-           if (!u.ugold)
+       else {
+           if (!umoney)
                verbalize("You have hidden gold.");
            verbalize("Most likely all your gold was stolen from this vault.");
            verbalize("Please drop that gold and follow me.");
        }
-#else
-        umoney = money_cnt(invent);
-       if (Deaf)
-           ;
-       else if (!umoney && !hidden_gold())
-           verbalize("Please follow me.");
-       else {
-           if (!umoney)
-               verbalize("You have hidden money.");
-           verbalize("Most likely all your money was stolen from this vault.");
-           verbalize("Please drop that money and follow me.");
-       }
-#endif
        EGD(guard)->gdx = gx;
        EGD(guard)->gdy = gy;
        EGD(guard)->fcbeg = 0;