Files
2026-09-16 16:42:59 -04:00

171 lines
6.7 KiB
Lua

-- Bank02.asm Map32ToMap16; Kakariko $18/$19/$20/$21; Bank0F.asm Map16ToMap8.
local HOUSE = {
{ 0x3F7, 0x3F8, 0x3F9, 0x3F9, 0x3FA, 0x3FB },
{ 0x3FC, 0x3FD, 0x3FE, 0x3FE, 0x3FF, 0x400 },
{ 0x402, 0x403, 0x404, 0x404, 0x405, 0x406 },
{ 0x40A, 0x40B, 0x40C, 0x40D, 0x40B, 0x40E },
{ 0x0F9, 0x0FA, 0x0FB, 0x0FC, 0x0FD, 0x0FE },
}
local LAB = {
{ 0x5AC, 0x5AD, 0x5AE, 0x5AE, 0x5AF, 0x5B0 },
{ 0x5B1, 0x5B6, 0x5B3, 0x5B3, 0x5B7, 0x5B5 },
{ 0x5B8, 0x5B9, 0x5BA, 0x5BA, 0x5BB, 0x5BC },
{ 0x5BD, 0x5BE, 0x5BF, 0x5C0, 0x5BE, 0x5C1 },
HOUSE[5],
}
local TREE = {
{ 0x0AE, 0x0AF, 0x07E, 0x07F },
{ 0x0B0, 0x014, 0x015, 0x0A8 },
{ 0x089, 0x01C, 0x01D, 0x076 },
{ 0x0F1, 0x04E, 0x04F, 0x0D9 },
{ 0x09A, 0x09B, 0x09C, 0x095 },
}
return function(mod, base, map, imagePath)
local source = love.image.newImageData(imagePath)
local function tile(image, id, x, y)
image:paste(source, x, y, id % 64 * 16, math.floor(id / 64) * 16, 16, 16)
end
local function mosaic(rows)
local image = love.image.newImageData(#rows[1] * 16, #rows * 16)
for y, row in ipairs(rows) do
for x, id in ipairs(row) do tile(image, id, (x - 1) * 16, (y - 1) * 16) end
end
return image
end
local function scale(target, image, x, y, w, h, sx, sy, sw, sh)
sx, sy = sx or 0, sy or 0
sw, sh = sw or image:getWidth(), sh or image:getHeight()
for py = 0, h - 1 do
for px = 0, w - 1 do
target:setPixel(x + px, y + py, image:getPixel(
sx + math.floor((px + 0.5) * sw / w),
sy + math.floor((py + 0.5) * sh / h)))
end
end
end
local width, height = map.width * 32, map.height * 32
local canvas = love.image.newImageData(width, height + 32)
local tree = mosaic(TREE)
local Map = require("src.world.Map")
local function water(x, y)
if x < 0 or y < 0 or x >= width / 16 or y >= height / 16 then return true end
local id = Map.defCellTile(map, base, x, y)
return id == 0x14 or id == 0x32
end
local function shoreline(x, y)
local sx, sy = 0x2DB % 64 * 16, math.floor(0x2DB / 64) * 16
for n = 0, 15 do
for depth = 0, 3 do
local r, g, b, a = source:getPixel(sx + n, sy + 12 + depth)
if not water(x - 1, y) then canvas:setPixel(x * 16 + 3 - depth, y * 16 + n, r, g, b, a) end
if not water(x + 1, y) then canvas:setPixel(x * 16 + 12 + depth, y * 16 + n, r, g, b, a) end
if not water(x, y - 1) then canvas:setPixel(x * 16 + n, y * 16 + 3 - depth, r, g, b, a) end
if not water(x, y + 1) then canvas:setPixel(x * 16 + n, y * 16 + 12 + depth, r, g, b, a) end
end
end
end
for y = 0, height / 16 - 1 do
for x = 0, width / 16 - 1 do
local original = Map.defCellTile(map, base, x, y)
tile(canvas, (x + y) % 7 == 0 and 0x10E or 0x034, x * 16, y * 16)
if original == 0x3A then
scale(canvas, tree, x * 16, y * 16, 16, 16)
elseif original == 0x14 or original == 0x32 then
local ripple = (x + y * 3) % 5
tile(canvas, ripple == 0 and 0x2D8 or ripple == 2 and 0x2D9 or 0x2CD,
x * 16, y * 16)
shoreline(x, y)
elseif original == 0x55 then
tile(canvas, 0x334, x * 16, y * 16)
elseif original == 0x56 then
tile(canvas, 0x413, x * 16, y * 16)
elseif original == 0x52 then
tile(canvas, 0x3F6, x * 16, y * 16)
elseif (y == 6 and x >= 3 and x <= 15)
or (x == 9 and y >= 2 and y <= 16)
or (y == 12 and x >= 9 and x <= 15) then
tile(canvas, 0x3D2, x * 16, y * 16)
elseif original == 0x2C and x > 1 and x < 18 and y > 1 then
tile(canvas, 0x3C6, x * 16, y * 16)
end
end
end
local function building(rows, x, y, w, h, doorX)
local image = mosaic(rows)
local door = love.image.newImageData(32, 32)
door:paste(image, 0, 0, 32, 48, 32, 32)
tile(image, rows[4][2], 32, 48)
tile(image, rows[4][2], 48, 48)
tile(image, rows[5][2], 32, 64)
tile(image, rows[5][5], 48, 64)
scale(canvas, image, x, y, w, h - 16, 0, 0, 96, 64)
scale(canvas, image, x, y + h - 16, w, 16, 0, 64, 96, 16)
scale(canvas, door, doorX, y + h - 24, 16, 24)
local r, g, b = source:getPixel(0x0FB % 64 * 16 + 14,
math.floor(0x0FB / 64) * 16 + 7)
for py = y + h - 17, y + h - 2 do
for px = doorX + 4, doorX + 11 do canvas:setPixel(px, py, r * 0.15, g * 0.15, b * 0.15, 1) end
end
image:release()
door:release()
end
building(HOUSE, 64, 48, 64, 48, 80)
building(HOUSE, 192, 48, 64, 48, 208)
building(LAB, 160, 128, 96, 64, 192)
for y = 0, 1 do
for x = 0, 1 do scale(canvas, tree, x * 16, height + y * 16, 16, 16) end
end
local atlas = love.image.newImageData(256, math.ceil((width * height / 64 + 16) / 32) * 8)
local blocks, mapBlocks, variants, count = {}, {}, {}, 0
local sets = {}
for _, name in ipairs({ "walkable", "doorTiles", "warpTiles", "counterTiles", "waterTiles", "shoreTiles" }) do
sets[name] = {}
local fallback = name == "waterTiles" and { 0x14 }
or name == "shoreTiles" and { 0x32, 0x48 } or {}
for _, id in ipairs(base[name] or fallback) do sets[name][id] = true end
end
local result = { image = "mod_cache/" .. mod.id .. "/pallet.png",
imageWidth = atlas:getWidth(), imageHeight = atlas:getHeight(),
tilesPerRow = 32, blocks = blocks, trueColor = true,
walkable = {}, doorTiles = {}, warpTiles = {}, counterTiles = {}, waterTiles = {}, shoreTiles = {} }
local piece = love.image.newImageData(8, 8)
local function addBlock(original, bx, by)
local row = {}
for i, old in ipairs(original) do
local tx, ty = (i - 1) % 4, math.floor((i - 1) / 4)
piece:paste(canvas, 0, 0, bx * 32 + tx * 8, by * 32 + ty * 8, 8, 8)
if old == base.grassTile then
piece:paste(source, 0, 0, 0x3F6 % 64 * 16, math.floor(0x3F6 / 64) * 16, 8, 8)
end
local key = old .. ":" .. piece:getString()
local id = variants[key]
if id == nil then
id = count
count = count + 1
variants[key] = id
atlas:paste(piece, id % 32 * 8, math.floor(id / 32) * 8, 0, 0, 8, 8)
for name, set in pairs(sets) do
if set[old] then result[name][#result[name] + 1] = id end
end
if old == base.grassTile then result.grassTile = id end
end
row[i] = id
end
blocks[#blocks + 1] = row
return #blocks - 1
end
for i, id in ipairs(map.blocks) do
mapBlocks[i] = addBlock(assert(base.blocks[id + 1]), (i - 1) % map.width,
math.floor((i - 1) / map.width))
end
local border = addBlock(assert(base.blocks[(map.borderBlock or 0) + 1]), 0, map.height)
assert(mod.cache:write("pallet.png", atlas:encode("png"):getString()))
source:release()
tree:release()
canvas:release()
atlas:release()
piece:release()
return result, mapBlocks, border
end