fix: preserve native companion art palettes

This commit is contained in:
AverageConsumer
2026-08-23 17:24:31 +02:00
parent 6a7be196d5
commit cb3eea652f
3 changed files with 127 additions and 20 deletions
+48 -20
View File
@@ -2148,7 +2148,8 @@ return function(mod)
quads[i] = G.newQuad((i % across) * 8, math.floor(i / across) * 8,
8, 8, iw, ih)
end
mapAsset = { image = image, quads = quads, maps = gfx.maps, gen2 = true }
mapAsset = { image = image, quads = quads, maps = gfx.maps,
palettes = gfx.palettes, palMap = gfx.palMap, gen2 = true }
return mapAsset
end
local townMap = game and game.data and game.data.field
@@ -2176,7 +2177,8 @@ return function(mod)
end
local function sprite(species, side, mon)
local path = PokemonSprites.path(game and game.data, species, side,
local path, trueColor = PokemonSprites.path(
game and game.data, species, side,
{ kind = "summary", mon = mon })
if not path then return nil end
local key = side .. ":" .. path
@@ -2190,12 +2192,12 @@ return function(mod)
if ok and image then image:setFilter("nearest", "nearest") end
spriteCache[key] = ok and image or false
end
return spriteCache[key] or nil
return spriteCache[key] or nil, trueColor
end
local function drawSprite(species, side, x, y, maxW, maxH, tint,
mon, quiet)
local image = sprite(species, side, mon)
local image, trueColor = sprite(species, side, mon)
if not image then
if not quiet then box("fill", x + 4, y + 4, maxW - 8, maxH - 8, DARK) end
return false
@@ -2207,11 +2209,20 @@ return function(mod)
G.draw(image, x + (maxW - iw * scale) / 2,
y + (maxH - ih * scale) / 2, 0, scale, scale)
end
local gbc, palettes = compat.gen2PaletteModules()
local colors = palettes and palettes.monColors
and palettes.monColors(game.data.gen2Palettes, species,
mon and mon.shiny)
if colors and gbc and gbc.available() then gbc.with(colors, paint)
local gbc = require("src.render.GbcPalette")
local colors
if not (tint or trueColor) then
if compat.isGen2() then
local _, palettes = compat.gen2PaletteModules()
colors = palettes and palettes.monColors
and palettes.monColors(game.data.gen2Palettes, species,
mon and mon.shiny)
else
colors = PaletteFX.monPal(game.data, species,
mon and mon.transformed)
end
end
if colors and gbc.available() then gbc.with(colors, paint)
else paint() end
return true
end
@@ -2670,21 +2681,29 @@ return function(mod)
local asset = loadMap()
if asset then
local cells = asset.map
local gbc = require("src.render.GbcPalette")
local mapColors = not asset.gen2
and PaletteFX.pal(game.data, "TOWNMAP") or nil
if asset.gen2 then
cells = asset.maps[region]
color(THEME.style == "modern_dark" and INK or PAPER)
else
color({ 1, 1, 1, 1 })
end
for i, tile in ipairs(cells or {}) do
local quad = asset.quads[tile]
if quad then
local col, row = (i - 1) % 20, math.floor((i - 1) / 20)
if asset.gen2 then
G.draw(asset.image, quad, 20 + col * 6, 20 + row * 6,
0, 0.75, 0.75)
elseif row > 0 then
G.draw(asset.image, quad, 20 + col * 6, 22 + (row - 1) * 6, 0, 0.75, 0.75)
local y = asset.gen2 and 20 + row * 6 or 22 + (row - 1) * 6
local colors = asset.gen2 and asset.palettes
and asset.palettes[(asset.palMap and asset.palMap[tile + 1]) or 1]
or mapColors
local function paint()
color(colors and { 1, 1, 1, 1 }
or asset.gen2 and (THEME.style == "modern_dark" and INK or PAPER)
or { 1, 1, 1, 1 })
G.draw(asset.image, quad, 20 + col * 6, y, 0, 0.75, 0.75)
end
if (asset.gen2 or row > 0) then
if colors and gbc.available() then gbc.with(colors, paint)
else paint() end
end
end
end
@@ -2939,6 +2958,8 @@ return function(mod)
spriteCache.__badges = ok and card and card.badges or false
end
local badgeAsset = spriteCache.__badges
local gen1BadgeColors = not compat.isGen2()
and PaletteFX.pal(game.data, "MEWMON") or nil
header("TRAINER", false, true)
box("fill", 4, 22, 152, 50, MID)
@@ -2960,11 +2981,18 @@ return function(mod)
badgeOwned and PAPER or DARK)
end
elseif quad then
local tint = badgeOwned and INK or DARK
G.setColor(tint[1], tint[2], tint[3], badgeOwned and 1 or 0.25)
local x = math.floor(5 + (i - 1) * 134
/ math.max(1, #badges - 1))
G.draw(badgeAsset.img, quad, x, 56)
local colors = badgeOwned and gen1BadgeColors
local function paint()
local tint = badgeOwned and INK or DARK
if colors then G.setColor(1, 1, 1, 1)
else G.setColor(tint[1], tint[2], tint[3], badgeOwned and 1 or 0.25) end
G.draw(badgeAsset.img, quad, x, 56)
end
local gbc = require("src.render.GbcPalette")
if colors and gbc.available() then gbc.with(colors, paint)
else paint() end
else
local badgeGap = 152 / math.max(1, #badges)
local x = math.floor(4 + (i - 1) * badgeGap)
+63
View File
@@ -1015,6 +1015,16 @@ local fallbackPhase = false
local fallbackImage
local decodedFrames = 0
local genericSprites, ownedSprites = 0, 0
local PaletteFX = require("src.render.PaletteFX")
local GbcPalette = require("src.render.GbcPalette")
local monPal = PaletteFX.monPal
local paletteWith = GbcPalette.with
local paletteAvailable = GbcPalette.available
local nativeMonColors = {
{ 255, 255, 255 }, { 248, 184, 112 }, { 152, 80, 136 }, { 0, 0, 0 },
}
local nativeMonPaletteUses = 0
local trueColorMonPalCalls = 0
local originalIcons = game.data.icons
game.data.icons = {
bySpecies = { PIKACHU = "TEST_ICON" },
@@ -1048,6 +1058,11 @@ T.love.graphics.newImage = function(path, ...)
if path == "official-icon.png" then fallbackImage = image end
return image
end
PaletteFX.monPal = function(...)
trueColorMonPalCalls = trueColorMonPalCalls + 1
return monPal(...)
end
GbcPalette.available = function() return true end
for _ = 1, 32 do
trigger.right = 0.8
run.loader.hooks:call("input.step", function() end, game, 1 / 60)
@@ -1067,6 +1082,33 @@ T.check(ownedSprites > 0,
"owned Pokemon screens pass their live Pokemon to the sprite resolver")
T.eq(fallbackIcons, 0,
"decoded Party sprite frames do not use placeholder icons")
T.eq(trueColorMonPalCalls, 0,
"full-color mod sprites bypass native palette remapping")
PaletteFX.monPal = function() return nativeMonColors end
GbcPalette.with = function(colors, body)
if colors == nativeMonColors then
nativeMonPaletteUses = nativeMonPaletteUses + 1
end
return body()
end
Sprites.path = function(_, _, _, opts)
if opts and opts.mon then ownedSprites = ownedSprites + 1
else genericSprites = genericSprites + 1 end
return "decoded-frame.png", false
end
for _ = 1, 32 do
trigger.right = 0.8
run.loader.hooks:call("input.step", function() end, game, 1 / 60)
trigger.right = 0
run.loader.hooks:call("input.step", function() end, game, 1 / 60)
run.loader.hooks:call("render.compose", function() return false end, {}, {
secondScreen = { detected = function() return displayDetected end,
pollTouch = function() return nil end },
})
if nativeMonPaletteUses > 0 then break end
end
T.check(nativeMonPaletteUses > 0,
"Gen 1 Pokemon sprites use their native species palette")
Sprites.path = function() return "unavailable.gif", true end
fallbackPhase = true
Assets.imageData = function(path)
@@ -1085,6 +1127,8 @@ for _ = 1, 32 do
if fallbackIcons > 0 then break end
end
Sprites.path, Assets.imageData = spritePath, imageData
PaletteFX.monPal, GbcPalette.with = monPal, paletteWith
GbcPalette.available = paletteAvailable
T.love.graphics.newImage = newImage
T.love.graphics.draw = drawImage
game.data.icons = originalIcons
@@ -1094,6 +1138,8 @@ T.check(fallbackIsWhite, "fallback Party icons keep their original colors")
do
local badgeLoads, badgeAlphas = 0, {}
local badgePaletteUses = 0
local palette = PaletteFX.pal
local draw = T.love.graphics.draw
local TrainerCard = require("src.ui.TrainerCard")
local trainerCardNew = TrainerCard.new
@@ -1106,6 +1152,18 @@ do
{ id = "VOLCANOBADGE" }, { id = "EARTHBADGE" },
}
game.save.inventory.TEST_BADGE = true
local badgeColors = {
{ 255, 255, 255 }, { 248, 184, 112 }, { 152, 80, 136 }, { 0, 0, 0 },
}
PaletteFX.pal = function(data, name)
if name == "MEWMON" then return badgeColors end
return palette(data, name)
end
GbcPalette.available = function() return true end
GbcPalette.with = function(colors, body)
if colors == badgeColors then badgePaletteUses = badgePaletteUses + 1 end
return body()
end
TrainerCard.new = function()
badgeLoads = badgeLoads + 1
local badges = { img = T.love.graphics.newImage({}), quads = {} }
@@ -1137,6 +1195,9 @@ do
if #badgeAlphas >= 8 then break end
end
TrainerCard.new, T.love.graphics.draw = trainerCardNew, draw
PaletteFX.pal = palette
GbcPalette.with = paletteWith
GbcPalette.available = paletteAvailable
game.data.constants.badges = dataBadges
game.save.inventory.TEST_BADGE = nil
T.eq(badgeLoads, 1, "Trainer badges reuse Recomp's Trainer Card sprites")
@@ -1148,6 +1209,8 @@ do
end
T.eq(solid, 1, "owned badges draw at full strength")
T.eq(faded, 7, "unearned badges remain visible as faded silhouettes")
T.eq(badgePaletteUses, 1,
"owned Gen 1 badges use the native Trainer Card palette")
end
T.eq(run.loader.hooks:call("render.output_enabled",
+16
View File
@@ -52,9 +52,13 @@ run.data.gen2Encounters = { grass = { FIX_ROUTE = { slots = {
} } }, water = {} }
local johtoMap = {}
for i = 1, 20 * 18 do johtoMap[i] = 0 end
local mapColors = {
{ 255, 255, 255 }, { 104, 208, 88 }, { 32, 120, 64 }, { 0, 0, 0 },
}
run.data.gen2MenuGfx = { pokegear = {
tiles = "gold-map.png", tilesWide = 1,
maps = { johto = johtoMap, kanto = johtoMap },
palettes = { mapColors }, palMap = { [1] = 1 },
} }
run.data.gen2Sprites = { SPRITE_CHRIS = {
image = "gold-player.png", frames = 1, trueColor = true, paletteId = 0,
@@ -111,8 +115,12 @@ local companion = {
push = function() return true end,
}
local SpriteRenderer = require("src.render.SpriteRenderer")
local GbcPalette = require("src.render.GbcPalette")
local rendererNew = SpriteRenderer.new
local paletteWith = GbcPalette.with
local paletteAvailable = GbcPalette.available
local markerPalette
local mapPaletteUsed = false
SpriteRenderer.new = function(def, seed)
local renderer = rendererNew(def, seed)
if seed == "kanto-gear-map" then
@@ -124,13 +132,21 @@ SpriteRenderer.new = function(def, seed)
end
return renderer
end
GbcPalette.with = function(colors, body)
if colors == mapColors then mapPaletteUsed = true end
return body()
end
GbcPalette.available = function() return true end
local mapDraws = T.record.draw()
run.loader.hooks:call("render.compose", function() return false end, {}, {
secondScreen = companion,
})
SpriteRenderer.new = rendererNew
GbcPalette.with, GbcPalette.available = paletteWith, paletteAvailable
T.check(#mapDraws:fromPath("gold-map.png") > 0,
"Gold map renders the extracted Pokegear town-map tiles")
T.check(mapPaletteUsed,
"Gold map applies its extracted per-tile town-map palettes")
local playerMarker = mapDraws:fromPath("gold-player.png")[1]
T.check(playerMarker and playerMarker.args[2] == 44
and playerMarker.args[3] == 56 and playerMarker.args[5] == 0.75,