From 2edf27f0f0edb6fb75ae8f68ee788ee51220e9ca Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 4 Jun 2026 15:36:12 -0400 Subject: [PATCH] aklys fixes track which locations had updates that could be seen in tmp_at() to aid in cleanup. ensure that nothing is shown for places that the hero can't see (internal buglist entry 3161). adjust several aklys messages to better reflect the tethering aspect. --- src/display.c | 77 ++++++++++++++++++++++++++++++++----------- src/dothrow.c | 90 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 125 insertions(+), 42 deletions(-) diff --git a/src/display.c b/src/display.c index 6f4f5f74a..e1e301905 100644 --- a/src/display.c +++ b/src/display.c @@ -1164,6 +1164,7 @@ tether_glyph(coordxy x, coordxy y) static struct tmp_glyph { coord saved[TMP_AT_MAX_GLYPHS]; /* previously updated positions */ + boolean shown_on_map[TMP_AT_MAX_GLYPHS]; int sidx; /* index of next unused slot in saved[] */ int style; /* either DISP_BEAM or DISP_FLASH or DISP_ALWAYS */ int glyph; /* glyph to use when printing */ @@ -1175,6 +1176,7 @@ tmp_at(coordxy x, coordxy y) { static struct tmp_glyph *tglyph = (struct tmp_glyph *) 0; struct tmp_glyph *tmp; + boolean suppress_show = FALSE; switch (x) { case DISP_BEAM: @@ -1220,27 +1222,42 @@ tmp_at(coordxy x, coordxy y) int i; /* Erase (reset) from source to end */ - for (i = 0; i < tglyph->sidx; i++) + for (i = 0; i < tglyph->sidx; i++) { newsym(tglyph->saved[i].x, tglyph->saved[i].y); + tglyph->shown_on_map[i] = FALSE; + } } else if (tglyph->style == DISP_TETHER) { int i; if (y == BACKTRACK && tglyph->sidx > 1) { /* backtrack */ for (i = tglyph->sidx - 1; i > 0; i--) { - newsym(tglyph->saved[i].x, tglyph->saved[i].y); - show_glyph(tglyph->saved[i - 1].x, - tglyph->saved[i - 1].y, tglyph->glyph); - flush_screen(0); /* make sure it shows up */ - nh_delay_output(); + if (tglyph->shown_on_map[i]) { + newsym(tglyph->saved[i].x, tglyph->saved[i].y); + tglyph->shown_on_map[i] = FALSE; + } + if (cansee(tglyph->saved[i - 1].x, + tglyph->saved[i - 1].y)) { + tglyph->shown_on_map[i - 1] = TRUE; + show_glyph(tglyph->saved[i - 1].x, + tglyph->saved[i - 1].y, tglyph->glyph); + flush_screen(0); /* make sure it shows up */ + nh_delay_output(); + } } tglyph->sidx = 1; } - for (i = 0; i < tglyph->sidx; i++) - newsym(tglyph->saved[i].x, tglyph->saved[i].y); + for (i = 0; i < tglyph->sidx; i++) { + if (tglyph->shown_on_map[i]) + newsym(tglyph->saved[i].x, tglyph->saved[i].y); + } } else { /* DISP_FLASH or DISP_ALWAYS */ - if (tglyph->sidx) /* been called at least once */ - newsym(tglyph->saved[0].x, tglyph->saved[0].y); + if (tglyph->sidx) { /* been called at least once */ + if (tglyph->shown_on_map[0]) { + newsym(tglyph->saved[0].x, tglyph->saved[0].y); + tglyph->shown_on_map[0] = FALSE; + } + } } /* tglyph->sidx = 0; -- about to be freed, so not necessary */ tmp = tglyph->prev; @@ -1253,10 +1270,13 @@ tmp_at(coordxy x, coordxy y) if (!isok(x, y)) break; if (tglyph->style == DISP_BEAM || tglyph->style == DISP_ALL) { - if (tglyph->style != DISP_ALL && !cansee(x, y)) - break; if (tglyph->sidx >= TMP_AT_MAX_GLYPHS) break; /* too many locations */ + if (tglyph->style != DISP_ALL && !cansee(x, y)) { + tglyph->shown_on_map[tglyph->sidx] = FALSE; + suppress_show = TRUE; + break; + } /* save pos for later erasing */ tglyph->saved[tglyph->sidx].x = x; tglyph->saved[tglyph->sidx].y = y; @@ -1269,27 +1289,48 @@ tmp_at(coordxy x, coordxy y) px = tglyph->saved[tglyph->sidx - 1].x; py = tglyph->saved[tglyph->sidx - 1].y; - show_glyph(px, py, tether_glyph(px, py)); + if (cansee(px, py)) { + tglyph->shown_on_map[tglyph->sidx - 1] = TRUE; + show_glyph(px, py, tether_glyph(px, py)); + } else { + tglyph->shown_on_map[tglyph->sidx - 1] = FALSE; + suppress_show = TRUE; + } } /* save pos for later use or erasure */ tglyph->saved[tglyph->sidx].x = x; tglyph->saved[tglyph->sidx].y = y; + if (!cansee(x, y)) { + tglyph->shown_on_map[tglyph->sidx] = FALSE; + suppress_show = TRUE; + } else { + /* happens at end of this default case */ + tglyph->shown_on_map[tglyph->sidx] = TRUE; + } tglyph->sidx += 1; } else { /* DISP_FLASH/ALWAYS */ - if (tglyph - ->sidx) { /* not first call, so reset previous pos */ + if (tglyph->sidx) { /* not first call, so reset previous pos */ newsym(tglyph->saved[0].x, tglyph->saved[0].y); + tglyph->shown_on_map[0] = FALSE; tglyph->sidx = 0; /* display is presently up to date */ } - if (!cansee(x, y) && tglyph->style != DISP_ALWAYS) + if (!cansee(x, y) && tglyph->style != DISP_ALWAYS) { + suppress_show = TRUE; + tglyph->shown_on_map[0] = FALSE; break; + } else { + /* happens at end of this default case */ + tglyph->shown_on_map[0] = TRUE; + } tglyph->saved[0].x = x; tglyph->saved[0].y = y; tglyph->sidx = 1; } - show_glyph(x, y, tglyph->glyph); /* show it */ - flush_screen(0); /* make sure it shows up */ + if (!suppress_show) { + show_glyph(x, y, tglyph->glyph); /* show it */ + flush_screen(0); /* make sure it shows up */ + } break; } /* end switch */ } diff --git a/src/dothrow.c b/src/dothrow.c index 1d729ef69..82028f321 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1729,46 +1729,88 @@ throwit( } else { int dmg = rn2(2); + if (tethered_weapon) { + /* It's tethered, so it usually returns to your + * inventory, despite impairment */ + obj = addinv_before(obj, oldslot); + encumber_msg(); + /* addinv autoquivers an aklys if quiver is empty; + if obj is quivered, remove it before wielding */ + if (obj->owornmask & W_QUIVER) + setuqwep((struct obj *) 0); +#if 0 + setuwep(obj); + set_twoweap(twoweap); /* u.twoweap = twoweap */ +#endif + if (cansee(gb.bhitpos.x, gb.bhitpos.y)) + newsym(gb.bhitpos.x, gb.bhitpos.y); + } if (!dmg) { - pline(Blind ? "%s lands %s your %s." - : "%s back to you, landing %s your %s.", - Blind ? Something : Tobjnam(obj, "return"), - Levitation ? "beneath" : "at", - makeplural(body_part(FOOT))); + if (tethered_weapon) { + pline(Blind ? "%s%s back and is left" + " dangling from your %s." + : "%s is left dangling from your %s.", + Blind ? "Your tethered weapon" : Tobjnam(obj, "return"), + Blind ? " snaps" : "", + body_part(ARM)); + } else { + pline(Blind + ? "%s lands %s your %s." + : "%s back to you, landing %s your %s.", + Blind ? Something : Tobjnam(obj, "return"), + Levitation ? "beneath" : "at", + makeplural(body_part(FOOT))); + } } else { dmg += rnd(3); - pline(Blind ? "%s your %s!" + if (tethered_weapon) { + Your("tethered %s your %s!", + Blind ? "weapon returns and hits" : Tobjnam(obj, "hit"), + body_part(ARM)); + } else { + pline( + Blind + ? "%s your %s!" : "%s back toward you, hitting your %s!", - Tobjnam(obj, Blind ? "hit" : "fly"), - body_part(ARM)); + Tobjnam(obj, Blind ? "hit" : "fly"), + body_part(ARM)); + } if (obj->oartifact) (void) artifact_hit((struct monst *) 0, &gy.youmonst, obj, &dmg, 0); losehp(Maybe_Half_Phys(dmg), killer_xname(obj), KILLED_BY); } - - if (u.uswallow) { - swallowit(obj); - return; + if (!tethered_weapon) { + if (u.uswallow) { + swallowit(obj); + return; + } + if (!ship_object(obj, u.ux, u.uy, FALSE)) + dropy(obj); + } else { + pline_The("%s tether releases from your %s!", + s_suffix(simpleonames(obj)), body_part(ARM)); } - if (!ship_object(obj, u.ux, u.uy, FALSE)) - dropy(obj); } throwit_return(TRUE); return; } else { - if (tethered_weapon) + if (tethered_weapon) { tmp_at(DISP_END, 0); - /* when this location is stepped on, the weapon will be - auto-picked up due to 'obj->how_lost' of LOST_THROWN; - addinv() prevents thrown Mjollnir from being placed - into the quiver slot, but an aklys will end up there if - that slot is empty at the time; since hero will need to - explicitly rewield the weapon to get throw-and-return - capability back anyway, quivered or not shouldn't matter */ - pline("%s to return!", Tobjnam(obj, "fail")); - + /* when this location is stepped on, the weapon will be + auto-picked up due to 'obj->how_lost' of LOST_THROWN; + addinv() prevents thrown Mjollnir from being placed + into the quiver slot, but an aklys will end up there if + that slot is empty at the time; since hero will need to + explicitly rewield the weapon to get throw-and-return + capability back anyway, quivered or not shouldn't + matter */ + pline("The tether snaps off your %s!", + body_part(ARM)); + } else { + pline("%s to return!", Tobjnam(obj, "fail")); + } if (u.uswallow) { swallowit(obj); return;