fix white screen flash on shake on versions > 1.3.0

This commit is contained in:
DramaticShape
2026-07-28 16:10:58 -04:00
parent 2e0ae37bcd
commit d8d1d7e336
6 changed files with 72 additions and 8 deletions
+12
View File
@@ -1,5 +1,17 @@
# Changelog
## 1.1.1
### Fixed
- A move that shakes the screen no longer whites out the frame. The zone pass
fills each zone with its blank colour before drawing the shifted copy -- the
hardware showing empty BG in the strip the shake vacated -- and a shake
program alternates offset and no-offset frames, so over the map that read as
the whole battle screen, menu box included, flashing white a few times a
second. The fill is dropped while a battle is staged on the map; the shake
itself still moves the HUD.
## 1.2.0
### Added
+12 -4
View File
@@ -278,10 +278,16 @@ end
-- yet (the terrain mesh is still building, the driver has no depth support).
-- nil is not a failure: the caller simply leaves the battle screen as the
-- engine drew it for that frame.
-- White, for the hit flash. The shader replaces the card's colour outright
-- rather than multiplying it, so this is the sprite's own silhouette turned
-- solid white -- not a lightened picture of itself.
-- White, for the hit flash, and how far toward it the card goes.
--
-- The shader replaces the card's colour rather than multiplying it, so at
-- full strength this is the sprite turned into a solid white silhouette --
-- which is what the effect is on a flat GB screen and far too much on a
-- sprite standing in a lit world. Held well short of 1, the mon's own
-- shading still reads through the flash: it looks struck rather than
-- deleted.
BattleScene.FLASH_COLOR = { 1, 1, 1 }
BattleScene.FLASH_STRENGTH = 0.5
function BattleScene.render(state, arena, textures, token)
if not (state and state.map and arena) then return nil end
@@ -369,7 +375,9 @@ function BattleScene.render(state, arena, textures, token)
-- (see OverworldBattle) and put back HERE, on the two things it was ever
-- about: the mons themselves go solid white for those frames.
local flashing = textures and textures.flash
if flashing then Voxel3D.flatten(BattleScene.FLASH_COLOR) end
if flashing then
Voxel3D.flatten(BattleScene.FLASH_COLOR, BattleScene.FLASH_STRENGTH)
end
for _, card in ipairs(monCards(arena, groundY, textures)) do
Voxel3D.draw(BattleBillboard.mesh(), card.tex, card.model,
BattleBillboard.PULL)
+41
View File
@@ -645,6 +645,47 @@ function OverworldBattle.install()
if not ok then error(err, 0) end
end
-- The engine's flash has a SECOND half, and it is the one that reaches the
-- menu. Beside the white rectangle (dropped above) the flash moves are
-- driven by a BGP palette fade -- BGP_LIGHT and friends -- which the
-- colorized pipeline applies in drawZonePass to the WHOLE background
-- canvas. That canvas carries the HUD glyphs and the text box, so a fade
-- meant for the two mons washed the menu out with them.
--
-- The fade is left switched on for the pics, which read it through
-- picImage, and switched off for the zone pass alone. So the mons flash
-- and the furniture around them does not.
--
-- The zone pass has a SECOND thing it paints, and this is the one that
-- reads as the menu box flashing. A screen shake makes it fill every zone
-- with the zone's own color 0 before it draws the offset copy -- the
-- hardware showing empty BG in the strip the shake vacated. On a white
-- battle field that fill is invisible; over a world it is an opaque white
-- sheet across the whole frame, and since a shake program alternates
-- offset and no-offset frames (SE_SHAKE_SCREEN steps dx 1, 0, 1, 0...) it
-- switches on and off a few times a second. It is dropped: the background
-- here is the map, so what the shake vacates should show the map.
local innerZone = BattleState.drawZonePass
function BattleState:drawZonePass(src, sx, sy)
if not self.dramaticShapeShot then return innerZone(self, src, sx, sy) end
-- shadow the method on the instance for this call only; putting the
-- field back to whatever it was (normally nil) lets the class method be
-- found again
local had = rawget(self, "activeBgp")
self.activeBgp = function() return nil end
local g = love.graphics
local rectangle = g.rectangle
g.rectangle = function(mode, ...)
-- the pass draws no other rectangle; the shake still shifts the copy
if mode == "fill" then return end
return rectangle(mode, ...)
end
local ok, err = pcall(innerZone, self, src, sx, sy)
g.rectangle = rectangle
self.activeBgp = had
if not ok then error(err, 0) end
end
-- Black glyphs on grass are not readable; over a frosted panel measured
-- dark they are not readable either, so they go white. Mapped rather than
-- rewritten: the HUD sets pure black for its text and nothing else, and in
+5 -2
View File
@@ -544,12 +544,15 @@ end
-- simply wants to come out one colour, which is what a hit flash on a sprite
-- is. beginScene resets the uniform every frame, so a pass that forgets to
-- clear it cannot leak into the next one.
function Voxel3D.flatten(color)
-- `amount` is how far toward that colour, 0..1; omitted is all the way.
-- Anything short of 1 leaves the sprite's own shading showing through, which
-- is the difference between a hit flash and a white cut-out.
function Voxel3D.flatten(color, amount)
if not (active and activeShader) then return end
local sh = activeShader
if color then
pcall(sh.send, sh, "ghostColor", color)
pcall(sh.send, sh, "ghost", 1)
pcall(sh.send, sh, "ghost", math.max(0, math.min(1, amount or 1)))
else
pcall(sh.send, sh, "ghost", 0)
end
+1 -1
View File
@@ -620,7 +620,7 @@ mod.events:on("battle.ended", function()
OverworldBattle.finish()
end)
mod.exports.version = "1.2.0"
mod.exports.version = "1.1.1"
-- exposed so a companion mod can pin its own tiles' shapes or read the
-- camera without reaching into this mod's file layout
mod.exports.lib = V
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "DRAMATIC_SHAPE",
"name": "Dramatic Shape Voxel Mod",
"version": "1.2.0",
"version": "1.1.1",
"api": 2,
"entry": "main.lua",
"profile": "content",