From 335e868865938136e6e65516920ae93d0be17760 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 3 Jul 2018 14:59:34 -0700 Subject: [PATCH 1/5] fix github issue #111 - stone-to-flesh of statues Fixes #111 Casting stone-to-flesh at a random statue animates it as a monster (created via direct call to makemon()) at an adjacent or nearby spot if there is already a monster at the statue's spot, but doing so on a statue of a petrified monster (create attempt via montraits() which called makemon() without the ADJACENTOK flag) turned it into a corpse instead. Pass an extra argument to montraits() so that it behaves the same normal statue animation for stone-to-flesh without changing how it behaves when reviving corpses for undead-turning. --- doc/fixes36.2 | 5 ++++- include/extern.h | 2 +- src/trap.c | 2 +- src/zap.c | 8 +++++--- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 23b699ac4..d2cfcdd62 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -54,7 +54,10 @@ 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) 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/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/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 { From a7daa522a4e33a1a29cf082ed60c74742e2b4d8e Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 3 Jul 2018 15:49:44 -0700 Subject: [PATCH 2/5] fix github pull request #114 - ant holes in *.des Fixes #114 Report and contributed fix described lack of support for room type "ant hole" in the code that loads special levels (and mentioned that none of our des files attempted to use that room type so it isn't noticeable in unmodified version of the game). The fix overlooked a couple of other missing room types (leprechaun hall and cockatrice nest) so I didn't use the pull-request's commit (so not sure what github's automated updating will make of 'Fixes #114'). --- doc/fixes36.2 | 2 ++ src/sp_lev.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index d2cfcdd62..a4c3a8f09 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -58,6 +58,8 @@ when using 'O' to set hilite_status rules, hide the 'score' status field if 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) Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository 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); From faa85e23b47cd8007266670653a03c627efaf363 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 3 Jul 2018 16:39:34 -0700 Subject: [PATCH 3/5] fix #H7256 - bug WRT eating rings Wearing a negatively enchanted ring of increase would enhance the bonus gained from eating another ring of the same type when you got "the magic spreads through your body" effect so could be eploited. Conversely, wearing a positively enchanted one would make you lose that worn amount when gaining any bonus from eating one. --- doc/fixes36.2 | 2 ++ src/eat.c | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index a4c3a8f09..d4fbba9f2 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -60,6 +60,8 @@ make stone-to-flesh behave the same on statues of petrified monsters as it 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 Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository 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 From 2596052c39d925771a89b55e61ba69e01317dc08 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 4 Jul 2018 19:26:59 -0700 Subject: [PATCH 4/5] github pull request #113 - shopkeeper placement Fixes #113 Incorporate the contents of pull request #113 to fix shopkeeper setup for irregularly shaped shop rooms. Code intending to adjust the Y coordinate was erroneously incrementing the X one instead. (I'm not sure whether we have any irregular shops at all but if so, they don't have the necessary orientation to trigger this bug.) And add a couple of formatting tweaks in the vicinity.... --- doc/fixes36.2 | 3 +++ src/shknam.c | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index d4fbba9f2..ff9b89d18 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -62,6 +62,9 @@ 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) Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository 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. */ From 777d9d922d29420a2ce9eb7d3bfa1f40b172ae76 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 5 Jul 2018 16:06:31 -0700 Subject: [PATCH 5/5] restore vs perm_invent Redo how updates of permanent inventory window are suppressed during restore. Reverses part of e9f1e032717921cb7a51c0f2822628355a35ec36 which included a simpler attempt to deal with this. It looks like we should have been getting impossible "unpaid_cost: object wasn't on any bill" but segfault was reported; I haven't tried to figure out why. The band in xname() ought to be redundant now but is included for bulletproofing. --- doc/fixes36.2 | 3 +++ src/objnam.c | 4 +++- src/restore.c | 24 ++++++++++++++++-------- src/wield.c | 7 ++++--- src/worn.c | 7 ++----- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index ff9b89d18..5e1d1ad9d 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -65,6 +65,9 @@ eating rings while polymorphed didn't handle bonus/penalty for increase damage, 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/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/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() */