diff --git a/doc/fixes36.3 b/doc/fixes36.3 index 0764ce2d3..ba04dc4d3 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.23 $ $NHDT-Date: 1558856435 2019/05/26 07:40:35 $ +$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.24 $ $NHDT-Date: 1558921075 2019/05/27 01:37:55 $ This fixes36.3 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.2 in May 2019. Please note, however, @@ -26,6 +26,10 @@ on rare occasions, multiple mine's end luckstones were being marked as the make sure the correct luckstone is the prize in mine's end free dungeon overview's bones information at end of game free current level's bones information at end of game +free ball and chain if Punished hero dies while descending stairs or dies or + quits while swallowed; put ball and chain in bones for the stairs case +if hero dies while a thrown or kicked object is in transit, put that object + on the map in case bones data gets saved Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository diff --git a/src/ball.c b/src/ball.c index 5f87ef6e3..39ccbdac4 100644 --- a/src/ball.c +++ b/src/ball.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 ball.c $NHDT-Date: 1558485648 2019/05/22 00:40:48 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.37 $ */ +/* NetHack 3.6 ball.c $NHDT-Date: 1558920171 2019/05/27 01:22:51 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.38 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) David Cohrs, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -373,20 +373,7 @@ xchar ballx, bally, chainx, chainy; /* only matter !before */ } } -/* return TRUE if the caller needs to place the ball and chain down again - * - * Should not be called while swallowed. Should be called before movement, - * because we might want to move the ball or chain to the hero's old - * position. - * - * It is called if we are moving. It is also called if we are teleporting - * *if* the ball doesn't move and we thus must drag the chain. It is not - * called for ordinary teleportation. - * - * allow_drag is only used in the ugly special case where teleporting must - * drag the chain, while an identical-looking movement must drag both the ball - * and chain. - */ +/* return TRUE if the caller needs to place the ball and chain down again */ boolean drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay, allow_drag) @@ -399,6 +386,20 @@ boolean allow_drag; struct trap *t = (struct trap *) 0; boolean already_in_rock; + /* + * Should not be called while swallowed. Should be called before + * movement, because we might want to move the ball or chain to the + * hero's old position. + * + * It is called if we are moving. It is also called if we are + * teleporting *if* the ball doesn't move and we thus must drag the + * chain. It is not called for ordinary teleportation. + * + * 'allow_drag' is only used in the ugly special case where teleporting + * must drag the chain, while an identical-looking movement must drag + * both the ball and chain. + */ + *ballx = uball->ox; *bally = uball->oy; *chainx = uchain->ox; @@ -425,6 +426,7 @@ boolean allow_drag; } return TRUE; } + #define CHAIN_IN_MIDDLE(chx, chy) \ (distmin(x, y, chx, chy) <= 1 \ && distmin(chx, chy, uball->ox, uball->oy) <= 1) @@ -432,19 +434,21 @@ boolean allow_drag; (IS_ROCK(levl[x][y].typ) \ || (IS_DOOR(levl[x][y].typ) \ && (levl[x][y].doormask & (D_CLOSED | D_LOCKED)))) -/* Don't ever move the chain into solid rock. If we have to, then instead - * undo the move_bc() and jump to the drag ball code. Note that this also - * means the "cannot carry and drag" message will not appear, since unless we - * moved at least two squares there is no possibility of the chain position - * being in solid rock. - */ -#define SKIP_TO_DRAG \ - { \ + /* + * Don't ever move the chain into solid rock. If we have to, then + * instead undo the move_bc() and jump to the drag ball code. Note + * that this also means the "cannot carry and drag" message will not + * appear, since unless we moved at least two squares there is no + * possibility of the chain position being in solid rock. + */ +#define SKIP_TO_DRAG \ + do { \ *chainx = oldchainx; \ *chainy = oldchainy; \ move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \ goto drag; \ - } + } while (0) + if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy) || IS_CHAIN_ROCK(uball->ox, uball->oy)) already_in_rock = TRUE; @@ -469,8 +473,8 @@ boolean allow_drag; case 5: { xchar tempx, tempy, tempx2, tempy2; - /* find position closest to current position of chain */ - /* no effect if current position is already OK */ + /* find position closest to current position of chain; + no effect if current position is already OK */ if (abs(x - uball->ox) == 1) { tempx = x; tempx2 = uball->ox; diff --git a/src/end.c b/src/end.c index 21a10c5e3..daebeb9e2 100644 --- a/src/end.c +++ b/src/end.c @@ -1,4 +1,4 @@ -/* 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. */ @@ -28,6 +28,7 @@ static void FDECL(done_hangup, (int)); 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)); @@ -973,6 +974,55 @@ int what; } #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 g.thrownobj and g.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 (g.thrownobj && g.thrownobj->where == OBJ_FREE) { + place_object(g.thrownobj, ox, oy); + stackobj(g.thrownobj), g.thrownobj = 0; + } + if (g.kickedobj && g.kickedobj->where == OBJ_FREE) { + place_object(g.kickedobj, ox, oy); + stackobj(g.kickedobj), g.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) @@ -1144,15 +1194,10 @@ int how; /* 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 (g.thrownobj && g.thrownobj->where == OBJ_FREE) - dealloc_obj(g.thrownobj); - if (g.kickedobj && g.kickedobj->where == OBJ_FREE) - dealloc_obj(g.kickedobj); + /* maybe use up active invent item(s), place thrown/kicked missile, + deal with ball and chain possibly being temporarily off the map */ + if (!g.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 @@ -1279,10 +1324,8 @@ int how; 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 && g.urace.femalenum != NON_PM) ? g.urace.femalenum : g.urace.malenum;