]> granicus.if.org Git - nethack/commitdiff
loose objects at game end
authornethack.rankin <nethack.rankin>
Thu, 4 Sep 2008 20:47:04 +0000 (20:47 +0000)
committernethack.rankin <nethack.rankin>
Thu, 4 Sep 2008 20:47:04 +0000 (20:47 +0000)
     Some post-3.4.3 code to clean up thrown or kicked objects which were
in transit at the end of a game didn't work correctly for kicked objects,
leading to an "obj not free" panic if you kicked an object at some point
and didn't kick anything else before the game was over.  Unlike thrownobj,
kickobj wasn't being cleared after use.

src/dokick.c
src/end.c

index 7eb94a680c0929da8e7e52d87cac7690c3612aab..41f0eb186991f9fb02216680790cebac59a84984 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)dokick.c   3.5     2007/05/16      */
+/*     SCCS Id: @(#)dokick.c   3.5     2008/09/04      */
 /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -18,6 +18,7 @@ extern boolean notonhead;     /* for long worms */
 STATIC_DCL void FDECL(kickdmg, (struct monst *, BOOLEAN_P));
 STATIC_DCL void FDECL(kick_monster, (XCHAR_P, XCHAR_P));
 STATIC_DCL int FDECL(kick_object, (XCHAR_P, XCHAR_P));
+STATIC_DCL int FDECL(really_kick_object, (XCHAR_P,XCHAR_P));
 STATIC_DCL char *FDECL(kickstr, (char *));
 STATIC_DCL void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long));
 STATIC_DCL void FDECL(drop_to, (coord *,SCHAR_P));
@@ -397,9 +398,27 @@ struct obj *obj;
        }
 }
 
+/* jacket around really_kick_object */
 STATIC_OVL int
 kick_object(x, y)
 xchar x, y;
+{
+    int res = 0;
+
+    /* if a pile, the "top" object gets kicked */
+    kickobj = level.objects[x][y];
+    if (kickobj) {
+       /* kick the object; if doing is fatal, done() will clean up kickobj */
+       res = really_kick_object(x, y);
+       kickobj = (struct obj *)0;
+    }
+    return res;
+}
+
+/* guts of kick_object */
+STATIC_OVL int
+really_kick_object(x, y)
+xchar x, y;
 {
        int range;
        struct monst *mon, *shkp = 0;
@@ -407,9 +426,6 @@ xchar x, y;
        char bhitroom;
        boolean costly, isgold, slide = FALSE;
 
-       /* if a pile, the "top" object gets kicked */
-       kickobj = level.objects[x][y];
-
        /* kickobj should always be set due to conditions of call */
        if(!kickobj || kickobj->otyp == BOULDER
                        || kickobj == uball || kickobj == uchain)
@@ -810,7 +826,6 @@ dokick()
                return 1;
        }
 
-       kickobj = (struct obj *)0;
        if (OBJ_AT(x, y) &&
            (!Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
             || sobj_at(BOULDER,x,y))) {
index 1427c77775c213cc16391429bd36883260e56a2f..6748a9deec187de40ce50c0dc51968bfc8447118 100644 (file)
--- a/src/end.c
+++ b/src/end.c
@@ -710,10 +710,10 @@ die:
        /* might have been killed while using a disposable item, so make sure
           it's gone prior to inventory disclosure and creation of bones data */
        inven_inuse(TRUE);
-       /* not on object lists; if an active light source, would cause big
-          trouble (`obj_is_local' panic) for savebones() -> savelev() */
-       if (thrownobj) dealloc_obj(thrownobj);
-       if (kickobj) dealloc_obj(kickobj);
+       /* maybe not on object lists; if an active light source, would cause
+          big trouble (`obj_is_local' panic) for savebones() -> savelev() */
+       if (thrownobj && thrownobj->where == OBJ_FREE) dealloc_obj(thrownobj);
+       if (kickobj && kickobj->where == OBJ_FREE) dealloc_obj(kickobj);
 
        /* Sometimes you die on the first move.  Life's not fair.
         * On those rare occasions you get hosed immediately, go out