diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 23f01b8d7..7e76d7abc 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.870 $ $NHDT-Date: 1649530942 2022/04/09 19:02:22 $ +HDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.870 $ $NHDT-Date: 1649530942 2022/04/09 19:02:22 $ General Fixes and Modified Features ----------------------------------- @@ -875,6 +875,8 @@ avoid "the Lord Surtur's corpse glows iridescently" when shk_your() or the() restoring while attached ball or chain is on floor in a breach of a shop wall could have it be moved out of wall gap as that gets repaired, then might trigger an impossible about being positioned too far from hero +don't try to catch up for lost time for shop damage repair in restdamage() + called from getlev(); let normal shopkeeper movement take care of it Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index 0ad900f2b..7e09175f2 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2436,7 +2436,8 @@ extern void sellobj(struct obj *, xchar, xchar); extern int doinvbill(int); extern struct monst *shkcatch(struct obj *, xchar, xchar); extern void add_damage(xchar, xchar, long); -extern int repair_damage(struct monst *, struct damage *, boolean); +extern int repair_damage(struct monst *, struct damage *); +extern void fix_shop_damage(void); extern int shk_move(struct monst *); extern void after_shk_move(struct monst *); extern boolean is_fshk(struct monst *); diff --git a/src/allmain.c b/src/allmain.c index 2b637509b..ef75a7eb6 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -68,6 +68,7 @@ moveloop_preamble(boolean resuming) g.context.botlx = TRUE; /* for STATUS_HILITES */ if (resuming) { /* restoring old game */ read_engr_at(u.ux, u.uy); /* subset of pickup() */ + fix_shop_damage(); } (void) encumber_msg(); /* in case they auto-picked up something */ diff --git a/src/bones.c b/src/bones.c index 5326e08df..5d11ffd15 100644 --- a/src/bones.c +++ b/src/bones.c @@ -660,6 +660,7 @@ getbones(void) } resetobjs(fobj, TRUE); resetobjs(g.level.buriedobjlist, TRUE); + fix_shop_damage(); } } close_nhfile(nhfp); diff --git a/src/do.c b/src/do.c index 04525b8ea..079b163d5 100644 --- a/src/do.c +++ b/src/do.c @@ -1805,6 +1805,11 @@ goto_level( /* assume this will always return TRUE when changing level */ (void) in_out_region(u.ux, u.uy); + /* shop repair is normally done when shopkeepers move, but we may + need to catch up for lost time here; do this before maybe dying + so bones map will include it */ + if (!new) + fix_shop_damage(); /* fall damage? */ if (do_fall_dmg) { diff --git a/src/restore.c b/src/restore.c index 21b21e899..5ded5580d 100644 --- a/src/restore.c +++ b/src/restore.c @@ -154,51 +154,22 @@ restdamage(NHFILE* nhfp) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &dmgcount, sizeof(dmgcount)); + mread(nhfp->fd, (genericptr_t) &dmgcount, sizeof dmgcount); counter = (int) dmgcount; if (!counter) return; - tmp_dam = (struct damage *) alloc(sizeof(struct damage)); - while (--counter >= 0) { - char damaged_shops[5], *shp = (char *) 0; - + do { + tmp_dam = (struct damage *) alloc(sizeof *tmp_dam); if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam)); + mread(nhfp->fd, (genericptr_t) tmp_dam, sizeof *tmp_dam); if (ghostly) tmp_dam->when += (g.moves - g.omoves); - /* - * This should be removed and handled separately when returning - * to a level. It's a holdover from when restore would catch up - * for lost time on any level as it went through all the levels - * instead of just splitting the save file into individual level - * files. - */ - Strcpy(damaged_shops, - in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE)); - if (u.uz.dlevel) { - /* when restoring, there are two passes over the current - * level. the first time, u.uz isn't set, so neither is - * shop_keeper(). just wait and process the damage on - * the second pass. - */ - for (shp = damaged_shops; *shp; shp++) { - struct monst *shkp = shop_keeper(*shp); - - if (shkp && inhishop(shkp) - && repair_damage(shkp, tmp_dam, TRUE)) - break; - } - } - if (!shp || !*shp) { - tmp_dam->next = g.level.damagelist; - g.level.damagelist = tmp_dam; - tmp_dam = (struct damage *) alloc(sizeof(*tmp_dam)); - } - } - free((genericptr_t) tmp_dam); + tmp_dam->next = g.level.damagelist; + g.level.damagelist = tmp_dam; + } while (--counter > 0); } /* restore one object */ diff --git a/src/shk.c b/src/shk.c index cb7431ef7..6927a3c47 100644 --- a/src/shk.c +++ b/src/shk.c @@ -156,7 +156,7 @@ money2u(struct monst* mon, long amount) } static struct monst * -next_shkp(register struct monst* shkp, register boolean withbill) +next_shkp(register struct monst *shkp, boolean withbill) { for (; shkp; shkp = shkp->nmon) { if (DEADMONSTER(shkp)) @@ -1983,9 +1983,11 @@ find_oid(unsigned int id) /* Returns the price of an arbitrary item in the shop, 0 if the item doesn't belong to a shopkeeper or hero is not in the shop. */ long -get_cost_of_shop_item(register struct obj* obj, int* nochrg) - /* alternate return value: 1: no charge, 0: shop owned, */ -{ /* -1: not in a shop (so should't be formatted as "no charge") */ +get_cost_of_shop_item( + struct obj *obj, + int *nochrg) /* alternate return value: 1: no charge, 0: shop owned, + * -1: not in a shop (so don't format as "no charge") */ +{ struct monst *shkp; struct obj *top; xchar x, y; @@ -3632,7 +3634,7 @@ discard_damage_owned_by(struct monst *shkp) /* Shopkeeper tries to repair damage belonging to them */ static void -shk_fixes_damage(struct monst* shkp) +shk_fixes_damage(struct monst *shkp) { struct damage *dam = find_damage(shkp); boolean shk_closeby; @@ -3649,7 +3651,7 @@ shk_fixes_damage(struct monst* shkp) else if (!Deaf && shk_closeby) You_hear("someone muttering an incantation."); - (void) repair_damage(shkp, dam, FALSE); + (void) repair_damage(shkp, dam); discard_damage_struct(dam); } @@ -3769,19 +3771,19 @@ litter_newsyms(xchar *litter, xchar x, xchar y) int repair_damage( struct monst *shkp, - struct damage *tmp_dam, - boolean catchup) /* restoring a level */ + struct damage *tmp_dam) { xchar x, y; xchar *litter; struct obj *otmp; struct trap *ttmp; int k, disposition = 1; - boolean stop_picking = FALSE; + boolean catchup, stop_picking = FALSE; if (!repairable_damage(tmp_dam, shkp)) return 0; + catchup = g.moves > tmp_dam->when + REPAIR_DELAY; x = tmp_dam->place.x; y = tmp_dam->place.y; @@ -3873,11 +3875,25 @@ repair_damage( return disposition; } +/* normally repair is done when a shopkeeper moves, but we also try to + catch up for lost time when reloading a previously visited level */ +void +fix_shop_damage(void) +{ + struct monst *shkp; + + for (shkp = next_shkp(fmon, FALSE); shkp; + shkp = next_shkp(shkp->nmon, FALSE)) { + if (shkp->mcanmove && inhishop(shkp)) + shk_fixes_damage(shkp); + } +} + /* * shk_move: return 1: moved 0: didn't -1: let m_move do it -2: died */ int -shk_move(struct monst* shkp) +shk_move(struct monst *shkp) { xchar gx, gy, omx, omy; int udist;