fix(skills): remove translucent solid light boxes during cast overlay animation (#386, #395)

This commit is contained in:
troytt 2026-09-23 06:14:11 +00:00
parent 88bb16238d
commit 15948eb896
2 changed files with 9 additions and 32 deletions

View File

@ -3792,44 +3792,15 @@ export async function loadOverlayArtMap(
* Render a Diablo II 1.13c character cast overlay effect: * Render a Diablo II 1.13c character cast overlay effect:
* - Uses authentic baked DCC sprite atlas with additive blending (Trans === 3) when available. * - Uses authentic baked DCC sprite atlas with additive blending (Trans === 3) when available.
* - Respects frame anchorX and anchorY offsets to align with caster's origin. * - Respects frame anchorX and anchorY offsets to align with caster's origin.
* - Projects a dynamic point light with authentic 1.13c light colors and radius.
* - Falls back to procedural magic glow in test/offline environments. * - Falls back to procedural magic glow in test/offline environments.
* - Dynamic lighting/light mask rendering deferred to issue #395.
*/ */
export function drawCastOverlay( export function drawCastOverlay(
renderer: SpriteRenderer, renderer: SpriteRenderer,
overlay: ActiveOverlay, overlay: ActiveOverlay,
overlayArt?: LoadedOverlayArt, overlayArt?: LoadedOverlayArt,
): void { ): void {
// 1. Dynamic point light halo (1.13c colors & radius) // 1. Sprite animation with additive blending
const [r255, g255, b255] = overlay.lightColor
const r = r255 / 255
const g = g255 / 255
const b = b255 / 255
const radius = overlay.lightRadius > 0 ? overlay.lightRadius * 5 : 45
const progress = Math.min(1, Math.max(0, overlay.frame / overlay.maxFrames))
const intensity = Math.sin(progress * Math.PI) * 0.35 + 0.15
if (intensity > 0.01) {
renderer.drawSolid(
overlay.x - radius,
overlay.y - radius,
radius * 2,
radius * 2,
[r, g, b, intensity * 0.25],
{ blendMode: 'additive' },
)
const coreRadius = radius * 0.5
renderer.drawSolid(
overlay.x - coreRadius,
overlay.y - coreRadius,
coreRadius * 2,
coreRadius * 2,
[r, g, b, intensity * 0.5],
{ blendMode: 'additive' },
)
}
// 2. Sprite animation with additive blending
if (overlayArt !== undefined) { if (overlayArt !== undefined) {
const frameCount = Math.max(1, overlayArt.meta.framesPerDirection || overlayArt.meta.frames) const frameCount = Math.max(1, overlayArt.meta.framesPerDirection || overlayArt.meta.frames)
const frameIndex = Math.min(Math.max(0, Math.floor(overlay.frame)), frameCount - 1) const frameIndex = Math.min(Math.max(0, Math.floor(overlay.frame)), frameCount - 1)
@ -3844,7 +3815,11 @@ export function drawCastOverlay(
} }
} }
// 3. Fallback procedural representation in test/offline environments // 2. Fallback procedural representation in test/offline environments
const [r255, g255, b255] = overlay.lightColor
const r = r255 / 255
const g = g255 / 255
const b = b255 / 255
const fallbackRadius = 16 const fallbackRadius = 16
renderer.drawSolid( renderer.drawSolid(
overlay.x - fallbackRadius, overlay.x - fallbackRadius,

View File

@ -522,6 +522,8 @@ describe('Issue #386 — Diablo II v1.13c Cast Overlay Parity', () => {
drawCastOverlay(rendererMock as any, overlay, dummyArt) drawCastOverlay(rendererMock as any, overlay, dummyArt)
expect(draws.length).toBe(1) expect(draws.length).toBe(1)
// Verify no residual translucent solid boxes are drawn when overlay art is rendered
expect(solids.length).toBe(0)
const drawCall = draws[0]! const drawCall = draws[0]!
expect(drawCall.options.blendMode).toBe('additive') expect(drawCall.options.blendMode).toBe('additive')