diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 23b699ac4..5e1d1ad9d 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -54,7 +54,20 @@ highlighting status conditions would fail to use attributes if a rule with them was followed by another one without (color only or color&normal) when using 'O' to set hilite_status rules, hide the 'score' status field if game has been built without SCORE_ON_BOTL; latent rules for 'score' - can still be set in config file but can't be added or removed via 'O' + can still be set in config file and removed via 'O' but can't be added +make stone-to-flesh behave the same on statues of petrified monsters as it + does on random 'dungeon art' ones (revive at a nearby spot instead of + becoming a corpse when there's already a monster at statue's location) +special level loader didn't support populating several types of special rooms + (ant hole, cockatrice nest, leprechaun hall) +eating rings while polymorphed didn't handle bonus/penalty for increase damage, + increase accuracy, or protection correctly +shopkeeper's position in front of shop door didn't correctly handle bottom + edge of irregularly shaped shop due to typo or copy+paste error + (latent bug; no such shops are present in 3.6.x) +attempting to update permanent inventory window during restore had problems + with unpaid items (needed shop bill before shop and its shopkeeper + were restored) and named fruit Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index aa990d10b..bd1924a6b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2860,7 +2860,7 @@ E boolean FDECL(get_obj_location, (struct obj *, xchar *, xchar *, int)); E boolean FDECL(get_mon_location, (struct monst *, xchar *, xchar *, int)); E struct monst *FDECL(get_container_location, (struct obj * obj, int *, int *)); -E struct monst *FDECL(montraits, (struct obj *, coord *)); +E struct monst *FDECL(montraits, (struct obj *, coord *, BOOLEAN_P)); E struct monst *FDECL(revive, (struct obj *, BOOLEAN_P)); E int FDECL(unturn_dead, (struct monst *)); E void FDECL(cancel_item, (struct obj *)); diff --git a/src/eat.c b/src/eat.c index 79fd56df0..1c055abbc 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1877,10 +1877,11 @@ int old, inc, typ; { int absold, absinc, sgnold, sgninc; - /* don't include any amount coming from worn rings */ - if (uright && uright->otyp == typ) + /* don't include any amount coming from worn rings (caller handles + 'protection' differently) */ + if (uright && uright->otyp == typ && typ != RIN_PROTECTION) old -= uright->spe; - if (uleft && uleft->otyp == typ) + if (uleft && uleft->otyp == typ && typ != RIN_PROTECTION) old -= uleft->spe; absold = abs(old), absinc = abs(inc); sgnold = sgn(old), sgninc = sgn(inc); @@ -1900,6 +1901,11 @@ int old, inc, typ; } else { inc = 0; /* no further increase allowed via this method */ } + /* put amount from worn rings back */ + if (uright && uright->otyp == typ && typ != RIN_PROTECTION) + old += uright->spe; + if (uleft && uleft->otyp == typ && typ != RIN_PROTECTION) + old += uleft->spe; return old + inc; } @@ -1908,7 +1914,7 @@ accessory_has_effect(otmp) struct obj *otmp; { pline("Magic spreads through your body as you digest the %s.", - otmp->oclass == RING_CLASS ? "ring" : "amulet"); + (otmp->oclass == RING_CLASS) ? "ring" : "amulet"); } STATIC_OVL void diff --git a/src/objnam.c b/src/objnam.c index 5fa0ddd42..7de07963c 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1194,7 +1194,9 @@ unsigned doname_flags; Strcat(bp, " (at the ready)"); } } - if (!iflags.suppress_price && is_unpaid(obj)) { + /* treat 'restoring' like suppress_price because shopkeeper and + bill might not be available yet while restore is in progress */ + if (!iflags.suppress_price && !restoring && is_unpaid(obj)) { long quotedprice = unpaid_cost(obj, TRUE); Sprintf(eos(bp), " (%s, %ld %s)", diff --git a/src/restore.c b/src/restore.c index b967e1464..f7e92da76 100644 --- a/src/restore.c +++ b/src/restore.c @@ -35,8 +35,7 @@ STATIC_DCL struct monst *FDECL(restmonchn, (int, BOOLEAN_P)); STATIC_DCL struct fruit *FDECL(loadfruitchn, (int)); STATIC_DCL void FDECL(freefruitchn, (struct fruit *)); STATIC_DCL void FDECL(ghostfruit, (struct obj *)); -STATIC_DCL boolean -FDECL(restgamestate, (int, unsigned int *, unsigned int *)); +STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *)); STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int)); STATIC_DCL int FDECL(restlevelfile, (int, XCHAR_P)); STATIC_OVL void FDECL(restore_msghistory, (int)); @@ -521,6 +520,7 @@ unsigned int *stuckid, *steedid; struct obj *otmp, *tmp_bc; char timebuf[15]; unsigned long uid; + boolean defer_perm_invent; mread(fd, (genericptr_t) &uid, sizeof uid); if (SYSOPT_CHECK_SAVE_UID @@ -531,7 +531,7 @@ unsigned int *stuckid, *steedid; if (!wizard) return FALSE; } - mread(fd, (genericptr_t) &context, sizeof(struct context_info)); + mread(fd, (genericptr_t) &context, sizeof (struct context_info)); if (context.warntype.speciesidx >= LOW_PM) context.warntype.species = &mons[context.warntype.speciesidx]; @@ -539,7 +539,13 @@ unsigned int *stuckid, *steedid; file option values instead of keeping old save file option values if partial restore fails and we resort to starting a new game */ newgameflags = flags; - mread(fd, (genericptr_t) &flags, sizeof(struct flag)); + mread(fd, (genericptr_t) &flags, sizeof (struct flag)); + /* avoid keeping permanent inventory window up to date during restore + (setworn() calls update_inventory); attempting to include the cost + of unpaid items before shopkeeper's bill is available is a no-no; + named fruit names aren't accessible yet either */ + defer_perm_invent = flags.perm_invent; + flags.perm_invent = FALSE; /* wizard and discover are actually flags.debug and flags.explore; player might be overriding the save file values for them; in the discover case, we don't want to set that for a normal @@ -645,14 +651,14 @@ unsigned int *stuckid, *steedid; restlevchn(fd); mread(fd, (genericptr_t) &moves, sizeof moves); mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves); - mread(fd, (genericptr_t) &quest_status, sizeof(struct q_score)); - mread(fd, (genericptr_t) spl_book, sizeof(struct spell) * (MAXSPELL + 1)); + mread(fd, (genericptr_t) &quest_status, sizeof (struct q_score)); + mread(fd, (genericptr_t) spl_book, (MAXSPELL + 1) * sizeof (struct spell)); restore_artifacts(fd); restore_oracles(fd); if (u.ustuck) - mread(fd, (genericptr_t) stuckid, sizeof(*stuckid)); + mread(fd, (genericptr_t) stuckid, sizeof *stuckid); if (u.usteed) - mread(fd, (genericptr_t) steedid, sizeof(*steedid)); + mread(fd, (genericptr_t) steedid, sizeof *steedid); mread(fd, (genericptr_t) pl_character, sizeof pl_character); mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit); @@ -665,6 +671,8 @@ unsigned int *stuckid, *steedid; /* must come after all mons & objs are restored */ relink_timers(FALSE); relink_light_sources(FALSE); + /* inventory display is now viable */ + flags.perm_invent = defer_perm_invent; return TRUE; } diff --git a/src/shknam.c b/src/shknam.c index 43ab8651e..a36b67ec4 100644 --- a/src/shknam.c +++ b/src/shknam.c @@ -602,6 +602,7 @@ struct mkroom *sroom; /* check that the shopkeeper placement is sane */ if (sroom->irregular) { int rmno = (int) ((sroom - rooms) + ROOMOFFSET); + if (isok(sx - 1, sy) && !levl[sx - 1][sy].edge && (int) levl[sx - 1][sy].roomno == rmno) sx--; @@ -613,18 +614,18 @@ struct mkroom *sroom; sy--; else if (isok(sx, sy + 1) && !levl[sx][sy + 1].edge && (int) levl[sx][sy + 1].roomno == rmno) - sx++; + sy++; else goto shk_failed; - } else if (sx == sroom->lx - 1) + } else if (sx == sroom->lx - 1) { sx++; - else if (sx == sroom->hx + 1) + } else if (sx == sroom->hx + 1) { sx--; - else if (sy == sroom->ly - 1) + } else if (sy == sroom->ly - 1) { sy++; - else if (sy == sroom->hy + 1) + } else if (sy == sroom->hy + 1) { sy--; - else { + } else { shk_failed: #ifdef DEBUG /* Said to happen sometimes, but I have never seen it. */ diff --git a/src/sp_lev.c b/src/sp_lev.c index a1b1f6d2a..91412d214 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -786,10 +786,9 @@ link_doors_rooms() void fill_rooms() { - int tmpi; + int tmpi, m; for (tmpi = 0; tmpi < nroom; tmpi++) { - int m; if (rooms[tmpi].needfill) fill_room(&rooms[tmpi], (rooms[tmpi].needfill == 2)); for (m = 0; m < rooms[tmpi].nsubrooms; m++) @@ -2452,6 +2451,9 @@ boolean prefilled; case COURT: case ZOO: case BEEHIVE: + case ANTHOLE: + case COCKNEST: + case LEPREHALL: case MORGUE: case BARRACKS: fill_zoo(croom); diff --git a/src/trap.c b/src/trap.c index 8f62dcc63..1c106890b 100644 --- a/src/trap.c +++ b/src/trap.c @@ -595,7 +595,7 @@ int *fail_reason; if (use_saved_traits) { /* restore a petrified monster */ cc.x = x, cc.y = y; - mon = montraits(statue, &cc); + mon = montraits(statue, &cc, (cause == ANIMATE_SPELL)); if (mon && mon->mtame && !mon->isminion) wary_dog(mon, TRUE); } else { diff --git a/src/wield.c b/src/wield.c index c45282a14..1063e125b 100644 --- a/src/wield.c +++ b/src/wield.c @@ -112,7 +112,6 @@ register struct obj *obj; : !is_weptool(obj) && !is_wet_towel(obj); } else unweapon = TRUE; /* for "bare hands" message */ - update_inventory(); } STATIC_OVL boolean @@ -230,7 +229,9 @@ setuqwep(obj) register struct obj *obj; { setworn(obj, W_QUIVER); - update_inventory(); + /* no extra handling needed; this used to include a call to + update_inventory() but that's already performed by setworn() */ + return; } void @@ -238,7 +239,7 @@ setuswapwep(obj) register struct obj *obj; { setworn(obj, W_SWAPWEP); - update_inventory(); + return; } /*** Commands to change particular slot(s) ***/ diff --git a/src/worn.c b/src/worn.c index 828e6a902..e7860c655 100644 --- a/src/worn.c +++ b/src/worn.c @@ -106,8 +106,7 @@ long mask; } } } - if (!restoring) - update_inventory(); + update_inventory(); } /* called e.g. when obj is destroyed */ @@ -138,9 +137,7 @@ register struct obj *obj; if ((p = w_blocks(obj, wp->w_mask)) != 0) u.uprops[p].blocked &= ~wp->w_mask; } - /* setnotworn() isn't called during restore but parallel setworn() */ - if (!restoring) - update_inventory(); + update_inventory(); } /* return item worn in slot indiciated by wornmask; needed by poly_obj() */ diff --git a/src/zap.c b/src/zap.c index 1b83a3ad5..966ac914e 100644 --- a/src/zap.c +++ b/src/zap.c @@ -555,9 +555,10 @@ int locflags; /* non-zero means get location even if monster is buried */ /* used by revive() and animate_statue() */ struct monst * -montraits(obj, cc) +montraits(obj, cc, adjacentok) struct obj *obj; coord *cc; +boolean adjacentok; /* False: at obj's spot only, True: nearby is allowed */ { struct monst *mtmp = (struct monst *) 0; struct monst *mtmp2 = (struct monst *) 0; @@ -570,7 +571,8 @@ coord *cc; if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data)) return (struct monst *) 0; mtmp = makemon(mtmp2->data, cc->x, cc->y, - NO_MINVENT | MM_NOWAIT | MM_NOCOUNTBIRTH); + (NO_MINVENT | MM_NOWAIT | MM_NOCOUNTBIRTH + | (adjacentok ? MM_ADJACENTOK : 0))); if (!mtmp) return mtmp; @@ -786,7 +788,7 @@ boolean by_hero; } else if (has_omonst(corpse)) { /* use saved traits */ xy.x = x, xy.y = y; - mtmp = montraits(corpse, &xy); + mtmp = montraits(corpse, &xy, FALSE); if (mtmp && mtmp->mtame && !mtmp->isminion) wary_dog(mtmp, TRUE); } else {