Files

142 lines
6.9 KiB
Lua

-- gen_npcs.lua — named NPC sprites (each 48x24: 3 frames = smile / flat / off)
-- plus npc_bird.png (32x24: 2 frames = beak closed / open)
local ROOT = "/Users/leidianyayi/Documents/GitHub/ModelTest20260714/Kimi-K3/"
local H = dofile(ROOT .. "tools/aseprite/helpers.lua")
-- ---- shared expression core ------------------------------------------------
-- eyes at (lx,ly)/(rx,ry); mouth baseline my. ex in {"smile","flat","off"}.
-- "off" = smile mouth but the right eye sits 1px lower (a 1-2px difference).
local function expr(t, ex, lx, ly, rx, ry, my, eyeCol, mouthCol)
eyeCol = eyeCol or "ink"; mouthCol = mouthCol or "brown_d"
if ex == "off" then ry = ry + 1 end
t.pn(lx, ly, eyeCol); t.pn(rx, ry, eyeCol)
if ex == "flat" then
t.hln(lx + 1, my, rx - lx - 1, mouthCol)
else
t.pn(lx + 1, my, mouthCol); t.pn(lx + 2, my + 1, mouthCol)
t.pn(rx - 2, my + 1, mouthCol); t.pn(rx - 1, my, mouthCol)
end
end
local function arms(t, c) t.rectn(2, 12, 2, 5, c); t.rectn(12, 12, 2, 5, c) end
local function feet(t, c) t.rectn(5, 20, 2, 3, c); t.rectn(9, 20, 2, 3, c) end
-- ---- species bodies (face forward, 16x24 local) ---------------------------
local function afu(t, ex) -- 狗村长 dog village head
t.rectn(1, 3, 3, 6, "brown_d"); t.rectn(12, 3, 3, 6, "brown_d") -- floppy ears
t.rectn(1, 3, 3, 2, "brown"); t.rectn(12, 3, 3, 2, "brown")
t.rectn(3, 3, 10, 9, "brown"); t.rectn(3, 3, 10, 1, "brown_l")
t.rectn(6, 8, 4, 4, "cream"); t.pn(7, 8, "ink") -- muzzle + nose
t.rectn(4, 12, 8, 7, "brown"); t.rectn(4, 12, 8, 3, "honey") -- vest
t.pn(7, 13, "honey_d"); t.pn(8, 13, "honey_d")
arms(t, "brown"); feet(t, "brown_d")
expr(t, ex, 5, 6, 10, 6, 10)
end
local function yuanyuan(t, ex) -- 兔面包师 rabbit baker
t.rectn(4, 0, 2, 5, "cream"); t.rectn(10, 0, 2, 5, "cream") -- long ears
t.rectn(5, 1, 1, 3, "pink"); t.rectn(10, 1, 1, 3, "pink") -- inner ear
t.rectn(3, 4, 10, 8, "cream"); t.rectn(3, 4, 10, 1, "white")
t.pn(7, 9, "pink_d") -- bunny nose
t.rectn(4, 12, 8, 7, "pink") -- dress
t.rectn(4, 12, 8, 5, "white") -- apron
t.rectn(4, 12, 8, 1, "cream_d")
t.pn(6, 14, "cream_d"); t.pn(9, 14, "cream_d")
arms(t, "cream"); feet(t, "cream_d")
expr(t, ex, 5, 7, 10, 7, 10)
end
local function dabao(t, ex) -- 熊邮差 bear postman
t.discn(4, 3, 2, "brown"); t.discn(11, 3, 2, "brown") -- round ears
t.discn(4, 3, 1, "brown_d"); t.discn(11, 3, 1, "brown_d")
t.rectn(2, 3, 12, 9, "brown"); t.rectn(2, 3, 12, 1, "brown_l") -- big head
t.rectn(6, 8, 4, 4, "cream"); t.pn(7, 8, "ink")
t.rectn(3, 12, 10, 7, "brown") -- big body
t.pn(4, 12, "brown_d"); t.pn(5, 13, "brown_d"); t.pn(6, 14, "brown_d")
t.pn(7, 15, "brown_d"); t.pn(8, 16, "brown_d") -- satchel strap
t.rectn(9, 15, 4, 4, "yellow_d"); t.framen(9, 15, 4, 4, "brown_d"); t.rectn(9, 15, 4, 1, "yellow")
t.rectn(1, 12, 2, 5, "brown"); t.rectn(13, 12, 2, 5, "brown") -- arms (wider)
feet(t, "brown_d")
expr(t, ex, 5, 6, 10, 6, 10)
end
local function mimi(t, ex) -- 猫店主 cat shopkeeper
t.rectn(3, 2, 2, 3, "honey"); t.rectn(11, 2, 2, 3, "honey") -- pointy ears
t.pn(3, 2, "honey_d"); t.pn(12, 2, "honey_d")
t.pn(3, 3, "pink"); t.pn(12, 3, "pink")
t.rectn(3, 4, 10, 8, "honey"); t.rectn(3, 4, 10, 1, "honey_l")
t.pn(4, 4, "honey_d"); t.pn(7, 4, "honey_d"); t.pn(10, 4, "honey_d") -- stripes
t.pn(7, 9, "pink_d") -- nose
t.rectn(4, 12, 8, 7, "cream")
t.rectn(4, 12, 8, 4, "sky"); t.rectn(4, 12, 8, 1, "sky_d") -- apron
arms(t, "honey"); feet(t, "honey_d")
t.pn(1, 8, "honey_d"); t.pn(14, 8, "honey_d") -- whiskers
expr(t, ex, 5, 7, 10, 7, 10)
end
local function fuyisheng(t, ex) -- 鹿医生 deer doctor
t.vln(4, 0, 3, "brown_d"); t.pn(3, 1, "brown_d"); t.pn(5, 1, "brown_d") -- antlers
t.vln(11, 0, 3, "brown_d"); t.pn(10, 1, "brown_d"); t.pn(12, 1, "brown_d")
t.rectn(2, 4, 2, 3, "cream_d"); t.rectn(12, 4, 2, 3, "cream_d") -- ears
t.rectn(3, 3, 10, 9, "cream_d"); t.rectn(3, 3, 10, 1, "skin")
t.rectn(6, 8, 4, 4, "cream"); t.pn(7, 8, "ink") -- muzzle
t.rectn(3, 12, 10, 7, "white"); t.framen(3, 12, 10, 7, "w_lo") -- white coat
t.vln(8, 12, 7, "w_lo")
t.rectn(5, 12, 6, 2, "skin")
t.pn(11, 14, "red"); t.pn(11, 15, "red") -- red cross hint
arms(t, "white"); feet(t, "brown_d")
expr(t, ex, 5, 6, 10, 6, 10)
end
local function guiyeye(t, ex) -- 龟老者 turtle elder
t.rectn(6, 4, 6, 5, "leaf_l"); t.rectn(6, 4, 6, 1, "cream") -- head
t.rectn(6, 8, 6, 2, "white") -- beard
t.discn(8, 14, 6, "leaf_d") -- shell
t.discn(8, 13, 5, "leaf")
t.discn(6, 12, 2, "leaf_l")
t.pn(8, 12, "leaf_dd"); t.pn(6, 14, "leaf_dd"); t.pn(10, 14, "leaf_dd"); t.pn(8, 16, "leaf_dd")
t.rectn(4, 20, 3, 3, "leaf_d"); t.rectn(9, 20, 3, 3, "leaf_d") -- feet
t.vln(13, 12, 9, "brown_d"); t.pn(13, 11, "brown") -- cane
expr(t, ex, 7, 6, 10, 6, 8, "ink", "brown_d")
end
-- ---- build the 6 three-frame NPC sprites ----------------------------------
local npcs = {
{ "afu", afu }, { "yuanyuan", yuanyuan }, { "dabao", dabao },
{ "mimi", mimi }, { "fuyisheng", fuyisheng }, { "guiyeye", guiyeye },
}
for _, n in ipairs(npcs) do
local spr, img = H.new(48, 24)
for i, ex in ipairs({ "smile", "flat", "off" }) do
n[2](H.at(img, (i - 1) * 16, 0), ex)
end
spr:saveAs(ROOT .. "public/assets/sprites/npc_" .. n[1] .. ".png")
print("npc_" .. n[1] .. ".png done")
end
-- ---- twin birds (32x24, 2 frames = beak closed / open) ---------------------
local function bird(t, open)
t.rectn(0, 18, 16, 2, "brown_d") -- branch
-- bird A (faces right)
t.discn(4, 11, 4, "blue"); t.discn(4, 8, 3, "blue")
t.discn(3, 10, 2, "blue_l")
t.discn(5, 11, 2, "blue_d") -- wing
t.pn(1, 12, "blue_d"); t.pn(0, 13, "blue_d") -- tail
t.pn(3, 7, "ink") -- eye
if open then t.pn(6, 8, "yellow"); t.pn(6, 9, "yellow_d") else t.pn(6, 8, "yellow") end
t.vln(3, 15, 3, "honey_d"); t.vln(5, 15, 3, "honey_d")
-- bird B (faces left), slightly lower
t.discn(11, 13, 4, "blue"); t.discn(11, 10, 3, "blue")
t.discn(12, 12, 2, "blue_l")
t.discn(10, 13, 2, "blue_d")
t.pn(14, 14, "blue_d"); t.pn(15, 15, "blue_d")
t.pn(12, 9, "ink")
if open then t.pn(9, 10, "yellow"); t.pn(9, 11, "yellow_d") else t.pn(9, 10, "yellow") end
t.vln(10, 16, 2, "honey_d"); t.vln(12, 16, 2, "honey_d")
end
local bspr, bimg = H.new(32, 24)
bird(H.at(bimg, 0, 0), false)
bird(H.at(bimg, 16, 0), true)
bspr:saveAs(ROOT .. "public/assets/sprites/npc_bird.png")
print("npc_bird.png done")