-- gen_all.lua : draws EVERY pixel asset for 蜜糖村 from scratch (Aseprite Lua API).
-- No external art, no imported palettes. Run: aseprite -b --script-param outdir=... --script gen_all.lua
local outdir = app.params["outdir"]
if not outdir then error("need --script-param outdir=") end

local function pack(t) return app.pixelColor.rgba(t[1], t[2], t[3], t[4] or 255) end
local function px(img,x,y,c) if x>=0 and y>=0 and x<img.width and y<img.height then img:drawPixel(x,y,pack(c)) end end
local function rect(img,x,y,w,h,c) for j=0,h-1 do for i=0,w-1 do px(img,x+i,y+j,c) end end end
local function hline(img,x,y,w,c) for i=0,w-1 do px(img,x+i,y,c) end end
local function vline(img,x,y,h,c) for j=0,h-1 do px(img,x,y+j,c) end end
local function speck(img,ox,oy,w,h,c,mod,rem) for j=0,h-1 do for i=0,w-1 do if ((i*7+j*13+i*j)%mod)==rem then px(img,ox+i,oy+j,c) end end end end

local function newImg(w,h)
  local s = Sprite(w,h, ColorMode.RGB)
  return s, s.cels[1].image
end
local function save(s,name) s:saveAs(outdir.."/"..name) end

local P = {
  grass1={124,200,110}, grass2={96,170,80}, grass3={158,222,138},
  soil={150,110,70}, soilD={120,86,54},
  path1={203,185,158}, path2={170,150,118}, path3={226,214,190},
  water1={112,196,232}, water2={80,168,216}, water3={56,134,182}, foam={205,240,250}, waterDeep={44,110,158},
  wall1={234,202,156}, wall2={210,170,122}, wallD={186,140,96},
  roof1={224,116,108}, roof2={192,88,80}, roof3={240,152,142},
  door1={140,92,60}, door2={106,64,40}, knob={240,208,120},
  wood1={178,130,82}, wood2={140,98,58}, wood3={202,160,114},
  pink1={244,156,194}, pink2={224,112,160}, pinkD={198,86,134},
  red1={232,90,90}, red2={192,58,58},
  yellow1={246,232,170}, yellow2={234,210,130}, yellow3={252,244,206},
  orange1={242,170,80}, orange2={218,140,54},
  sky={144,212,240},
  trunk={140,98,58}, trunkD={108,74,44},
  canopy1={80,170,70}, canopy2={64,128,58}, canopy3={100,198,88},
  ifloor1={202,160,114}, ifloor2={178,134,88},
  iwall1={152,118,86}, iwall2={122,92,66}, iwallTrim={212,182,142},
  cloth={244,182,122}, clothW={252,236,214},
  paper={248,244,232}, ink={90,70,60},
  metal={150,158,166}, metalD={110,118,128}, glass={176,222,240},
  seed={58,46,46}, black={40,34,34}, gray={120,120,124},
  wbg={218,221,224}, wwall={196,200,206}, wwallD={168,174,182},
  wfloor={208,212,216}, wfloorL={224,227,230}, wdark={150,156,164}, wbed={234,236,238}, wline={176,182,190},
  skin={245,205,162}, skinD={214,168,128}, hair={92,64,42},
}

-- ============ TILESET (8x9 = 72 tiles) -> tileset.png ============
do
  local s, img = newImg(128,144)
  local function grassBase(ox,oy) rect(img,ox,oy,16,16,P.grass1); speck(img,ox,oy,16,16,P.grass2,5,0); speck(img,ox,oy,16,16,P.grass3,7,2) end
  local T = {}
  T[0]=function(ox,oy) grassBase(ox,oy) end
  T[1]=function(ox,oy) grassBase(ox,oy); px(img,ox+4,oy+5,P.yellow2); px(img,ox+11,oy+10,P.pink1); px(img,ox+8,oy+13,P.pink1) end
  T[2]=function(ox,oy) rect(img,ox,oy,16,16,P.path1); speck(img,ox,oy,16,16,P.path2,6,1); speck(img,ox,oy,16,16,P.path3,9,3); hline(img,ox,oy,16,P.path2); vline(img,ox,oy,16,P.path2) end
  T[3]=function(ox,oy) grassBase(ox,oy); rect(img,ox+4,oy,8,16,P.path1); speck(img,ox+4,oy,8,16,P.path2,6,1) end
  T[4]=function(ox,oy) rect(img,ox,oy,16,16,P.water1); speck(img,ox,oy,16,16,P.water2,5,0); hline(img,ox+2,oy+4,5,P.foam); hline(img,ox+9,oy+10,4,P.foam) end
  T[5]=function(ox,oy) rect(img,ox,oy,16,16,P.water1); speck(img,ox,oy,16,16,P.water3,7,2); hline(img,ox+1,oy+2,14,P.foam); hline(img,ox+3,oy+8,10,P.water2) end
  T[6]=function(ox,oy) grassBase(ox,oy); rect(img,ox+2,oy+6,12,8,P.canopy2); speck(img,ox+2,oy+6,12,8,P.canopy1,4,0); px(img,ox+4,oy+7,P.pink1); px(img,ox+9,oy+8,P.yellow2); px(img,ox+7,oy+11,P.pink2); px(img,ox+12,oy+11,P.pink1) end
  T[7]=function(ox,oy) grassBase(ox,oy); rect(img,ox+2,oy+5,12,9,P.canopy2); speck(img,ox+2,oy+5,12,9,P.canopy1,3,0); for _,p in ipairs({{5,7},{9,7},{6,10},{11,9},{8,12}}) do px(img,ox+p[1],oy+p[2],P.red1); px(img,ox+p[1],oy+p[2]-1,P.red2) end end
  T[8]=function(ox,oy) rect(img,ox+2,oy+1,12,12,P.canopy2); rect(img,ox+3,oy,10,2,P.canopy2); rect(img,ox+1,oy+3,14,8,P.canopy2); speck(img,ox,oy,16,14,P.canopy1,4,0); speck(img,ox,oy,16,14,P.canopy3,6,3) end
  T[9]=function(ox,oy) grassBase(ox,oy); rect(img,ox+6,oy+2,4,13,P.trunk); vline(img,ox+6,oy+2,13,P.trunkD); px(img,ox+7,oy+7,P.trunkD) end
  T[10]=function(ox,oy) rect(img,ox,oy,16,16,P.wall1); speck(img,ox,oy,16,16,P.wall2,7,2); hline(img,ox,oy+8,16,P.wallD); for i=0,3 do vline(img,ox+i*4+2,oy,8,P.wallD) end; for i=0,3 do vline(img,ox+i*4,oy+8,8,P.wallD) end end
  T[11]=function(ox,oy) rect(img,ox,oy,16,16,P.roof1); for j=0,15 do hline(img,ox,oy+j,16,(j%3==0) and P.roof2 or P.roof1) end; speck(img,ox,oy,16,16,P.roof3,8,4) end
  T[12]=function(ox,oy) rect(img,ox,oy,16,16,P.wall2); rect(img,ox+3,oy+2,10,14,P.door1); rect(img,ox+4,oy+3,8,13,P.door2); px(img,ox+10,oy+9,P.knob) end
  T[13]=function(ox,oy) grassBase(ox,oy); rect(img,ox+1,oy+4,2,10,P.wood2); rect(img,ox+7,oy+4,2,10,P.wood2); rect(img,ox+13,oy+4,2,10,P.wood2); hline(img,ox,oy+6,16,P.wood1); hline(img,ox,oy+10,16,P.wood1) end
  T[14]=function(ox,oy) rect(img,ox,oy,16,16,P.soilD); rect(img,ox+1,oy+1,14,14,P.soil); for _,p in ipairs({{3,3},{8,4},{12,6},{5,9},{10,11},{3,12}}) do px(img,ox+p[1],oy+p[2],P.pink1); px(img,ox+p[1]+1,oy+p[2],P.pink2); px(img,ox+p[1],oy+p[2]-1,P.yellow2) end end
  T[15]=function(ox,oy) grassBase(ox,oy); rect(img,ox+2,oy+4,12,11,P.path2); rect(img,ox+3,oy+5,10,9,P.path1); rect(img,ox+5,oy+7,6,6,P.black); rect(img,ox+5,oy+7,6,3,P.waterDeep); vline(img,ox+2,oy+1,5,P.wood2); vline(img,ox+13,oy+1,5,P.wood2); hline(img,ox+2,oy+1,12,P.wood1) end
  T[16]=function(ox,oy) rect(img,ox,oy,16,16,{225,228,232,235}); speck(img,ox,oy,16,16,{240,242,245,255},4,0); speck(img,ox,oy,16,16,{205,210,216,220},5,2) end
  T[17]=function(ox,oy) rect(img,ox+1,oy+2,14,11,P.wood2); rect(img,ox+2,oy+3,12,9,P.paper); px(img,ox+4,oy+5,P.ink); px(img,ox+6,oy+5,P.ink); px(img,ox+8,oy+5,P.ink); hline(img,ox+4,oy+7,7,P.ink); hline(img,ox+4,oy+9,5,P.ink); rect(img,ox+2,oy+13,2,3,P.wood1); rect(img,ox+12,oy+13,2,3,P.wood1) end
  T[18]=function(ox,oy) grassBase(ox,oy); rect(img,ox+7,oy+6,2,9,P.wood2); rect(img,ox+4,oy+2,8,6,P.red1); rect(img,ox+4,oy+2,8,2,P.red2); hline(img,ox+5,oy+5,6,P.black); rect(img,ox+11,oy+1,1,4,P.red2) end
  T[19]=function(ox,oy) grassBase(ox,oy); for j=0,9 do for i=0,13 do local red=((i//2)+(j//2))%2==0; px(img,ox+1+i,oy+3+j, red and P.red1 or P.clothW) end end end
  T[20]=function(ox,oy) grassBase(ox,oy); rect(img,ox+1,oy+7,14,3,P.wood1); rect(img,ox+1,oy+4,14,2,P.wood2); vline(img,ox+2,oy+9,5,P.wood2); vline(img,ox+13,oy+9,5,P.wood2) end
  T[21]=function(ox,oy) grassBase(ox,oy); rect(img,ox+7,oy+4,2,11,P.metalD); rect(img,ox+5,oy+1,6,4,P.yellow3); rect(img,ox+6,oy+2,4,2,P.yellow2) end
  T[22]=function(ox,oy) grassBase(ox,oy); rect(img,ox+4,oy+8,8,6,P.canopy2); speck(img,ox+4,oy+8,8,6,P.canopy1,3,0) end
  T[23]=function(ox,oy) rect(img,ox,oy,16,16,P.wall1); speck(img,ox,oy,16,16,P.wall2,4,1); speck(img,ox,oy,16,16,P.wallD,9,3) end
  T[24]=function(ox,oy) rect(img,ox,oy,16,16,P.ifloor1); for j=0,3 do hline(img,ox,oy+j*4,16,P.ifloor2) end; speck(img,ox,oy,16,16,P.ifloor2,11,4) end
  T[25]=function(ox,oy) rect(img,ox,oy,16,16,P.ifloor1); for i=0,3 do vline(img,ox+i*4,oy,16,P.ifloor2) end end
  T[26]=function(ox,oy) rect(img,ox,oy,16,16,P.iwall1); speck(img,ox,oy,16,16,P.iwall2,7,3); hline(img,ox,oy,16,P.iwall2) end
  T[27]=function(ox,oy) rect(img,ox,oy,16,16,P.iwall1); rect(img,ox,oy,16,5,P.iwallTrim); hline(img,ox,oy+5,16,P.iwall2) end
  T[28]=function(ox,oy) rect(img,ox,oy,16,16,P.wood2); rect(img,ox+1,oy+4,14,11,P.pink1); rect(img,ox+1,oy+4,14,4,P.clothW); rect(img,ox+2,oy+4,5,3,P.clothW); hline(img,ox+1,oy+9,14,P.pinkD) end
  T[29]=function(ox,oy) rect(img,ox,oy,16,16,P.iwall1); rect(img,ox+3,oy+2,10,12,P.paper); hline(img,ox+3,oy+2,10,P.red1); px(img,ox+5,oy+6,P.ink); px(img,ox+7,oy+6,P.ink); px(img,ox+9,oy+6,P.ink); hline(img,ox+5,oy+9,6,P.ink); px(img,ox+7,oy+11,P.red2); px(img,ox+8,oy+11,P.red2) end
  T[30]=function(ox,oy) rect(img,ox,oy+3,16,12,P.wood2); rect(img,ox,oy+3,16,3,P.wood3); hline(img,ox,oy+9,16,P.wood1); rect(img,ox+2,oy+11,3,3,P.wood1); rect(img,ox+11,oy+11,3,3,P.wood1) end
  T[31]=function(ox,oy) rect(img,ox,oy+1,16,14,P.metalD); rect(img,ox+2,oy+3,12,8,P.black); rect(img,ox+3,oy+7,10,4,P.orange1); rect(img,ox+4,oy+8,8,2,P.yellow2); hline(img,ox+2,oy+2,12,P.metal); px(img,ox+11,oy+4,P.red1) end
  T[32]=function(ox,oy) rect(img,ox,oy,16,16,P.wood1); rect(img,ox+2,oy+2,12,12,P.paper); hline(img,ox+4,oy+5,8,P.ink); hline(img,ox+4,oy+7,8,P.ink); hline(img,ox+4,oy+9,5,P.ink); px(img,ox+12,oy+11,P.red1) end
  T[33]=function(ox,oy) rect(img,ox,oy,16,16,P.wood2); hline(img,ox,oy+5,16,P.wood1); hline(img,ox,oy+10,16,P.wood1); rect(img,ox+2,oy+1,3,3,P.orange1); rect(img,ox+7,oy+1,3,3,P.red1); rect(img,ox+11,oy+1,3,3,P.sky); rect(img,ox+2,oy+6,3,3,P.pink1); rect(img,ox+7,oy+6,3,3,P.yellow2) end
  T[34]=function(ox,oy) rect(img,ox,oy,16,16,P.wood2); hline(img,ox,oy+8,16,P.wood1); rect(img,ox+3,oy+2,4,5,P.orange1); rect(img,ox+3,oy+2,4,2,P.orange2); rect(img,ox+9,oy+2,4,5,P.orange1); rect(img,ox+9,oy+2,4,2,P.orange2); rect(img,ox+3,oy+10,4,5,P.orange1); rect(img,ox+9,oy+10,4,5,P.orange1) end
  T[35]=function(ox,oy) rect(img,ox+1,oy+4,14,4,P.wood3); rect(img,ox+1,oy+4,14,2,P.wood1); vline(img,ox+2,oy+8,6,P.wood2); vline(img,ox+13,oy+8,6,P.wood2) end
  T[36]=function(ox,oy) rect(img,ox+4,oy+2,8,3,P.wood2); rect(img,ox+4,oy+7,8,3,P.wood3); vline(img,ox+4,oy+5,2,P.wood2); vline(img,ox+5,oy+10,4,P.wood2); vline(img,ox+10,oy+10,4,P.wood2) end
  T[37]=function(ox,oy) rect(img,ox+1,oy+5,14,4,P.wood3); rect(img,ox+3,oy,10,7,P.paper); hline(img,ox+3,oy,10,P.water3); hline(img,ox+4,oy+2,8,P.ink); hline(img,ox+4,oy+4,5,P.ink); rect(img,ox+9,oy+1,4,3,P.wood3) end
  T[38]=function(ox,oy) rect(img,ox,oy,16,16,P.iwall1); rect(img,ox+2,oy+2,12,10,P.glass); rect(img,ox+2,oy+2,12,4,P.sky); vline(img,ox+8,oy+2,10,P.iwall2); hline(img,ox+2,oy+7,12,P.iwall2); rect(img,ox+1,oy+1,14,1,P.iwallTrim) end
  T[39]=function(ox,oy) rect(img,ox,oy,16,16,P.iwall1); rect(img,ox+3,oy+2,10,14,P.door1); rect(img,ox+4,oy+3,8,13,P.door2); px(img,ox+10,oy+9,P.knob) end
  T[40]=function(ox,oy) rect(img,ox,oy,16,16,P.wwall); speck(img,ox,oy,16,16,P.wwallD,9,4); hline(img,ox,oy+11,16,P.wwallD) end
  T[41]=function(ox,oy) rect(img,ox,oy,16,16,P.wfloor); hline(img,ox,oy,16,P.wline); vline(img,ox,oy,16,P.wline); speck(img,ox,oy,16,16,P.wfloorL,13,3) end
  T[42]=function(ox,oy) rect(img,ox,oy,16,16,P.wfloorL); hline(img,ox+8,oy,8,P.wline); vline(img,ox,oy+8,8,P.wline) end
  T[43]=function(ox,oy) rect(img,ox,oy,16,16,P.wfloor); rect(img,ox+1,oy+3,14,11,P.wbed); rect(img,ox+1,oy+3,14,3,P.wdark); hline(img,ox+1,oy+9,14,P.wline); rect(img,ox,oy+2,2,13,P.metal); rect(img,ox+14,oy+2,2,13,P.metal) end
  T[44]=function(ox,oy) rect(img,ox,oy,16,16,P.wwall); rect(img,ox+3,oy+1,10,15,P.wfloorL); rect(img,ox+4,oy+2,8,14,P.wfloor); px(img,ox+10,oy+9,P.metalD) end
  T[45]=function(ox,oy) rect(img,ox,oy,16,16,P.wwall); rect(img,ox+2,oy+2,12,10,{212,224,230}); vline(img,ox+8,oy+2,10,P.wdark); hline(img,ox+2,oy+7,12,P.wdark) end
  T[46]=function(ox,oy) for i=0,15 do local j=math.floor(2*math.sin(i*0.9)+6); px(img,ox+i,oy+j,P.pink2); px(img,ox+i,oy+j+1,P.pink1) end; px(img,ox+3,oy+3,P.yellow2); px(img,ox+11,oy+9,P.sky) end
  T[47]=function(ox,oy) rect(img,ox,oy+6,16,10,P.wood2); rect(img,ox,oy+6,16,2,P.wood3); rect(img,ox+2,oy,12,6,P.red1); for i=0,3 do px(img,ox+2+i*4,oy+5,P.yellow2) end end
  T[48]=function(ox,oy) grassBase(ox,oy); for _,p in ipairs({{4,6},{9,4},{11,10},{6,11}}) do px(img,ox+p[1],oy+p[2],P.red1); px(img,ox+p[1]+1,oy+p[2],P.red2); px(img,ox+p[1],oy+p[2]+1,P.yellow2) end end
  T[49]=function(ox,oy) grassBase(ox,oy); for _,p in ipairs({{5,5},{10,7},{7,11},{12,12}}) do px(img,ox+p[1],oy+p[2],P.sky); px(img,ox+p[1]+1,oy+p[2],P.water2); px(img,ox+p[1],oy+p[2]+1,P.yellow2) end end
  T[50]=function(ox,oy) grassBase(ox,oy); rect(img,ox+6,oy+9,3,4,P.wall1); rect(img,ox+4,oy+6,7,4,P.red1); px(img,ox+5,oy+7,P.yellow3); px(img,ox+8,oy+8,P.yellow3) end
  T[51]=function(ox,oy) grassBase(ox,oy); rect(img,ox+3,oy+7,10,6,P.gray); rect(img,ox+3,oy+7,10,2,{150,150,154}); px(img,ox+5,oy+10,P.metalD) end
  T[52]=function(ox,oy) grassBase(ox,oy); rect(img,ox+4,oy+7,8,6,P.trunk); rect(img,ox+5,oy+6,6,2,P.wood3); px(img,ox+7,oy+7,P.trunkD); px(img,ox+8,oy+7,P.trunkD) end
  T[53]=function(ox,oy) rect(img,ox,oy,16,16,P.water1); speck(img,ox,oy,16,16,P.water2,5,0); rect(img,ox+4,oy+5,8,6,P.canopy1); px(img,ox+7,oy+7,P.pink1); px(img,ox+8,oy+7,P.pink2) end
  T[54]=function(ox,oy) rect(img,ox,oy,16,16,P.water1); speck(img,ox,oy,16,16,P.water2,5,0); vline(img,ox+5,oy+2,10,P.canopy2); vline(img,ox+9,oy+1,11,P.canopy2); rect(img,ox+4,oy+1,3,3,P.trunk); rect(img,ox+8,oy,3,3,P.trunk) end
  T[55]=function(ox,oy) rect(img,ox+4,oy+4,8,10,P.orange1); rect(img,ox+4,oy+4,8,3,P.orange2); rect(img,ox+5,oy+1,6,3,P.wood2); rect(img,ox+6,oy+8,4,4,P.yellow2) end
  T[56]=function(ox,oy) rect(img,ox+1,oy+2,14,13,P.wood2); rect(img,ox+2,oy+3,12,11,P.wood1); vline(img,ox+8,oy+3,11,P.wood2); hline(img,ox+2,oy+8,12,P.wood2) end
  T[57]=function(ox,oy) rect(img,ox+3,oy+1,10,14,P.wood1); rect(img,ox+3,oy+1,10,2,P.wood2); hline(img,ox+3,oy+5,10,P.wood2); hline(img,ox+3,oy+10,10,P.wood2); vline(img,ox+7,oy+1,14,P.wood3) end
  T[58]=function(ox,oy) rect(img,ox,oy,16,16,P.wood2); hline(img,ox,oy+8,16,P.wood1); for i=0,4 do vline(img,ox+1+i*3,oy+1,6,({P.red1,P.sky,P.canopy1,P.orange1,P.pink2})[i+1]) end; for i=0,4 do vline(img,ox+1+i*3,oy+9,6,({P.canopy1,P.pink2,P.red1,P.sky,P.yellow2})[i+1]) end end
  T[59]=function(ox,oy) rect(img,ox,oy,16,16,P.iwall1); rect(img,ox+4,oy+3,8,8,P.wall1); rect(img,ox+5,oy+4,6,6,P.paper); vline(img,ox+8,oy+5,3,P.ink); hline(img,ox+8,oy+7,3,P.ink) end
  T[60]=function(ox,oy) rect(img,ox,oy,16,16,P.iwall1); rect(img,ox+2,oy+2,12,10,P.wood2); rect(img,ox+3,oy+3,10,8,P.sky); rect(img,ox+3,oy+8,10,3,P.canopy1); px(img,ox+10,oy+5,P.yellow3) end
  T[61]=function(ox,oy) rect(img,ox+5,oy+10,6,5,P.orange2); rect(img,ox+4,oy+9,8,2,P.orange1); rect(img,ox+5,oy+4,6,6,P.canopy2); speck(img,ox+5,oy+4,6,6,P.canopy1,3,0) end
  T[62]=function(ox,oy) rect(img,ox,oy,16,16,P.ifloor1); rect(img,ox+2,oy+3,12,10,P.pink2); rect(img,ox+4,oy+5,8,6,P.pink1); px(img,ox+7,oy+7,P.yellow2); px(img,ox+8,oy+8,P.yellow2) end
  T[63]=function(ox,oy) rect(img,ox,oy,16,16,P.grass2); speck(img,ox,oy,16,16,P.canopy2,5,0); speck(img,ox,oy,16,16,P.grass1,7,2) end
  T[64]=function(ox,oy) grassBase(ox,oy); px(img,ox+3,oy+3,P.orange1); px(img,ox+7,oy+6,P.pink2); px(img,ox+12,oy+4,P.yellow2); px(img,ox+9,oy+12,P.red1); px(img,ox+4,oy+11,P.sky) end
  T[65]=function(ox,oy) rect(img,ox,oy,16,16,P.waterDeep); speck(img,ox,oy,16,16,P.water3,5,0); hline(img,ox+3,oy+6,8,P.water2) end
  T[66]=function(ox,oy) rect(img,ox,oy,16,16,P.path1); speck(img,ox,oy,16,16,P.path2,6,1); rect(img,ox,oy,6,6,P.grass1); speck(img,ox,oy,6,6,P.grass2,4,0) end
  T[67]=function(ox,oy) rect(img,ox,oy,16,16,P.roof1); rect(img,ox,oy+11,16,5,P.roof2); hline(img,ox,oy+11,16,P.wall1); speck(img,ox,oy,16,11,P.roof3,8,4) end
  T[68]=function(ox,oy) rect(img,ox,oy,16,16,P.wall1); speck(img,ox,oy,16,16,P.wall2,7,2); rect(img,ox+3,oy+3,10,9,P.glass); rect(img,ox+3,oy+3,10,4,P.sky); vline(img,ox+8,oy+3,9,P.wallD); hline(img,ox+3,oy+7,10,P.wallD); rect(img,ox+2,oy+2,12,1,P.wallD) end
  T[69]=function(ox,oy) rect(img,ox,oy,16,16,P.sky); rect(img,ox+7,oy+4,3,3,P.yellow2); px(img,ox+8,oy+3,P.yellow3); px(img,ox+8,oy+8,P.yellow3); px(img,ox+4,oy+6,P.yellow3); px(img,ox+12,oy+6,P.yellow3) end
  T[70]=function(ox,oy) grassBase(ox,oy); vline(img,ox+7,oy+8,5,P.canopy2); rect(img,ox+6,oy+5,4,4,P.clothW); px(img,ox+7,oy+6,P.yellow2) end
  T[71]=function(ox,oy) rect(img,ox,oy,16,16,P.path2); for j=0,3 do for i=0,3 do local c=((i+j)%2==0) and P.path1 or P.path3; rect(img,ox+i*4,oy+j*4,4,4,c) end end end
  for idx=0,71 do T[idx]((idx%8)*16,(idx//8)*16) end
  save(s,"tileset.png"); s:close(); print("tileset done")
end

-- ============ PLAYER walk sheet 64x96 (4 dir x 4 frame) ============
do
  local skin=P.skin; local skinD=P.skinD; local hair=P.hair
  local shirt={92,152,212}; local shirtD={64,116,176}
  local pants={78,96,128}; local pantsD={56,72,102}; local shoe={70,58,58}
  local s, img = newImg(64,96)
  local function person(ox,oy,dir,frame)
    local sw=0; if frame==1 then sw=1 elseif frame==3 then sw=-1 end
    rect(img,ox+5,oy+10,6,7,shirt); hline(img,ox+5,oy+10,6,shirtD); vline(img,ox+5,oy+10,7,shirtD)
    vline(img,ox+4,oy+11,4,skin); vline(img,ox+11,oy+11,4,skin)
    rect(img,ox+5,oy+3,6,6,skin); hline(img,ox+5,oy+8,6,skinD)
    rect(img,ox+4,oy+1,8,3,hair); px(img,ox+4,oy+4,hair); px(img,ox+11,oy+4,hair)
    local lx,rx=ox+6,ox+9
    if dir==0 then
      px(img,ox+6,oy+5,P.black); px(img,ox+9,oy+5,P.black); px(img,ox+7,oy+7,skinD)
      rect(img,lx,oy+17,2,4,pants); rect(img,rx,oy+17,2,4,pants)
      rect(img,lx,oy+21+(sw>0 and 1 or 0),2,1,shoe); rect(img,rx,oy+21+(sw<0 and 1 or 0),2,1,shoe)
    elseif dir==3 then
      rect(img,ox+4,oy+1,8,5,hair)
      rect(img,lx,oy+17,2,4,pants); rect(img,rx,oy+17,2,4,pants)
      rect(img,lx,oy+21+(sw>0 and 1 or 0),2,1,shoe); rect(img,rx,oy+21+(sw<0 and 1 or 0),2,1,shoe)
    else
      px(img,ox+9,oy+5,P.black); px(img,ox+11,oy+6,skinD); rect(img,ox+4,oy+1,7,3,hair)
      rect(img,ox+6+sw,oy+17,2,4,pants); rect(img,ox+8-sw,oy+17,2,4,pantsD)
      rect(img,ox+6+sw,oy+21,2,1,shoe); rect(img,ox+8-sw,oy+21,2,1,shoe)
    end
  end
  for f=0,3 do person(f*16,0,0,f); person(f*16,72,3,f); person(f*16,48,2,f) end
  for f=0,3 do for yy=0,23 do for xx=0,15 do
    img:drawPixel(f*16+(15-xx), 24+yy, img:getPixel(f*16+xx, 48+yy))
  end end end
  save(s,"player.png"); s:close(); print("player done")
end

-- ============ PLAYER PORTRAITS 64x32 (smile / real face) ============
do
  local s, img = newImg(64,32)
  local function drawPortrait(ox,tired)
    local sk = tired and {216,199,185} or P.skin
    local skd = tired and {186,170,158} or P.skinD
    local hr = tired and {104,98,92} or P.hair
    rect(img,ox+8,4,16,20,sk)
    rect(img,ox+7,3,18,7,hr); px(img,ox+7,10,hr); px(img,ox+24,10,hr)
    if tired then
      rect(img,ox+11,13,2,2,P.black); rect(img,ox+19,13,2,2,P.black)
      hline(img,ox+10,16,4,skd); hline(img,ox+18,16,4,skd)
      hline(img,ox+13,20,6,skd); px(img,ox+12,21,skd); px(img,ox+19,21,skd)
    else
      rect(img,ox+11,12,2,3,P.black); rect(img,ox+19,12,2,3,P.black); px(img,ox+12,12,P.glass)
      px(img,ox+12,19,skd); hline(img,ox+13,20,6,skd); px(img,ox+19,19,skd)
      px(img,ox+14,13,{255,150,160}); px(img,ox+18,13,{255,150,160})
    end
    rect(img,ox+15,16,2,2,skd)
  end
  drawPortrait(0,false); drawPortrait(32,true)
  save(s,"portraits.png"); s:close(); print("portraits done")
end

-- ============ NPCS 48x24 (smile/flat/off) ============
local function drawAnimal(img, ox, expr, spec)
  local body=spec.body; local bodyD=spec.bodyD; local muzzle=spec.muzzle or {250,244,232}
  -- torso
  rect(img,ox+3,9,10,12,body); rect(img,ox+3,9,10,2,bodyD)
  rect(img,ox+5,13,6,7,muzzle) -- belly
  -- feet
  rect(img,ox+4,21,3,2,bodyD); rect(img,ox+9,21,3,2,bodyD)
  -- head
  rect(img,ox+4,2,8,8,body)
  rect(img,ox+5,5,6,5,muzzle) -- face patch
  -- ears
  if spec.ears=="floppy" then
    rect(img,ox+2,3,2,5,bodyD); rect(img,ox+12,3,2,5,bodyD)
  elseif spec.ears=="long" then
    rect(img,ox+4,-0+0,2,4,body); rect(img,ox+10,0,2,4,body); px(img,ox+4,1,P.pink1); px(img,ox+10,1,P.pink1)
    rect(img,ox+4,0,2,3,body); rect(img,ox+10,0,2,3,body)
  elseif spec.ears=="round" then
    rect(img,ox+3,1,3,3,body); rect(img,ox+10,1,3,3,body); px(img,ox+4,2,bodyD); px(img,ox+11,2,bodyD)
  elseif spec.ears=="pointy" then
    px(img,ox+4,1,body); rect(img,ox+3,2,3,2,body); px(img,ox+11,1,body); rect(img,ox+10,2,3,2,body); px(img,ox+4,2,P.pink1); px(img,ox+11,2,P.pink1)
  elseif spec.ears=="antler" then
    px(img,ox+4,0,P.wood2); px(img,ox+4,1,P.wood2); px(img,ox+3,0,P.wood2); px(img,ox+11,0,P.wood2); px(img,ox+11,1,P.wood2); px(img,ox+12,0,P.wood2)
  end
  -- eyes (base y=6). off lowers RIGHT eye by 1px.
  local ey=6
  px(img,ox+6,ey,P.black)
  px(img,ox+9, expr=="off" and ey+1 or ey, P.black)
  -- nose
  px(img,ox+7,8,bodyD); px(img,ox+8,8,bodyD)
  -- mouth: smile curve / flat line / off = smile + 1px corner
  if expr=="flat" then
    hline(img,ox+6,10,4,bodyD)
  else
    px(img,ox+5,9,bodyD); hline(img,ox+6,10,4,bodyD); px(img,ox+10,9,bodyD)
    if expr=="off" then px(img,ox+11,9,bodyD) end -- 1px extra corner
  end
  -- extras
  if spec.whiskers then hline(img,ox+1,7,3,P.gray); hline(img,ox+12,7,3,P.gray) end
  if spec.glasses then rect(img,ox+5,5,3,3,P.metal); rect(img,ox+8,5,3,3,P.metal); px(img,ox+6,6,P.glass); px(img,ox+9, expr=="off" and 7 or 6,P.glass) end
  if spec.shell then rect(img,ox+3,10,10,9,{86,140,80}); rect(img,ox+5,12,6,5,{110,168,100}); px(img,ox+7,14,{70,116,66}); px(img,ox+8,15,{70,116,66}); rect(img,ox+5,13,6,7,muzzle,{}); rect(img,ox+3,10,10,9,{86,140,80}); px(img,ox+6,13,{70,116,66}); px(img,ox+9,16,{70,116,66}) end
  if spec.coat then rect(img,ox+3,11,10,10,P.clothW); rect(img,ox+3,11,10,2,{230,230,236}); rect(img,ox+7,13,2,7,P.red1); rect(img,ox+6,15,4,2,P.red1); rect(img,ox+4,20,3,1,bodyD); rect(img,ox+9,20,3,1,bodyD) end
  if spec.head then rect(img,ox+4,0,8,3,spec.head) end
end

do
  local specs = {
    afu   ={body={168,120,72},  bodyD={128,90,52},  ears="floppy"},                         -- 狗 村长
    yuan  ={body={244,236,222}, bodyD={206,196,180}, ears="long"},                            -- 兔 面包师
    dabao ={body={128,90,60},   bodyD={98,68,44},   ears="round"},                            -- 熊 邮差
    mimi  ={body={236,152,80},  bodyD={200,120,56}, ears="pointy", whiskers=true},            -- 猫 杂货
    fu    ={body={216,176,124}, bodyD={176,138,92}, ears="antler", coat=true},               -- 鹿 医生
    gui   ={body={120,180,110}, bodyD={90,140,84},  ears=nil,      shell=true, glasses=true}, -- 龟 老者
    afu2  =nil,
  }
  local order = {"afu","yuan","dabao","mimi","fu","gui"}
  for _,name in ipairs(order) do
    local s, img = newImg(48,24)
    local exprs = {"smile","flat","off"}
    for i,e in ipairs(exprs) do drawAnimal(img,(i-1)*16,e,specs[name]) end
    save(s,"npc_"..name..".png"); s:close()
  end
  print("npcs done")
end

-- ============ TWIN BIRDS 32x24 (beak closed / open) ============
do
  local s, img = newImg(32,24)
  local function drawBird(ox,open)
    local body={110,170,220}; local bodyD={78,132,186}
    rect(img,ox+4,6,8,10,body); rect(img,ox+4,6,8,2,{150,200,240})
    rect(img,ox+3,9,3,5,bodyD) -- wing
    rect(img,ox+5,3,6,5,body) -- head
    px(img,ox+7,5,P.black); px(img,ox+8,5,P.black) -- eyes
    -- beak
    if open then
      px(img,ox+11,6,P.orange2); px(img,ox+12,6,P.orange2); px(img,ox+11,8,P.orange2); px(img,ox+12,8,P.orange2); px(img,ox+13,7,P.orange1)
    else
      px(img,ox+11,7,P.orange2); px(img,ox+12,7,P.orange2); px(img,ox+13,7,P.orange1)
    end
    -- feet
    px(img,ox+6,16,P.orange2); px(img,ox+9,16,P.orange2)
    -- little tuft
    px(img,ox+7,2,bodyD); px(img,ox+8,2,body)
  end
  drawBird(0,false); drawBird(16,true)
  save(s,"birds.png"); s:close(); print("birds done")
end

-- ============ EXTRAS (群演) 32x80 = 5 critters x 2 frames, 16x16 ============
do
  local s, img = newImg(32,80)
  local function critter(ox,oy,f,spec)
    local bob = (f==1) and 1 or 0
    local b=spec.body; local bd=spec.bodyD
    rect(img,ox+4,oy+7+bob,8,6,b); rect(img,ox+4,oy+7+bob,8,2,bd) -- body
    rect(img,ox+5,oy+3+bob,6,5,b) -- head
    px(img,ox+6,oy+5+bob,P.black); px(img,ox+9,oy+5+bob,P.black)
    if spec.tail=="bushy" then rect(img,ox+11,oy+4+bob,3,7,b); rect(img,ox+12,oy+3+bob,2,3,bd) end
    if spec.tail=="thin" then vline(img,ox+12,oy+9+bob,3,bd) end
    if spec.spikes then for i=0,4 do px(img,ox+4+i*2,oy+6+bob,bd); px(img,ox+5+i*2,oy+8+bob,bd) end end
    if spec.ears=="mouse" then px(img,ox+5,oy+2+bob,b); px(img,ox+10,oy+2+bob,b); rect(img,ox+4,oy+2+bob,2,2,b); rect(img,ox+10,oy+2+bob,2,2,b) end
    if spec.ears=="pointy" then px(img,ox+5,oy+2+bob,b); px(img,ox+10,oy+2+bob,b) end
    rect(img,ox+5,oy+13+bob,2,2,bd); rect(img,ox+9,oy+13+bob,2,2,bd) -- feet
  end
  local specs = {
    {body={214,142,72},  bodyD={176,108,52}, tail="bushy", ears="pointy"},  -- squirrel
    {body={150,120,90},  bodyD={110,86,64},  spikes=true, ears="pointy"},   -- hedgehog
    {body={200,160,100}, bodyD={160,120,70}, tail="bushy", ears="pointy"},  -- squirrel2
    {body={188,190,196}, bodyD={150,152,158},tail="thin", ears="mouse"},    -- mouse
    {body={230,200,120}, bodyD={196,164,90}, tail="thin", ears="pointy"},   -- chipmunk
  }
  for k=0,4 do critter(0,k*16,0,specs[k+1]); critter(16,k*16,1,specs[k+1]) end
  save(s,"extras.png"); s:close(); print("extras done")
end

-- ============ SPARROW (E3 real bird) 16x16 gray ============
do
  local s, img = newImg(16,16)
  local g1={128,124,118}; local g2={98,94,90}; local g3={160,156,150}; local beak={90,80,60}
  rect(img,4,6,8,6,g1); rect(img,4,6,8,2,g3)
  rect(img,3,8,3,4,g2) -- wing
  rect(img,10,4,4,4,g1) -- head
  px(img,12,5,P.black); px(img,13,6,beak); px(img,14,6,beak)
  px(img,5,12,beak); px(img,8,12,beak) -- feet
  speck(img,4,6,8,6,g2,3,0)
  save(s,"sparrow.png"); s:close(); print("sparrow done")
end

print("ALL ASSETS DONE")
