-/* NetHack 3.6 end.c $NHDT-Date: 1557094801 2019/05/05 22:20:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.170 $ */
+/* NetHack 3.6 end.c $NHDT-Date: 1558921075 2019/05/27 01:37:55 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.174 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
STATIC_DCL void FDECL(disclose, (int, BOOLEAN_P));
STATIC_DCL void FDECL(get_valuables, (struct obj *));
STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *, int));
+STATIC_DCL void NDECL(done_object_cleanup);
STATIC_DCL void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid));
STATIC_DCL void FDECL(really_done, (int)) NORETURN;
STATIC_DCL void FDECL(savelife, (int));
}
#endif
+/* deal with some objects which may be in an abnormal state at end of game */
+STATIC_OVL void
+done_object_cleanup()
+{
+ int ox, oy;
+
+ /* might have been killed while using a disposable item, so make sure
+ it's gone prior to inventory disclosure and creation of bones */
+ inven_inuse(TRUE);
+ /*
+ * Hero can die when throwing an object (by hitting an adjacent
+ * gas spore, for instance, or being hit by mis-returning Mjollnir),
+ * or while in transit (from falling down stairs). If that happens,
+ * some object(s) might be in limbo rather than on the map or in
+ * any inventory. Saving bones with an active light source in limbo
+ * would trigger an 'object not local' panic.
+ *
+ * We used to use dealloc_obj() on thrownobj and kickedobj but
+ * that keeps them out of bones and could leave uball in a confused
+ * state (gone but still attached). Place them on the map but
+ * bypass flooreffects(). That could lead to minor anomalies in
+ * bones, like undamaged paper at water or lava locations or piles
+ * not being knocked down holes, but it seems better to get this
+ * game over with than risk being tangled up in more and more details.
+ */
+ ox = u.ux + u.dx, oy = u.uy + u.dy;
+ if (!isok(ox, oy) || !accessible(ox, oy))
+ ox = u.ux, oy = u.uy;
+ /* put thrown or kicked object on map (for bones); location might
+ be incorrect (perhaps killed by divine lightning when throwing at
+ a temple priest?) but this should be better than just vanishing
+ (fragile stuff should be taken care of before getting here) */
+ if (thrownobj && thrownobj->where == OBJ_FREE) {
+ place_object(thrownobj, ox, oy);
+ stackobj(thrownobj), thrownobj = 0;
+ }
+ if (kickedobj && kickedobj->where == OBJ_FREE) {
+ place_object(kickedobj, ox, oy);
+ stackobj(kickedobj), kickedobj = 0;
+ }
+ /* if Punished hero dies during level change or dies or quits while
+ swallowed, uball and uchain will be in limbo; put them on floor
+ so bones will have them and object list cleanup finds them */
+ if (uchain && uchain->where == OBJ_FREE) {
+ placebc();
+ }
+ return;
+}
+
/* called twice; first to calculate total, then to list relevant items */
STATIC_OVL void
artifact_score(list, counting, endwin)
/* render vision subsystem inoperative */
iflags.vision_inited = 0;
- /* 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);
- /* 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 (kickedobj && kickedobj->where == OBJ_FREE)
- dealloc_obj(kickedobj);
+ /* maybe use up active invent item(s), place thrown/kicked missile,
+ deal with ball and chain possibly being temporarily off the map */
+ if (!program_state.panicking)
+ done_object_cleanup();
/* remember time of death here instead of having bones, rip, and
topten figure it out separately and possibly getting different
int mnum = u.umonnum;
if (!Upolyd) {
- /* Base corpse on race when not poly'd since original
- * u.umonnum is based on role, and all role monsters
- * are human.
- */
+ /* Base corpse on race when not poly'd since original u.umonnum
+ is based on role, and all role monsters are human. */
mnum = (flags.female && urace.femalenum != NON_PM)
? urace.femalenum
: urace.malenum;