mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-09 01:59:15 -04:00
322 lines
11 KiB
Lua
322 lines
11 KiB
Lua
-- engine/gfx/mon_icons.asm WriteSymmetricMonPartySpriteOAM
|
|
-- engine/gfx/load_pics.asm
|
|
|
|
local CacheFs = require("src.import.CacheFs")
|
|
local GameVersion = require("src.core.GameVersion")
|
|
local Sprites = require("src.pokemon.Sprites")
|
|
|
|
local OnlineSprites = {}
|
|
|
|
local catalogs = {}
|
|
local cache = {}
|
|
|
|
-- engine/gfx/mon_icons.asm:246
|
|
local function mirrors(name)
|
|
return name ~= nil and name ~= "HELIX"
|
|
end
|
|
|
|
local SHADES = { { 255, 255, 255 }, { 170, 170, 170 },
|
|
{ 85, 85, 85 }, { 0, 0, 0 } }
|
|
|
|
function OnlineSprites.key(version, species, shiny)
|
|
return ("%s|%s|%s"):format(tostring(version), tostring(species),
|
|
shiny and "shiny" or "normal")
|
|
end
|
|
|
|
function OnlineSprites.reset()
|
|
catalogs, cache = {}, {}
|
|
end
|
|
|
|
function OnlineSprites.keepOnly(versions)
|
|
local keep = {}
|
|
for _, version in ipairs(versions or {}) do keep[tostring(version)] = true end
|
|
for version in pairs(catalogs) do
|
|
if not keep[version] then catalogs[version] = nil end
|
|
end
|
|
for key in pairs(cache) do
|
|
local version = key:match("^([^|]*)|")
|
|
if version and not keep[version] then cache[key] = nil end
|
|
end
|
|
end
|
|
|
|
function OnlineSprites.readBytes(version, path)
|
|
local prefix = GameVersion.cachePrefix(version) or ""
|
|
local bytes = CacheFs.readAt(prefix .. path)
|
|
if type(bytes) == "string" and bytes ~= "" then return bytes end
|
|
return nil
|
|
end
|
|
|
|
local function loadTable(version, path)
|
|
local bytes = OnlineSprites.readBytes(version, path)
|
|
if not bytes then return nil end
|
|
local loader = loadstring or load
|
|
local chunk = loader(bytes, "@" .. path)
|
|
if not chunk then return nil end
|
|
local ok, value = pcall(chunk)
|
|
if not ok or type(value) ~= "table" then return nil end
|
|
return value
|
|
end
|
|
|
|
local function catalog(version)
|
|
local hit = catalogs[version]
|
|
if hit then return hit end
|
|
hit = {
|
|
pokemon = loadTable(version, "data/generated/pokemon.lua") or {},
|
|
icons = loadTable(version, "data/generated/icons.lua") or {},
|
|
palettes = loadTable(version, "data/generated/palettes.lua") or {},
|
|
generation = GameVersion.generation(version),
|
|
}
|
|
catalogs[version] = hit
|
|
return hit
|
|
end
|
|
|
|
local function paletteFor(cat, species, shiny)
|
|
local entry = cat.palettes and cat.palettes.pokemon
|
|
and cat.palettes.pokemon[species]
|
|
if type(entry) == "string" then
|
|
local ramp = cat.palettes.palettes and cat.palettes.palettes[entry]
|
|
if type(ramp) == "table" and #ramp == 4 then return ramp end
|
|
return nil
|
|
end
|
|
if type(entry) ~= "table" then return nil end
|
|
local pair = entry[shiny and "shiny" or "normal"] or entry.normal
|
|
if type(pair) ~= "table" or #pair < 2 then return nil end
|
|
return { { 255, 255, 255 }, pair[1], pair[2], { 0, 0, 0 } }
|
|
end
|
|
|
|
local function shadeIndex(r)
|
|
if r > 0.75 then return 1 end
|
|
if r > 0.5 then return 2 end
|
|
if r > 0.25 then return 3 end
|
|
return 4
|
|
end
|
|
|
|
function OnlineSprites.makeImage(bytes, path, palette)
|
|
if not (love and love.graphics and love.graphics.newImage) then return nil end
|
|
local ok, image = pcall(function()
|
|
local data = love.filesystem.newFileData(bytes, path)
|
|
if not (palette and love.image and love.image.newImageData) then
|
|
return love.graphics.newImage(data)
|
|
end
|
|
local pixels = love.image.newImageData(data)
|
|
if type(pixels.mapPixel) ~= "function" then
|
|
return love.graphics.newImage(data)
|
|
end
|
|
pixels:mapPixel(function(_, _, r, _, _, a)
|
|
local col = palette[shadeIndex(r)] or SHADES[shadeIndex(r)]
|
|
return (col[1] or 0) / 255, (col[2] or 0) / 255, (col[3] or 0) / 255, a
|
|
end)
|
|
return love.graphics.newImage(pixels)
|
|
end)
|
|
if not ok then return nil end
|
|
return image
|
|
end
|
|
|
|
local function image(version, path, palette)
|
|
local bytes = OnlineSprites.readBytes(version, path)
|
|
if not bytes then return false end
|
|
return OnlineSprites.makeImage(bytes, path, palette) or false
|
|
end
|
|
|
|
local function iconPath(cat, mon)
|
|
local icons = cat.icons or {}
|
|
if cat.generation == 2 then
|
|
local id = mon.isEgg and "ICON_EGG"
|
|
or (icons.species and icons.species[mon.species])
|
|
local entry = id and icons.icons and icons.icons[id]
|
|
if type(entry) == "table" then return entry.image, id end
|
|
return nil, id
|
|
end
|
|
local def = cat.pokemon and cat.pokemon[mon.species]
|
|
local entry = (icons.bySpecies and icons.bySpecies[mon.species])
|
|
or (def and def.icon)
|
|
local name, path
|
|
if type(entry) == "string" then
|
|
name = entry
|
|
path = icons.icons and icons.icons[entry]
|
|
elseif type(entry) == "table" then
|
|
path = entry.image
|
|
end
|
|
if not path then
|
|
name = def and def.dex and icons.byDex and icons.byDex[def.dex]
|
|
local hit = name and icons.icons and icons.icons[name]
|
|
path = (type(hit) == "table") and hit.image or hit
|
|
end
|
|
return path, name
|
|
end
|
|
|
|
local function gen3Pokemon()
|
|
return require("src.core.game3.pokemon")
|
|
end
|
|
|
|
local function gen3PicSpecies(mon)
|
|
local Pokemon = gen3Pokemon()
|
|
if Pokemon.isEgg(mon) then return Pokemon.SPECIES_EGG end
|
|
return Pokemon.picSpecies(mon.species, mon.personality)
|
|
end
|
|
|
|
local function monKey(version, mon)
|
|
if GameVersion.generation(version) ~= 3 then
|
|
return OnlineSprites.key(version, mon.species, mon.shiny == true)
|
|
end
|
|
return OnlineSprites.key(version, gen3PicSpecies(mon),
|
|
gen3Pokemon().isShiny(mon)) .. "|" .. tostring(mon.personality or 0)
|
|
end
|
|
|
|
local function gen3Front(version, mon)
|
|
local Pokemon = gen3Pokemon()
|
|
local was = { Pokemon._cache, Pokemon._front, Pokemon._spinda,
|
|
Pokemon._spindaPics }
|
|
Pokemon._cache = { read = function(_, rel)
|
|
return OnlineSprites.readBytes(version, rel)
|
|
end }
|
|
Pokemon._front, Pokemon._spinda, Pokemon._spindaPics = {}, nil, {}
|
|
local ok, entry = pcall(Pokemon.frontPic, gen3PicSpecies(mon), nil,
|
|
Pokemon.isShiny(mon), mon.personality)
|
|
Pokemon._cache, Pokemon._front, Pokemon._spinda, Pokemon._spindaPics =
|
|
was[1], was[2], was[3], was[4]
|
|
return ok and type(entry) == "table" and entry.image or false
|
|
end
|
|
|
|
-- pokefirered/src/pokemon_icon.c:1116
|
|
local function gen3Icon(version, mon)
|
|
local Pokemon = gen3Pokemon()
|
|
local was = { Pokemon._cache, Pokemon._icons }
|
|
Pokemon._cache = { read = function(_, rel)
|
|
return OnlineSprites.readBytes(version, rel)
|
|
end }
|
|
Pokemon._icons = {}
|
|
local ok, entry = pcall(Pokemon.icon, gen3PicSpecies(mon))
|
|
Pokemon._cache, Pokemon._icons = was[1], was[2]
|
|
if not ok or type(entry) ~= "table" or not entry.image then return false end
|
|
return entry
|
|
end
|
|
|
|
function OnlineSprites.get(version, mon)
|
|
if type(mon) ~= "table" then return nil end
|
|
return cache[monKey(version, mon)]
|
|
end
|
|
|
|
function OnlineSprites.ensure(version, mon)
|
|
if type(mon) ~= "table" or not version then return nil end
|
|
local key = monKey(version, mon)
|
|
local hit = cache[key]
|
|
if hit then return hit end
|
|
if GameVersion.generation(version) == 3 then
|
|
local icon = gen3Icon(version, mon)
|
|
hit = { key = key, mirror = false, icon = icon and icon.image or false,
|
|
iconW = icon and icon.w or nil, iconH = icon and icon.h or nil,
|
|
front = gen3Front(version, mon) }
|
|
cache[key] = hit
|
|
return hit
|
|
end
|
|
local cat = catalog(version)
|
|
local def = cat.pokemon and cat.pokemon[mon.species]
|
|
local palette = paletteFor(cat, mon.species, mon.shiny == true)
|
|
local path, name = iconPath(cat, mon)
|
|
local entry = { key = key, mirror = false }
|
|
if path then
|
|
entry.icon = image(version, path, nil)
|
|
entry.mirror = (cat.generation ~= 2) and mirrors(name) or false
|
|
else
|
|
entry.icon = false
|
|
end
|
|
local front, trueColor = Sprites.pic(def and def.spriteFront, {
|
|
species = mon.species,
|
|
side = "front",
|
|
kind = "online",
|
|
mon = mon,
|
|
data = cat,
|
|
shiny = mon.shiny == true,
|
|
})
|
|
if trueColor then palette = nil end
|
|
entry.front = front and image(version, front, palette) or false
|
|
if entry.front == false and front and front ~= (def and def.spriteFront)
|
|
and love and love.filesystem and love.filesystem.read then
|
|
local bytes = love.filesystem.read(front)
|
|
entry.front = bytes and OnlineSprites.makeImage(bytes, front, palette)
|
|
or false
|
|
end
|
|
cache[key] = entry
|
|
return entry
|
|
end
|
|
|
|
function OnlineSprites.prime(version, party)
|
|
if not version or type(party) ~= "table" then return 0 end
|
|
local n = 0
|
|
for _, mon in ipairs(party) do
|
|
if OnlineSprites.ensure(version, mon) then n = n + 1 end
|
|
end
|
|
return n
|
|
end
|
|
|
|
local savedColor = {}
|
|
|
|
local function paintWhite()
|
|
if not (love.graphics and love.graphics.getColor) then return nil end
|
|
local saved = savedColor
|
|
saved[1], saved[2], saved[3], saved[4] = love.graphics.getColor()
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
return saved
|
|
end
|
|
|
|
local function restore(saved)
|
|
if saved and love.graphics and love.graphics.setColor then
|
|
love.graphics.setColor(saved[1], saved[2], saved[3], saved[4])
|
|
end
|
|
end
|
|
|
|
function OnlineSprites.drawIcon(entry, x, y, size, frame)
|
|
if type(entry) ~= "table" or not entry.icon then return false end
|
|
local img = entry.icon
|
|
if type(img.getDimensions) ~= "function" then return false end
|
|
local iw, ih = img:getDimensions()
|
|
if not iw or iw <= 0 or ih <= 0 then return false end
|
|
local scale = (size or 16) / 16
|
|
local saved = paintWhite()
|
|
local quad = entry.iconQuadFor == img and entry.iconQuad or nil
|
|
if entry.iconW and entry.iconH then
|
|
local fw, fh = math.min(entry.iconW, iw), math.min(entry.iconH, ih)
|
|
local frames = math.max(1, math.floor(ih / fh))
|
|
local index = math.floor(tonumber(frame) or 0) % frames
|
|
if entry.iconQuadFor ~= img then entry.iconQuads = {} end
|
|
entry.iconQuads = entry.iconQuads or {}
|
|
quad = entry.iconQuads[index] or love.graphics.newQuad(0, index * fh, fw, fh, iw, ih)
|
|
entry.iconQuads[index] = quad
|
|
entry.iconQuadFor = img
|
|
local s = (size or fw) / math.max(fw, fh)
|
|
love.graphics.draw(img, quad, x, y, 0, s, s)
|
|
elseif ih > 16 and entry.mirror then
|
|
quad = quad or love.graphics.newQuad(0, 0, 8, 16, iw, ih)
|
|
entry.iconQuad, entry.iconQuadFor = quad, img
|
|
love.graphics.draw(img, quad, x, y, 0, scale, scale)
|
|
love.graphics.draw(img, quad, x + 16 * scale, y, 0, -scale, scale)
|
|
elseif ih > 16 then
|
|
quad = quad or love.graphics.newQuad(0, 0, 16, 16, iw, ih)
|
|
entry.iconQuad, entry.iconQuadFor = quad, img
|
|
love.graphics.draw(img, quad, x, y, 0, scale, scale)
|
|
else
|
|
love.graphics.draw(img, x, y, 0, scale, scale)
|
|
end
|
|
restore(saved)
|
|
return true
|
|
end
|
|
|
|
function OnlineSprites.drawFront(entry, x, y, box)
|
|
if type(entry) ~= "table" or not entry.front then return false end
|
|
local img = entry.front
|
|
if type(img.getDimensions) ~= "function" then return false end
|
|
local iw, ih = img:getDimensions()
|
|
if not iw or iw <= 0 or ih <= 0 then return false end
|
|
box = box or 56
|
|
local scale = box / math.max(iw, ih)
|
|
if scale >= 1 then scale = math.floor(scale) end
|
|
local saved = paintWhite()
|
|
love.graphics.draw(img, math.floor(x + (box - iw * scale) / 2),
|
|
math.floor(y + (box - ih * scale) / 2), 0, scale, scale)
|
|
restore(saved)
|
|
return true
|
|
end
|
|
|
|
return OnlineSprites
|