-- gen_portraits.lua: generate portrait sprite sheet for dialogue UI. -- Each portrait cell: 24x24. Single row of many cells. -- Cells order: -- 0 player-smile -- 1 player-realface (tired) -- 2 afu (dog mayor) smile -- 3 afu flat -- 4 afu off -- 5 yuanyuan (rabbit baker) smile -- 6 yuanyuan flat -- 7 yuanyuan off -- 8 dabao (bear postman) smile -- 9 dabao flat -- 10 dabao off -- 11 mimi (cat shopkeeper) smile -- 12 mimi flat -- 13 mimi off -- 14 dr_fu (deer doctor) smile (only smile; flat/off unused but provided) -- 15 dr_fu flat -- 16 dr_fu off -- 17 twinbirds smile -- 18 grandpa_turtle (turtle elder) smile -- 19 grandpa_turtle flat -- 20 grandpa_turtle off -- 21..25 extras (squirrel/hedgehog/etc) smile -- Produces assets/sprites/portraits.png local FW = 24 local FH = 24 local N = 26 local W = FW*N local H = FH app.command.NewFile{ width=W, height=H, colorMode=ColorMode.RGB } local spr = app.activeSprite local img = app.activeImage for y=0,H-1 do for x=0,W-1 do img:drawPixel(x,y, app.pixelColor.rgba(0,0,0,0)) end end local function px(x,y,c) img:drawPixel(x,y,c) end local function rect(ox,oy,w,h,c) for y=oy,oy+h-1 do for x=ox,ox+w-1 do px(ox+(x-ox),y,c) end end end -- careful rect above buggy; redefine properly local function R(ox,oy,w,h,c) for y=oy,oy+h-1 do for x=ox,ox+w-1 do img:drawPixel(x,y,c) end end end -- shared colors local skin = app.pixelColor.rgba(255,214,176,255) local skinS= app.pixelColor.rgba(224,176,140,255) local eye = app.pixelColor.rgba(56,40,40,255) local mouth= app.pixelColor.rgba(200,110,110,255) local cheek= app.pixelColor.rgba(255,170,170,255) local white= app.pixelColor.rgba(245,245,245,255) local black= app.pixelColor.rgba(40,40,40,255) -- generic face drawer: ox,oy top-left of 24x24 cell -- species-specific color + ears, expression (smile/flat/off) -- species: human, dog, rabbit, bear, cat, deer, bird, turtle, squirrel, hedgehog local function face(ox, oy, col, species, expr) -- head fill R(ox+6, oy+5, 12, 12, col) -- ears per species if species == "rabbit" then R(ox+7, oy+1, 2, 5, col); R(ox+15, oy+1, 2, 5, col) R(ox+7, oy+2, 2, 2, skinS); R(ox+15, oy+2, 2, 2, skinS) elseif species == "dog" then R(ox+5, oy+4, 2, 4, col); R(ox+17, oy+4, 2, 4, col) -- floppy R(ox+4, oy+6, 2, 6, col) R(ox+18, oy+6, 2, 6, col) elseif species == "bear" then R(ox+5, oy+3, 3, 3, col); R(ox+16, oy+3, 3, 3, col) px(ox+6, oy+4, skinS); px(ox+17, oy+4, skinS) elseif species == "cat" then -- pointy ears px(ox+6, oy+4, col); px(ox+7, oy+2, col); px(ox+8, oy+1, col); px(ox+9, oy+3, col) px(ox+15, oy+3, col); px(ox+16, oy+1, col); px(ox+17, oy+2, col); px(ox+18, oy+4, col) elseif species == "deer" then px(ox+8, oy+1, col); px(ox+8, oy+2, col); px(ox+9, oy+0, col) px(ox+9, oy+2, skinS); px(ox+15, oy+0, col); px(ox+15, oy+2, col); px(ox+14, oy+1, col) px(ox+14, oy+2, skinS) elseif species == "turtle" then -- no ears, rounded; draw a cap R(ox+5, oy+4, 14, 4, col) elseif species == "bird" then R(ox+6, oy+4, 12, 10, col) px(ox+7, oy+3, col); px(ox+16, oy+3, col) elseif species == "squirrel" then R(ox+5, oy+4, 2, 3, col); R(ox+17, oy+4, 2, 3, col) R(ox+2, oy+2, 3, 6, col) -- tail elseif species == "hedgehog" then for x=6,17,2 do px(ox+x, oy+3, skinS); px(ox+x, oy+4, skinS) end end -- eyes (expression dependent) if expr == "smile" then px(ox+9, oy+9, eye); px(ox+14, oy+9, eye) px(ox+9, oy+10, eye); px(ox+14, oy+10, eye) -- cheeks px(ox+8, oy+12, cheek); px(ox+15, oy+12, cheek) -- smile mouth px(ox+11, oy+13, mouth); px(ox+12, oy+13, mouth) px(ox+10, oy+12, mouth); px(ox+13, oy+12, mouth) elseif expr == "flat" then px(ox+9, oy+9, eye); px(ox+14, oy+9, eye) -- straight mouth px(ox+11, oy+13, mouth); px(ox+12, oy+13, mouth) elseif expr == "off" then -- one eye dropped 1px (the signature "off" detail) px(ox+9, oy+9, eye); px(ox+9, oy+10, eye) px(ox+14, oy+10, eye); -- right eye 1px lower -- mouth with extra 1px droop px(ox+11, oy+13, mouth); px(ox+12, oy+13, mouth); px(ox+13, oy+13, mouth) end end -- 0 player smile (human) face(0*FW, 0, skin, "human", "smile") -- add hair R(0*FW+6, 3, 12, 4, app.pixelColor.rgba(150,110,80,255)) -- 1 player realface (tired) face(1*FW, 0, skinS, "human", "flat") R(1*FW+6, 3, 12, 4, app.pixelColor.rgba(150,110,80,255)) -- tired eyes: half-lids px(1*FW+9, 10, skinS); px(1*FW+14, 10, skinS) -- a small frown px(1*FW+11, 14, mouth); px(1*FW+12, 14, mouth) -- shadow under eyes px(1*FW+9, 11, skinS); px(1*FW+14, 11, skinS) -- species color presets local dogC = app.pixelColor.rgba(200,150,90,255) local rabC = app.pixelColor.rgba(245,235,230,255) local bearC = app.pixelColor.rgba(150,100,60,255) local catC = app.pixelColor.rgba(230,220,210,255) local deerC = app.pixelColor.rgba(210,160,110,255) local birdC = app.pixelColor.rgba(120,200,230,255) local turC = app.pixelColor.rgba(120,160,90,255) local sqC = app.pixelColor.rgba(170,110,70,255) local hedC = app.pixelColor.rgba(150,110,70,255) -- 2-4 afu dog: smile/flat/off face(2*FW, 0, dogC, "dog", "smile") face(3*FW, 0, dogC, "dog", "flat") face(4*FW, 0, dogC, "dog", "off") -- 5-7 yuanyuan rabbit face(5*FW, 0, rabC, "rabbit", "smile") face(6*FW, 0, rabC, "rabbit", "flat") face(7*FW, 0, rabC, "rabbit", "off") -- 8-10 dabao bear face(8*FW, 0, bearC, "bear", "smile") face(9*FW, 0, bearC, "bear", "flat") face(10*FW, 0, bearC, "bear", "off") -- 11-13 mimi cat face(11*FW, 0, catC, "cat", "smile") face(12*FW, 0, catC, "cat", "flat") face(13*FW, 0, catC, "cat", "off") -- 14-16 dr_fu deer (only smile used; flat/off provided for completeness) face(14*FW, 0, deerC, "deer", "smile") face(15*FW, 0, deerC, "deer", "flat") face(16*FW, 0, deerC, "deer", "off") -- 17 twinbirds smile (single) face(17*FW, 0, birdC, "bird", "smile") -- 18-20 grandpa turtle face(18*FW, 0, turC, "turtle", "smile") face(19*FW, 0, turC, "turtle", "flat") face(20*FW, 0, turC, "turtle", "off") -- 21-25 extras face(21*FW, 0, sqC, "squirrel", "smile") face(22*FW, 0, hedC, "hedgehog", "smile") face(23*FW, 0, sqC, "squirrel", "smile") face(24*FW, 0, hedC, "hedgehog", "smile") face(25*FW, 0, sqC, "squirrel", "smile") local out = "assets/sprites/portraits.png" spr:saveCopyAs(out) print("Saved " .. out) app.exit()