diff --git a/include/hack.h b/include/hack.h index 0b8a780a4..5ba3bb9a0 100644 --- a/include/hack.h +++ b/include/hack.h @@ -436,6 +436,7 @@ enum bodypart_types { #define POTION_OCCUPANT_CHANCE(n) (13 + 2 * (n)) #define WAND_BACKFIRE_CHANCE 100 #define BALL_IN_MON (u.uswallow && uball && uball->where == OBJ_FREE) +#define CHAIN_IN_MON (u.uswallow && uchain && uchain->where == OBJ_FREE) #define NODIAG(monnum) ((monnum) == PM_GRID_BUG) /* Flags to control menus */ diff --git a/src/restore.c b/src/restore.c index 4f19ed878..010ef75c8 100644 --- a/src/restore.c +++ b/src/restore.c @@ -540,7 +540,8 @@ unsigned int *stuckid, *steedid; struct sysflag newgamesysflags; #endif struct context_info newgamecontext; /* all 0, but has some pointers */ - struct obj *otmp, *tmp_bc; + struct obj *otmp; + struct obj *bc_obj; char timebuf[15]; unsigned long uid; boolean defer_perm_invent; @@ -643,17 +644,15 @@ unsigned int *stuckid, *steedid; restore_timers(fd, RANGE_GLOBAL, FALSE, 0L); restore_light_sources(fd); invent = restobjchn(fd, FALSE, FALSE); - /* tmp_bc only gets set here if the ball & chain were orphaned - because you were swallowed; otherwise they will be on the floor - or in your inventory */ - tmp_bc = restobjchn(fd, FALSE, FALSE); - if (tmp_bc) { - for (otmp = tmp_bc; otmp; otmp = otmp->nobj) { - if (otmp->owornmask) - setworn(otmp, otmp->owornmask); - } - if (!uball || !uchain) - impossible("restgamestate: lost ball & chain"); + + /* restore dangling (not on floor or in inventory) ball and/or chain */ + bc_obj = restobjchn(fd, FALSE, FALSE); + while(bc_obj) { + struct obj * nobj = bc_obj->nobj; + if (bc_obj->owornmask) + setworn(bc_obj, bc_obj->owornmask); + bc_obj->nobj = (struct obj *)0; + bc_obj = nobj; } migrating_objs = restobjchn(fd, FALSE, FALSE); @@ -671,6 +670,10 @@ unsigned int *stuckid, *steedid; for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->owornmask) setworn(otmp, otmp->owornmask); + + if ((uball && !uchain) || (uchain && !uball)) + impossible("restgamestate: lost ball & chain"); + /* reset weapon so that player will get a reminder about "bashing" during next fight when bare-handed or wielding an unconventional item; for pick-axe, we aren't able to distinguish between having diff --git a/src/save.c b/src/save.c index 8bca5964a..e0af4b8d2 100644 --- a/src/save.c +++ b/src/save.c @@ -280,6 +280,7 @@ savegamestate(fd, mode) register int fd, mode; { unsigned long uid; + struct obj * bc_objs = (struct obj *)0; #ifdef MFLOPPY count_only = (mode & COUNT_SAVE); @@ -307,14 +308,18 @@ register int fd, mode; save_light_sources(fd, mode, RANGE_GLOBAL); saveobjchn(fd, invent, mode); - if (BALL_IN_MON) { - /* prevent loss of ball & chain when swallowed */ - uball->nobj = uchain; - uchain->nobj = (struct obj *) 0; - saveobjchn(fd, uball, mode); - } else { - saveobjchn(fd, (struct obj *) 0, mode); + + /* save ball and chain if they are currently dangling free (i.e. not on + floor or in inventory) */ + if (CHAIN_IN_MON) { + uchain->nobj = bc_objs; + bc_objs = uchain; } + if (BALL_IN_MON) { + uball->nobj = bc_objs; + bc_objs = uball; + } + saveobjchn(fd, bc_objs, mode); saveobjchn(fd, migrating_objs, mode); savemonchn(fd, migrating_mons, mode);