]> granicus.if.org Git - nethack/commitdiff
U162 - killing shopkeeper with unpaid thrown objects
authorcohrs <cohrs>
Thu, 13 Feb 2003 07:52:49 +0000 (07:52 +0000)
committercohrs <cohrs>
Thu, 13 Feb 2003 07:52:49 +0000 (07:52 +0000)
While an object is being thrown, it isn't on any list.  This means that
killing a shopkeeper with an unpaid object wouldn't be able to clear the
unpaid bit.  By the time the object lands, the shopkeeper is gone, and then
it's too late.  Added a new global to track a thrown object, set it and later
clear it in throwit(), also clear it as needed in dealloc_obj(), and check
it in setpaid().  It should be possible to use this global to avoid losing
thrown objects during hangup saves as well.  But that can wait.

doc/fixes34.1
src/dothrow.c
src/mkobj.c
src/shk.c

index 16274706f491b7c6b1653a793554b121b73f67ee..5450ab08f67bb0645ca14ab7f4eb830972f3e2a9 100644 (file)
@@ -383,6 +383,8 @@ avoid buffer overflow from long or too many -s params
 wake up first if trying to crawl out of water while asleep
 while waiting, don't try to change into were form when already in were form
 steed should remember traps encountered while mounted
+killing shopkeeper by throwing unpaid things would result in
+       "item not on bill" impossible error
 
 
 Platform- and/or Interface-Specific Fixes
index 983123fff545e8b6b0fc8e1f57d494c71c9dfcbe..b12c91d9537ee1ff0ba9bcb257e07d63d4d8fb46 100644 (file)
@@ -26,6 +26,8 @@ static NEARDATA const char toss_objs[] =
 static NEARDATA const char bullets[] =
        { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 };
 
+struct obj *thrownobj = 0;     /* tracks an object until it lands */
+
 extern boolean notonhead;      /* for long worms */
 
 
@@ -882,6 +884,8 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
            u.dz = 1;
        }
 
+       thrownobj = obj;
+
        if(u.uswallow) {
                mon = u.ustuck;
                bhitpos.x = mon->mx;
@@ -901,6 +905,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
            } else {
                hitfloor(obj);
            }
+           thrownobj = (struct obj*)0;
            return;
 
        } else if(obj->otyp == BOOMERANG && !Underwater) {
@@ -915,6 +920,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
                            setworn(obj, wep_mask);
                            u.twoweap = twoweap;
                        }
+                       thrownobj = (struct obj*)0;
                        return;
                }
        } else {
@@ -972,8 +978,10 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
                boolean obj_gone;
 
                if (mon->isshk &&
-                       obj->where == OBJ_MINVENT && obj->ocarry == mon)
+                   obj->where == OBJ_MINVENT && obj->ocarry == mon) {
+                   thrownobj = (struct obj*)0;
                    return;             /* alert shk caught it */
+               }
                (void) snuff_candle(obj);
                notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
                obj_gone = thitmonst(mon, obj);
@@ -1026,10 +1034,13 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
                            losehp(dmg, xname(obj),
                                obj_is_pname(obj) ? KILLED_BY : KILLED_BY_AN);
                        }
-                       if (ship_object(obj, u.ux, u.uy, FALSE))
+                       if (ship_object(obj, u.ux, u.uy, FALSE)) {
+                           thrownobj = (struct obj*)0;
                            return;
+                       }
                        dropy(obj);
                    }
+                   thrownobj = (struct obj*)0;
                    return;
                }
 
@@ -1052,11 +1063,15 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
                    if(*u.ushops)
                        check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
                    (void) mpickobj(mon, obj);  /* may merge and free obj */
+                   thrownobj = (struct obj*)0;
                    return;
                }
                (void) snuff_candle(obj);
-               if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE))
+               if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) {
+                   thrownobj = (struct obj*)0;
                    return;
+               }
+               thrownobj = (struct obj*)0;
                place_object(obj, bhitpos.x, bhitpos.y);
                if(*u.ushops && obj != uball)
                    check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
index 156b06044c79e30dd5f96df5c72fea567d08d8ee..ad6a2ebe10a3f6786461ea2defa422ed81e846e1 100644 (file)
@@ -16,6 +16,8 @@ STATIC_DCL void FDECL(check_contained, (struct obj *,const char *));
 #endif
 #endif /* OVL1 */
 
+extern struct obj *thrownobj;          /* defined in dothrow.c */
+
 /*#define DEBUG_EFFECTS*/      /* show some messages for debugging */
 
 struct icp {
@@ -1483,6 +1485,8 @@ dealloc_obj(obj)
     if (obj_sheds_light(obj))
        del_light_source(LS_OBJECT, (genericptr_t) obj);
 
+    if (obj == thrownobj) thrownobj = (struct obj*)0;
+
     free((genericptr_t) obj);
 }
 
index ce566d31b6543df19ccbe56b9041d1343f410e38..971bd58cc63b21d730b5f24425ce9ce95e00257b 100644 (file)
--- a/src/shk.c
+++ b/src/shk.c
@@ -24,6 +24,7 @@ STATIC_DCL void FDECL(kops_gone, (BOOLEAN_P));
 #define IS_SHOP(x)     (rooms[x].rtype >= SHOPBASE)
 
 extern const struct shclass shtypes[]; /* defined in shknam.c */
+extern struct obj *thrownobj;          /* defined in dothrow.c */
 
 STATIC_VAR NEARDATA long int followmsg;        /* last time of follow message */
 
@@ -285,6 +286,7 @@ register struct monst *shkp;
        clear_unpaid(invent);
        clear_unpaid(fobj);
        clear_unpaid(level.buriedobjlist);
+       if (thrownobj) thrownobj->unpaid = 0;
        for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
                clear_unpaid(mtmp->minvent);
        for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)