fix: residents step aside instead of trading pixels with the hero (#9) - #43
fix: residents step aside instead of trading pixels with the hero (#9)#43blippip69 wants to merge 2 commits into
Conversation
| let heroGeom = null | ||
| { | ||
| const lines_ = Array.isArray(hero.sprite) && hero.sprite.length ? hero.sprite : null | ||
| if (lines_) { | ||
| const hw = lines_.reduce((widest, line) => Math.max(widest, ascii(line).length), 1) | ||
| const hLeft = hx - clamp(HERO_ANCHOR_X, 0, hw - 1) | ||
| const heroAnchorY = Number.isFinite(Number(hero.anchorY)) | ||
| ? Math.round(Number(hero.anchorY)) | ||
| : lines_.length - 1 | ||
| const hTop = hy - clamp(heroAnchorY, 0, lines_.length - 1) | ||
| heroGeom = { left: hLeft, width: hw } | ||
| const solidView = { rows: tiles, width: mapW, height: mapH } | ||
| for (let sy = 0; sy < lines_.length; sy++) { | ||
| const line = ascii(lines_[sy]).padEnd(hw) | ||
| const first = line.search(/\S/) |
There was a problem hiding this comment.
⚠️ Bug: heroGeom null deref crashes glyph-hero + overlapping actor
When the hero has no sprite (glyph fallback), the reservation block leaves heroGeom = null but still reserves the hero cell hy,hx. If an actor's drawn footprint covers that cell, collidesHero(left) returns true and the code dereferences heroGeom.left/heroGeom.width (lines 831-832), throwing TypeError: Cannot read properties of null and crashing the render. Set a fallback geometry in the else branch (e.g. heroGeom = { left: hx, width: 1 }) so the separation maths works for glyph heroes too.
Give the glyph-hero fallback a valid geometry so the actor step-aside pass never dereferences null.:
} else {
heroReserved.add(hy + ',' + hx)
heroGeom = { left: hx, width: 1 }
}
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| // Reservation pass: the exact cells the hero is about to paint, computed | ||
| // with the same maths as the hero pass below (including the #16 solid clip). | ||
| const heroReserved = new Set() | ||
| const actorOccupied = new Set() |
There was a problem hiding this comment.
💡 Quality: actorOccupied set is populated but never read
actorOccupied is declared at line 759 and written to at line 859 but never read anywhere in the function or elsewhere in the file. It is dead code that adds per-cell overhead each frame. Remove the declaration and the .add() call unless a follow-up consumer is intended.
Was this helpful? React with 👍 / 👎
|
|
||
| const actorW = actorSprite.reduce((widest, line) => Math.max(widest, ascii(line).length), 1) | ||
| const left = ax - Math.floor(actorW / 2) | ||
| const actorW = actorSprite.reduce((widest, line) => Math.max(widest, line.length), 1) |
There was a problem hiding this comment.
💡 Bug: actorW uses raw length, diverging from ascii-normalized paint
The reservation/paint loops normalize actor sprite rows with ascii(...).padEnd(actorW), but actorW is now computed from raw line.length (line 804) after this PR dropped the previous ascii(line).length. For sprites containing astral (surrogate-pair) characters the two widths disagree, so padEnd(actorW) and the collision scan can misalign. NPC art is currently ASCII so impact is latent; restore ascii(line).length to keep width computation consistent with rendering.
Compute actorW from the ascii-normalized width, matching the loops that render the sprite.:
const actorW = actorSprite.reduce((widest, line) => Math.max(widest, ascii(line).length), 1)
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
The overlay loop painted every hero cell unconditionally, so the rows of the body that hang above the feet landed on solid tiles and off-map cells and read as holes in the wall, most visibly on every dungeon arrival. Hero cells are now skipped when the tile beneath them is solid, checked against the canonical isSolid table instead of render-local guesses.
…tcoindefi#9) A resident sprite is seven columns wide but blocks one logical cell, and talk distance reaches one or two tiles, so the hero body and the resident body shared screen cells and overwrote each other exactly when e hablar mattered. mapPane now reserves the cells the hero is about to paint and slides a colliding resident drawing sideways - the same presentation-only separation fieldPane applies to an active foe - clamped to the camera, falling back to skipping just the contested cells. Logical positions, collision and interaction range stay untouched. Stacked on the Bitcoindefi#16 clip, whose solid-cell reservation it reuses.
bfca610 to
98f69ee
Compare
Code Review
|
| Auto-apply | Compact |
|
|
Important
Your trial ends in 7 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.
Was this helpful? React with 👍 / 👎 | Gitar
|
Merged onto current The repository runs
|
fix: residents step aside instead of trading pixels with the hero (#9)
Summary by Gitar
#16)#9,#16)This will update automatically on new commits.