diff --git a/src/battle/BattleState.lua b/src/battle/BattleState.lua index 58f80d59..ec26c48b 100644 --- a/src/battle/BattleState.lua +++ b/src/battle/BattleState.lua @@ -234,7 +234,11 @@ local imageMeta = setmetatable({}, WEAK_KEYS) -- entirely, so its palette variant collapses back onto the plain path. local function getImage(path, pal, trueColor) if not path then return nil end - if trueColor then pal = nil end + if trueColor and require("src.render.PaletteFX").honorsTrueColor() then + pal = nil + else + trueColor = nil + end local key = pal and (path .. "#" .. pal.name) or path if not imageCache[key] then local img, pad, padL = nil, 0, 0 diff --git a/src/render/PaletteFX.lua b/src/render/PaletteFX.lua index 461a29c8..e920b739 100644 --- a/src/render/PaletteFX.lua +++ b/src/render/PaletteFX.lua @@ -305,6 +305,13 @@ function PaletteFX.usesGbcPack(mode) return mode == "redpp" end +function PaletteFX.honorsTrueColor() + if GameVersion.generation() >= 2 then + return require("src.render.GbcPalette").mode == "gbc" + end + return PaletteFX.mode == "redpp" +end + -- Yellow's authentic GBC look is CGBBasePalettes (per-map), not a boot-ROM -- auto-palette. The shared `ogred` save id wears that table on a Yellow -- playthrough and labels itself "OG YELLOW". diff --git a/src/render/Renderer.lua b/src/render/Renderer.lua index ff744222..e9d71727 100644 --- a/src/render/Renderer.lua +++ b/src/render/Renderer.lua @@ -641,6 +641,7 @@ end -- or empty zone list is left alone: that already draws the whole canvas -- unshaded, which is what the rects were asking for. local function withTrueColor(zoneList, pass) + if not PaletteFX.honorsTrueColor() then return zoneList end local rects = PaletteFX.trueColorRects(pass) if not (rects[1] and zoneList and zoneList[1]) then return zoneList end local merged = {} diff --git a/src/render/SpriteRenderer.lua b/src/render/SpriteRenderer.lua index 94909836..9983e27f 100644 --- a/src/render/SpriteRenderer.lua +++ b/src/render/SpriteRenderer.lua @@ -234,8 +234,12 @@ function SpriteRenderer:gen2Obp() self.objGroup .. "|" .. tostring(GbcPalette.mode) end +local function liveTrueColor(def) + return def and def.trueColor and PaletteFX.honorsTrueColor() +end + function SpriteRenderer:resolveImage() - if self.def.trueColor then return self.image end + if liveTrueColor(self.def) then return self.image end if self.objColors then return getObpImage(self.def.image, self:gen2Obp()) end @@ -289,7 +293,7 @@ function SpriteRenderer:draw(px, py, camX, camY, facing, walkPhase, stepFlip, local redraw = false -- True-color sheets bypass every palette bake; the screen-space exemption -- is recorded below once the final frame/height is known. - if self.def.trueColor then + if liveTrueColor(self.def) then image = self.image elseif self.objColors then -- Gen 2: the palette came from the caller (setObjPalette). Like RED++ @@ -349,7 +353,7 @@ function SpriteRenderer:draw(px, py, camX, camY, facing, walkPhase, stepFlip, drawHeight = math.max(1, self.frameHeight - math.min(8, self.frameHeight)) end -- Full-color art claims exactly the portion of the frame that was drawn. - if self.def.trueColor then + if liveTrueColor(self.def) then PaletteFX.markTrueColor(x, y, self.frameWidth, drawHeight) end blitFrame(image, quad, x, y, flip, redraw, self.frameWidth) @@ -362,7 +366,7 @@ end -- raw DMG shades (#384). function SpriteRenderer:drawTile(path, x, y, flip) local image, redraw = getImage(path), false - if self.def.trueColor then + if liveTrueColor(self.def) then PaletteFX.markTrueColor(x, y, 16, 8) elseif PaletteFX.usesGbcPack() then local colors, group = PaletteFX.spriteObp(self.def, self.seed) diff --git a/src/ui/gen2/BattleState.lua b/src/ui/gen2/BattleState.lua index c2d33a5d..9254d2b9 100644 --- a/src/ui/gen2/BattleState.lua +++ b/src/ui/gen2/BattleState.lua @@ -740,7 +740,8 @@ function BattleState:drawPic(mon, back) -- pokemon.sprite's ctx.trueColor, the same flag Gen 1's Sprites.path hands -- back to its own draw site. local function paint() - if colors and not trueColor and GbcPalette.available() then + if colors and not (trueColor and GbcPalette.mode == "gbc") + and GbcPalette.available() then GbcPalette.with(colors, body) else body() diff --git a/tests/gen2_big_object_test.lua b/tests/gen2_big_object_test.lua index 15144bd0..f7387578 100644 --- a/tests/gen2_big_object_test.lua +++ b/tests/gen2_big_object_test.lua @@ -126,6 +126,9 @@ end -- ---- and the draw picks the right table ----------------------------------- do + local PaletteFX = require("src.render.PaletteFX") + local savedColors = PaletteFX.mode + PaletteFX.setMode("redpp") local G = love.graphics local realDraw = G.draw local blits @@ -147,6 +150,7 @@ do "with the doll's own sprite deciding which, the way SetFacingBigDoll does") G.draw = realDraw + PaletteFX.setMode(savedColors) end -- ---- WillObjectIntersectBigObject ----------------------------------------- diff --git a/tests/mod_graphics_tests.lua b/tests/mod_graphics_tests.lua index 37ccc2a1..5b9ff89d 100644 --- a/tests/mod_graphics_tests.lua +++ b/tests/mod_graphics_tests.lua @@ -364,12 +364,6 @@ local r, g, b = shaded.data:getPixel(0, 0) check(r == 0 and g == 0 and b == 1, "a 4-shade pic is palette-quantized onto its shade bucket") -local full = battle:speciesSprite("FULLCOLOR", false) -r, g, b = full.data:getPixel(0, 0) -check(math.abs(r - 0.4) < 1e-6 and math.abs(g - 0.7) < 1e-6 - and math.abs(b - 0.9) < 1e-6, - "a trueColor pic keeps a pixel no 4-shade palette contains") - -- trainers.trueColor is the same opt-out on a class portrait BattleState.invalidate() local trainerPicData = { @@ -386,6 +380,14 @@ local shadedTrainer = BattleState.trainerSprite(trainerPicData, r, g, b = shadedTrainer.data:getPixel(0, 0) check(r == 0 and g == 0 and b == 1, "a 4-shade trainer pic is palette-quantized onto its shade bucket") + +local savedColors = PaletteFX.mode +PaletteFX.setMode("redpp") +local full = battle:speciesSprite("FULLCOLOR", false) +r, g, b = full.data:getPixel(0, 0) +check(math.abs(r - 0.4) < 1e-6 and math.abs(g - 0.7) < 1e-6 + and math.abs(b - 0.9) < 1e-6, + "a trueColor pic keeps a pixel no 4-shade palette contains") local fullTrainer = BattleState.trainerSprite(trainerPicData, trainerPicData.trainers.FULLCOLOR) r, g, b = fullTrainer.data:getPixel(0, 0) @@ -395,6 +397,7 @@ check(math.abs(r - 0.4) < 1e-6 and math.abs(g - 0.7) < 1e-6 check(BattleState.trainerTrueColor(trainerPicData, trainerPicData.trainers.REUSED) == true, "a basePic reuse inherits the base portrait's trueColor flag") +PaletteFX.setMode(savedColors) -- ------- trueColor: the colors == false zone sentinel @@ -434,6 +437,8 @@ check(bareDraw.shader == false, -- covered and endFrame splices it in. Driven through the real draw path -- rather than by handing endFrame a hand-built zone. +savedColors = PaletteFX.mode +PaletteFX.setMode("redpp") local GRAYS = PaletteFX.GRAYS local function canvasDraws(canvas) local drawn = {} @@ -625,6 +630,7 @@ check(#PaletteFX.trueColorRects("world") == 0, "the same tileset without the flag reports nothing") Renderer:endWorldPass() Renderer:endFrame({ PaletteFX.whole(GRAYS) }, fullWorldZones()) +PaletteFX.setMode(savedColors) -- ------- font pages and charmap ordering