0 \uaIcVzKD4--#ˑYm:M @2TvͫgE#2Tv2TvbͫG̰ "» " ""DD""DCDD3D3@DD0DD@""B"BDD4C4CDCDDDDCD3DDp"p"p'"'"p""p'"'r"""'"D@D@D@D@DDD@D@D@dDfdf0d3DDF̺̪  ¬ " ! "  ! " 0D30DD0DD0DD0DD3DDCD3DD3DDDDD4DD3DD3CD4DD43DD333 '"'""'"""'"""w"""p'"" "" "'r"'r"""""""""""""""r""@D@33D3D40D430333300CDD3DDD3@DD@@43DD``f`ffwpwwwDD3DD3@@D4CD4CDDdf00303030003D03D0D3D3DD3DfCdDfDDp0C30ffD3D33@403C43C4033D3s3333303033333333330333333333ff3fF@DDs@DDs03w03w0swp7373@w3Dw7DUw7DUwGTwwTww3PUDUUUUxw33pw33w33ww3www3333wٝ ޙЙݝݙݙݙٙݙٝٝٙ힙ݝݙݝݝݙݙݙٙݙݙݙٝݙ wpxwݐݙݙݙݙݙݙ~ٝٙٙٝޙݝݝݝݙ홙홙홙静ݞݙݙٝٝٝٝ=ٝݙݝٝٝ ݙٝݙٝݙݙpxxxppppwwwwwwwݙٝٝݙݙݙݙݙٙwٝwٝwww癙y癙y癙ywݙyݝ=y=ysw=wwsי3ݝwݗݗ9ݗ݈=ٙٝٙwywywwww}wwwwwwww3wיwݙי833ٙݙ݉݉3힙ݝ wwpwp3ٙy3y}}}~~ݙٙ93y7ywӝyw7~}wݝ}7ݙw}w}73s77s8ww8ݙ ݃p383xwww}wwwwwwwywwy}陙闙wwwwݝޝޝݝݝ9ݙ=݃=xݝٙݙݙ ݝݙ pwwpwpwpwwpwpwww0w3~wwww~www8w8ww8833wxwwwwxw7www3www7w7w3w373033ݝ333333=s9ݙ݈݃xݙݝםووݙݙݙ wxwxxxxxwxwwwwwwwpxwxwwwwwxwwpw7pw3pw3ww73w733w733w33333333333p88݈興  wwpppppwpww73w33w33w3773w7sw7sw7sw37ppyy9وxٙٙݝݝ ݙ ݙ pwwwwwp0swpwws333w3w73ww73www7wwwwswww3www3sww373ww7wwwwwwِ i`Ff`DF4@ffPf3P030333f@DDDDDT@@DDD@DDDDD@DDT@DDUDDDDDDDDDDDDDDDDDDDUUUUUUuSDDDDDDDDUDDDUUDD@DDDDDDDDDDDDDDDDDDDDDDD@DDDDDDTUDTUUDDDDDDDDDUTDDU5UDDD30`f63f63`63`63@DTCD033`d0D@eUDDDDDDDTUDTU@UUUUPDUUwUUUwUUUwUUUwUUUwWUUuWTUugTUuwUUctUU3vUU3vUUswU6wwesgf3gffwfffGDDDGD4TGDUgDUffUf6HUfHdfDUUUUUUUwUUuwUuwwUwwWuwwWwwwSwww3wWUEwUUEWUUEUUUEUUUUUU833WUeDDDDDDCDCD3DDSDDUDD3``ffffffff`ff6fffD3Dt3D@tCDDtCDDtDDDtdDDtfffvgfD@DDDDD43Dt7CDtwCDtw7fefvffffTUuwDTu7DDwSDtwSDt7U3s7U7s8Uww8UghfUUdUUUUUXUUUUUUUUUUUUUff@f@ee383wwwWvwwgwwwDwwpwwppUUUfUfffgfffgf`wwwwDDDDDDfDDDfFTE`FUEFUUfUUdVU@DDDDDDDD4DED4DEDDU5xDDDDDDD0f030303333fvw3wffffwwwgpwwff@fw8Ufw8Sww8S8cccUUUUUUUfUUffffff3wxwwwwxw7www3www7w7w3w373033df`D333330f3WU6sUU3hVUDDD`xEDUDDUGDDHDDUUDUUUUUUVUUDDDDDDDDDDDDUxwxwwwwwxwwpw7pw3pw3ww73w733w733w33333333333DDD`fUUhh`ff`ffUETUUUUUVUUEfUUfffff`fedfffPPUPUUPUUUPffUeffUefUfUfefw73w33w33w3773w7sw7sw7sw37`fvff`fXWEHDDt`ffff`fHDDDxDDDDDDUUUUUUeVefff@D@D@D@f@f@DfDffDfdffffPUUUePeEDDD@DTDfDDD0swpwws333w3w73ww73www7wwwwswww3www3sww373ww7wwwwww`f@@@D@@@@DTDDD@C0C33333333333@D4@DD3DD43DDD4DDTD3333333333333333DDDD333D3333333333DDDDDDDDCDDCDDDdEDDfDD ̼333333;333333333333ʻʪ3=3333333333333333333333333333DffFDfffDDdfDDDDDDDDNDD@DDDDDEDDDEDdfDDDDDDDDDDDDDDDddffffffVDDDDDDDffDDffDDDDDDDDDDD̪̪̪ @DDDfFDfff`fDDDDDDDDffffffffDDDDDDKffffffffDKDDDfffff PNG  IHDR$f>aiCCPkCGColorSpaceDisplayP3(c``RI,(aa``+) rwRR` b >@% 0|/:%5I^bՋD0գd S JSl): ȞbC@$XMH3}VHHIBOGbCnₜJc%VhʢG`(*x%(30s 8, Ě30n~@\;b 'v$%)-rH @=iF`yF'{Vc``ww1Py!e5xeXIfMM*JR(iZ pHYsMMʍ/~iTXtXML:com.adobe.xmp Untitled Artwork 132 132 2 2 Untitled Artwork Ξ IDATxϪEϑč(\)>1Wp""A([.u35Nuo ꚯ7}&ٿ8v@^k2k. `&.C 0pH5 G@4L7\: mRÏjppV~{2"!nKhk Y"F5Be#K˜;{lE#@"4aao9Ik Xz{B 3n7*^+p%Kn@#^sd'ХT$h{%Н;h1?lE; HLi/A by||!p@;=[y;!%n,0γe_X%SRk֜g|?Dۿ Z.,-%ZZ_k&t!%ʢ}֧1Z@7#2 wZs!Ph^KlC5 мB[iD-9NkXMԧ2t!)"@ 0_,Ai{N1EwJM `1EޟsM xx <;ˏs 4/.XcȆ~lEy%+1g c4/17e !$f,15s*w!p@>uc6;wTq V05knEc t%8^Rts휭۟?g*̽v`-R3UC|ƶj-1uN׳S@W;_Sk֋fNd^$O9ֈA/:OY87U c}X߿ݺ7z;Y~nGh ǛqƼ#)[ŘEq+ŵP+{n_㴇߁UpbxvġE:v9D}}>ΔU՛}?OiWe3{7ܩflEPB{͎Ua>8ϓGrjK~ H.>܃j'Us[k9~xm!h1a}v6=0q1GZ>旍i{eӰgK9ciLl>sk8ؿ8E]j|;vK]v♽.6еj\jl|VeZ~v^KXSulLsx e!V_. _ T ѵj4msbi5;/ZCe,+P<˾lw*1+'_-wu6zbZAg(N*GgsbZbYXpxXc[mE?]+vqkqJ{1VynG܍~CB4lղ;^ lh-Pځ+"\Oɞ|*Vv4+ީCZqЈwh N-|>,Z08bbȼu/W*fuw ///z*Yd2Z;0]݊_ÚSojchϲ[Sw&1ogNt "^m~Z}j%ܵl&`īFy60nZ,K`k?EC4'B- X8}EDz\D/Y r@`Y˦L4@@HBA X}>N7Ȉ!sںX'V /^fuj4V} .IX#t̸-!ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD '@8M)Hq8 !ӔD 'g1ՃIENDB`  @`a`@` ``` `` @`@``@@a` ``` `` ` ` `` `` @@`@ @` @`@`@`a` ` ```@` `` ` ` ` `` @`@``@@a` `` @`a` `@` `` ` ` ` `` @`@`` @@a` ` @`a` ` `@` `` ` ` ` ``@@`@@a` ` @a @` ` ` ```@@`  @@a  @a @` ` ` ```@@` @@a 0000@@@@€?QATAQAQUEUQUQDQTTUUUUUEDQQQQQDAUEUUEUUUUDUUEUUETQUUQUUUUEEQDDTUUUEUUUUUUUUUUUUEDUUEEQQUUUUUUUQAUUUUETUUUUUUUUUUUUUUUUUUUUEUQUUUUUUUUUEAAUUTAQUUUUUUUUUUUUUUUUUUUUUUUETTUUTUUEDTUUUUUUUUAUEUETUUUQUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUDTUUUUEDUUAQUTAQQUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUQTUUUUUUUUUUTEUEQTEQUEEUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUQUUUUUUUUUUUUTEUEUUUEEUUETUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUQQUUUUUUUUUUUUUUUUUUUUEUTUUUTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEUUUUUUUUUUUUUUUUUUUUUUDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUQTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUDTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUQDTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUQQUUUUUUeefVUfVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUeUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTUUeUVUfxxhUUUUUUUUUUUUUUUUUUUUUUUUUUUUUhUUUUUUUUUUUUUUUUUUUUUUUUUUUUTUUUeUewwxwwwhfUUUUUUUUUUUUUUUUUUUUUUUUeUexwUUfeeUUUUUUUUUUUUUUUUUUUUUUUETUexwwwwwwwwhUUUUUUUUUUUUUUUUUeeUefVxwwhXfUUUUUUUUUUUUUUUUUUUUUUUEUwxwwwwwwwwwwfVUUUUUUUfeVeehVeeVxxwwfUVUUUUeUUUUUUUUUUUUUUUfUexwwwwwwwwwwwwwwwwhVUVUUUeXxxwwwwwxeXeUUeheUVUUUUUUUUUUUUaFVxwwxwwwwwwwwwwwwwwwwXXUUUwwwxwwwwwwwwxUVhVVUUUUUUUUUUUUaahwwwxwwwwwwwwwwwwwwwwwwwxhUexwwxwwwxwwwwwwwwwwwxXwhhUUUUUUVUeUUUwwwxwwwwwwwwwwwwwwwwwwwwwfxwwxwxwwwwwwwwwwwwwwwwwwwxwwwVUUeVUVUffUwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwxwxwwwwwwwwwwwwwwwwwwwwxwwwefehfhwwwwwwwwwwwwwwwwwwwwwwwwwwwxwwwwwxwwwwwwwwwwwwwwwwwwwwwwwwwwwwxxxwwwqwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwxwwxwwwqwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwqwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwqwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwt-- script: lua -- title: Blossom -- author: luxille_, emerald8 -------- GLOBAL STORAGE -------- -- global state variables g = { initialized = false, genStep = 0, tick = 0, leftWasDown = false, --true if left mouse was down previous frame mode = "title", -- can be: "title", "pot", "game" fading = 0, music = "none", potX = 136, potY = 120 - 32, gameState = "decide", -- decide, plant, action, type, die, grow, admire validDrawLedge = 0, -- all draws at 0 growHeight = 0, admiring = 0, -- 0 means done (show back button) retrying = false, donePlanting = 0, tries = 0, sequentialTries = 0 } -- text displaying variables t = { text = "", target = "" } -- background graphical pixel values pixels = {} -- world generation details world = { lastGrassX = 0 } -- buttons buttons = {} -------- WORLD GENERATION -------- function generate() if g.genStep == 0 then genSky() elseif g.genStep == 1 then genGrass() elseif g.genStep == 2 then genTufts() elseif g.genStep == 3 then genDirt() end g.genStep = g.genStep + 1 end function genSky() for x=0, 240, 1 do for y=0, 136, 1 do pixels[x][y] = 1 end end end function genGrass() lastX = 48 + math.floor(36 * math.random()) -- current spot x = 240 y = 126 wasUp = true prevY = 136 while x > lastX do -- move the coords r = math.random() if r < 0.3 then y = y - 1 elseif r < 0.56 then y = y + 1 end -- assign the height if x == g.potX then g.potY = y - 4 - 30 end -- cap the y and bounce the direction if y > 126 then y = 126 elseif y < 116 then y = 116 end x = x - 1 -- assign the pixel value pixels[x][y] = 5 -- calculate the height h1 = 3 * math.log((x - lastX) / 3) h2 = (x - 100) / 16 h3 = 1.2 * math.sin(x / 5) h = math.floor(4 + h1 + h2 + h3) if (y - h < prevY) and math.random() < 0.3 then h = h + 1 end for i = 1, h - 1, 1 do pixels[x][y - i] = 5 prevY = y - i end end -- make the dirt dirtX = lastX + math.floor(2 + 3 * math.random()) dirtY = 0 for i = dirtX, 239, 1 do y = 136 while true do if pixels[i][y] == 5 then if dirtY == 0 then dirtY = y end for j = y + 1, 136, 1 do pixels[i][j] = 7 end break end y = y - 1 end end -- cut off the edge of the dirt x = dirtX y = dirtY cut = math.floor(2 + 2 * math.random()) edge = math.floor(3 + 2 * math.random()) while y < 136 do -- step down y = y + 1 -- update cut if cut > 0 then x = x + 1 cut = cut - 1 elseif cut > -2 then cut = cut - 1 elseif math.random() < 0.3 then cut = math.floor(2 + 2 * math.random()) x = x + 1 end -- update edge if edge > 0 then pixels[x + 1][y] = 8 edge = edge - 1 elseif edge > -1 then edge = edge - 1 elseif math.random() < 0.4 then edge = math.floor(3 + 2 * math.random()) end -- clear the pixels pixels[x][y] = 1 for i = x, dirtX, -1 do pixels[i][y] = 1 end end world.lastGrassX = lastX end function genTufts() -- lighten the top of the grass for x = world.lastGrassX + 4, 240, 1 do for y = 60, 136, 1 do if pixels[x][y] == 5 then r = math.random() if r < 0.22 then pixels[x][y] = 4 elseif r < 0.3 then pixels[x][y] = 4 pixels[x][y - 1] = 4 end if math.random() < 0.2 then d = math.floor(1 + 1.6 * math.random()) pixels[x][y + d] = 4 if math.random() < 0.2 then pixels[x + 1][y + d] = 4 end end break end end end -- darken the bottom of the grass for x = world.lastGrassX, 240, 1 do for y = 136, 0, -1 do if pixels[x][y] == 5 then r = math.random() if r < 0.6 then pixels[x][y] = 6 end if math.random() < 0.15 then d = math.floor(1.4 * math.random()) pixels[x][y - d] = 6 if math.random() < 0.2 then pixels[x + 1][y - d] = 6 end end break end end end -- add some darker sections in the middle end function genDirt() pillar = 0 stalag = 0 for x = 0, 240, 1 do for y = 0, 136, 1 do if pixels[x][y] == 7 then -- darken the first pixel pixels[x][y] = 8 -- potentially darken the second pixel r = math.random() if r < 0.35 then pixels[x][y + 1] = 8 end -- draw the pillar r = math.random() if pillar == 1 or pillar == 3 then -- generate the pillar r = math.floor(1 + 2 * math.random()) for i = 0, r, 1 do pixels[x][y + i] = 8 end -- stallagtite if stallag == pillar then p = r + 3 + math.floor(3 * math.random()) l = 1 + math.floor(2 * math.random()) for i = p, p + l, 1 do pixels[x][y + i] = 8 end end -- increment if pillar == 1 then pillar = 2 elseif pillar == 3 then pillar = 0 end elseif pillar == 2 then --generate the pillar r = math.floor(3 + 2 * math.random()) for i = 0, r, 1 do pixels[x][y + i] = 8 end -- stallagtite if stallag == pillar then p = r + 2 + math.floor(3 * math.random()) l = 1 + math.floor(2 * math.random()) for i = p, p + l, 1 do pixels[x][y + i] = 8 end end -- increment pillar = pillar + 1 elseif r < 0.2 then pillar = 1 r2 = math.random() if r2 < 0.05 then stallag = 1 elseif r2 < 0.1 then stallag = 3 elseif r2 < 0.2 then stallag = 2 else r2 = 0 end else pillar = 0 stallag = 0 end break end end end end -------- MAIN GAME LOOP -------- function TIC() -- initialize values if not g.initialized then initialize() g.initialized = true end -- listening eventListen() -- music updateMusic() -- main game loop if g.mode == "game" then gameLoop() end -- draw and game tick draw() g.tick = g.tick + 1 end function initialize() -- initialize pixel values (graphical and visual) for i=0, 240, 1 do pixels[i] = {} for j=0, 136, 1 do pixels[i][j] = 0 end end -- generate the intial background for i=0, 8, 1 do generate() end -- initialize the game buttons for i=0, 3, 1 do buttons[i] = {} if i < 2 then buttons[i].x = 4 else buttons[i].x = 28 end if i % 2 == 0 then buttons[i].y = 136 - 20 else buttons[i].y = 136 - 44 end buttons[i].sprite = 2 * i if i == 0 then buttons[i].name = "W" --water elseif i == 1 then buttons[i].name = "T" --trim elseif i == 2 then buttons[i].name = "F" --fertilize elseif i == 3 then buttons[i].name = "M" end --move end -- initialize the pot buttons for i=4, 6, 1 do buttons[i] = {} buttons[i].x = 48 + 64 * (i - 4) buttons[i].y = 58 buttons[i].sprite = 448 + 4 * (i - 4) if i == 4 then buttons[i].name = "green" elseif i == 5 then buttons[i].name = "blue" elseif i == 6 then buttons[i].name = "pink" end end -- initialize the land selection buttons for i=7, 8, 1 do buttons[i] = {} buttons[i].x = 64 + 96 * (i-7) buttons[i].y = 48 buttons[i].sprite = 0 end -- initialize the plant a seed button buttons[9] = {} buttons[9].x = g.potX - 8 + 16 buttons[9].y = 64 buttons[9].sprite = 416 -- initialize the return to title button buttons[10] = {} buttons[10].x = 4 buttons[10].y = 124 buttons[10].sprite = 0 end function eventListen() -- check for mouse clicks on buttons x, y, left, middle, right, scrollx, scrolly = mouse() if left then if not g.leftWasDown then if g.mode == "game" then if g.gameState == "action" then for i = 0, 3, 1 do b = buttons[i] if x >= b.x and y >= b.y and x <= b.x+16 and y <= b.y+16 then actionButtonClicked(b.name) end end elseif g.gameState == "decide" then for i = 7, 8, 1 do b = buttons[i] if x >= b.x and y >= b.y and x <= b.x + 17 and y <= b.y + 12 then landSelectionButtonClicked(i == 7) end end elseif g.gameState == "plant" then if g.donePlanting == 0 then for i = 9, 9, 1 do b = buttons[i] if x >= b.x and y >= b.y and x <= b.x+16 and y <= b.y+16 then plantButtonClicked() end end else changeText(narrativeFlavor.saplingPlanted.iter1.screen2) g.gameState = "type" end elseif g.gameState == "admire" then if g.admiring == 0 and t.target == "" then for i = 10, 10, 1 do b = buttons[i] if x >= b.x and y >= b.y and x <= b.x+16 and y <= b.y+16 then returnToTitleButtonClicked() end end elseif t.target == "" then nextStepAdmire() end elseif g.gameState == "remorse" then if g.admiring > 1 and t.target == "" then nextStepRemorse() elseif g.admiring == 1 then for i = 7, 8, 1 do b = buttons[i] if x >= b.x and y >= b.y and x <= b.x + 17 and y <= b.y + 12 then retryButtonClicked(i == 7) end end elseif g.admiring == 0 and g.fading > 180 then g.fading = 0 g.potX = 136 g.donePlanting = 0 changeText("") state.list = {} state.numActions = 0 state.size = 0 state.inPot = true state.isAlive = true tree.dies = false tree.grows = false tree.describe = "" if g.retrying then g.mode = "game" g.gameState = "decide" else g.mode = "title" end end end elseif g.mode == "title" and g.fading == 0 then g.fading = 1 elseif g.mode == "pot" and g.fading == 0 then for i = 4, 6, 1 do b = buttons[i] if x >= b.x and y >= b.y and x <= b.x+32 and y <= b.y+32 then potButtonClicked(b.name) end end end end g.leftWasDown = true else g.leftWasDown = false end end function loopFading() for x = 0, 240, 1 do for j = 0, math.min(g.fading, 136), 1 do if g.mode == "title" then pix(x, 136 - j, 0) elseif g.mode == "pot" then pix(x, j, 0) elseif g.mode == "game" then if g.gameState == "remorse" then pix(x, j, 0) end end end end g.fading = g.fading + 3 if g.mode == "title" and g.fading > 180 then g.mode = "pot" g.fading = 0 elseif g.mode == "pot" and g.fading > 180 then g.mode = "game" g.validDrawLedge = 240 g.fading = 0 end end function gameLoop() if g.validDrawLedge > 0 then g.validDrawLedge = g.validDrawLedge - 2 if g.validDrawLedge < 48 then g.validDrawLedge = 0 end elseif g.gameState == "decide" then if t.target == "" and t.text == "" then changeText("Would you like to grow your tree here?") end elseif g.gameState == "type" then if t.target == "" then if tree.grows then g.gameState = "grow" elseif tree.dies then g.gameState = "die" changeText("") state.isAlive = false else g.gameState = "action" end end elseif g.gameState == "grow" then if g.tick % 2 == 0 then g.growHeight = g.growHeight + 1 end if g.growHeight >= 80 then state.size = state.size + 1 if state.size == 6 then g.gameState = "admire" if g.tries == 0 then g.admiring = 0 else g.admiring = 4 end changeText(narrativeFlavor.admire.screen1) else g.gameState = "action" end end elseif g.gameState == "die" then if g.tick % 2 == 0 then g.growHeight = g.growHeight + 1 end if g.growHeight >= 80 then state.size = state.size + 1 g.gameState = "remorse" g.admiring = 4 end elseif g.gameState == "remorse" then if g.admiring == 4 then g.admiring = 3 changeText(narrativeFlavor.fail.screen1) elseif g.fading > 0 then if g.fading > 136 and g.fading < 140 then if g.retrying then changeText(narrativeFlavor.fail.yesScreen) else changeText(narrativeFlavor.fail.noScreen) end end end elseif g.gameState == "admire" then end end -------- DRAW METHODS -------- function draw() --clear cls() --write pixels for i = 0, 240, 1 do for j = 0, 136, 1 do if not (pixels[i][j] == 0) then v = pixels[i][j] -- grass and dirt if v >= 4 and v <= 8 then if i > g.validDrawLedge then pix(i, j, v) else pix(i, j, 1) end else pix(i, j, v) end end end end --specific drawing if g.mode == "title" then drawTitleStage() elseif g.mode == "pot" then drawPotStage() elseif g.mode == "game" then drawGameStage() end if g.fading > 0 then loopFading() end if g.mode == "game" and g.gameState == "remorse" and g.fading > 130 then drawGameStage() end end function drawTitleStage() --draw title titleX = 34 titleY = 30 for i = 0, 11, 1 do for j = 0, 3, 1 do spr(256 + i + (16 * j), titleX + 8 * i, titleY + 8 * j, 0) end end --draw subtitle print("A TINY GAME ABOUT TREES,", titleX - 16, 60, 14, nil, 1, nil) print("GROWTH, AND DETERMINATION", titleX - 22, 70, 14, nil, 1, nil) end function drawPotStage() print(narrativeFlavor.pot, 25, 17, 14, nil, 1, nil) --draw buttons for i = 4, 6, 1 do b = buttons[i] spr(b.sprite, b.x, b.y, 0, 1, 0, 0, 4, 4) for x = b.x - 3, b.x + 34, 1 do for y = b.y - 3, b.y + 34, 1 do if x < b.x-1 or x > b.x + 32 or y < b.y-1 or y > b.y + 32 then pix(x, y, 4) end end end end end function drawGameStage() if g.gameState == "decide" then if t.text == "Would you like to grow your tree here?" then for i = 7, 8, 1 do b = buttons[i] if i == 7 then print("YES", b.x + 1, b.y + 4, 14) else print("NO", b.x + 3, b.y + 4, 14) end for x = b.x - 2, b.x + 19, 1 do for y = b.y - 2, b.y + 14, 1 do if x < b.x or x > b.x + 17 or y < b.y or y > b.y + 12 then pix(x, y, 4) end end end end end elseif g.gameState == "plant" then -- draw plant button if g.donePlanting == 0 then b = buttons[9] spr(b.sprite, b.x, b.y, 0, 1, 0, 0, 2, 2) for x = b.x - 2, b.x + 18, 1 do for y = b.y - 2, b.y + 18, 1 do if x < b.x or x > b.x + 16 or y < b.y or y > b.y + 16 then pix(x, y, 4) end end end spr(state.potSprId, g.potX, g.potY, 0, 1, 0, 0, 4, 4) elseif g.donePlanting == 1 then drawTreeAndPot() end elseif g.gameState == "action" or g.gameState == "type" then --draw buttons if g.gameState == "action" then for i = 0, 3, 1 do b = buttons[i] spr(b.sprite, b.x, b.y, 0, 1, 0, 0, 2, 2) for x = b.x - 2, b.x + 18, 1 do for y = b.y - 2, b.y + 18, 1 do if x < b.x or x > b.x + 16 or y < b.y or y > b.y + 16 then pix(x, y, 4) end end end end end drawTreeAndPot() elseif g.gameState == "grow" then --draw pot if state.inPot then spr(state.potSprId, g.potX, g.potY, 0, 1, 0, 0, 4, 4) end --draw old tree if state.pot == "pink" then drawChangingTree(g.potX + 16, g.potY + 10, g.growHeight - 1, 80, state.size, true) elseif state.pot == "blue" then drawChangingTree(g.potX + 16, g.potY + 13, g.growHeight - 1, 80, state.size, true) elseif state.pot == "green" then drawChangingTree(g.potX + 16, g.potY + 13, g.growHeight - 1, 80, state.size, true) end --draw new tree if state.pot == "pink" then drawChangingTree(g.potX + 16, g.potY + 10, 0, g.growHeight, state.size + 1, true) elseif state.pot == "blue" then drawChangingTree(g.potX + 16, g.potY + 13, 0, g.growHeight, state.size + 1, true) elseif state.pot == "green" then drawChangingTree(g.potX + 16, g.potY + 13, 0, g.growHeight, state.size + 1, true) end elseif g.gameState == "die" then --draw pot if state.inPot then spr(state.potSprId, g.potX, g.potY, 0, 1, 0, 0, 4, 4) end --draw alive tree if state.pot == "pink" then drawChangingTree(g.potX + 16, g.potY + 10, -1, 79 - g.growHeight, state.size, true) elseif state.pot == "blue" then drawChangingTree(g.potX + 16, g.potY + 13, -1, 79 - g.growHeight, state.size, true) elseif state.pot == "green" then drawChangingTree(g.potX + 16, g.potY + 13, -1, 79 - g.growHeight, state.size, true) end --draw dead tree if state.pot == "pink" then drawChangingTree(g.potX + 16, g.potY + 10, 80 - g.growHeight, 80, state.size, false) elseif state.pot == "blue" then drawChangingTree(g.potX + 16, g.potY + 13, 80 - g.growHeight, 80, state.size, false) elseif state.pot == "green" then drawChangingTree(g.potX + 16, g.potY + 13, 80 - g.growHeight, 80, state.size, false) end elseif g.gameState == "admire" then --draw back button if g.admiring == 0 and t.target == "" then b = buttons[10] for x = b.x - 2, b.x + 8, 1 do for y = b.y - 2, b.y + 8, 1 do if x < b.x or x > b.x + 6 or y < b.y or y > b.y + 6 then print("<", b.x + 1, b.y + 1, 14) pix(x, y, 4) end end end end drawTreeAndPot() elseif g.gameState == "remorse" then if g.fading < 130 then drawTreeAndPot() end if g.admiring == 1 and t.target == "" then --draw buttons for i = 7, 8, 1 do b = buttons[i] if i == 7 then print("YES", b.x + 1, b.y + 4, 14) else print("NO", b.x + 3, b.y + 4, 14) end for x = b.x - 2, b.x + 19, 1 do for y = b.y - 2, b.y + 14, 1 do if x < b.x or x > b.x + 17 or y < b.y or y > b.y + 12 then pix(x, y, 4) end end end end --draw branch spr(32, 112, 32, 0, 1, 0, 0, 2, 2) end end --draw message drawText() end function drawTree(baseX, baseY) if state.isAlive then if state.size == 1 then spr(416, baseX - 7, baseY - 16, 0, 1, 0, 0, 2, 2) elseif state.size == 2 then spr(403, baseX - 7, baseY - 24, 0, 1, 0, 0, 2, 3) elseif state.size == 3 then spr(320, baseX - 16, baseY - 30, 0, 1, 0, 0, 4, 4) elseif state.size == 4 then spr(10, baseX - 24, baseY - 46, 0, 1, 0, 0, 6, 6) elseif state.size == 5 then spr(324, baseX - 48, baseY - 56, 0, 1, 0, 0, 4, 5) spr(328, baseX - 16, baseY - 56, 0, 1, 0, 0, 8, 7) elseif state.size == 6 then spr(116, baseX - 48, baseY - 72, 0, 1, 0, 0, 12, 9) end else if state.size < 4 then spr(144, baseX - 19, baseY - 20, 0, 1, 0, 0, 3, 3) else spr(192, baseX - 17, baseY - 28, 0, 1, 0, 0, 4, 4) end end end function drawTreeAndPot() --draw pot if state.inPot then spr(state.potSprId, g.potX, g.potY, 0, 1, 0, 0, 4, 4) end --draw tree if state.pot == "pink" then drawTree(g.potX + 16, g.potY + 10, state.isAlive) elseif state.pot == "blue" then drawTree(g.potX + 16, g.potY + 15, state.isAlive) elseif state.pot == "green" then drawTree(g.potX + 16, g.potY + 13, state.isAlive) end end -- from at 0 is base of tree function drawChangingTree(baseX, baseY, from, to, size, alive) -- initialize values sprite = 0 wid = 0 hei = 0 xOffset = 0 yOffset = 0 xOffsetSecond = 0 --only used in certain cases widSecond = 0 --only used in certain cases heiSecond = 0 --only used in certain cases spriteSecond = 0 --only used in certain cases -- pick values if alive then if size == 1 then sprite = 416 wid = 2 hei = 2 xOffset = -7 yOffset = -1 elseif size == 2 then sprite = 403 wid = 2 hei = 3 xOffset = -7 yOffset = -1 elseif size == 3 then sprite = 320 wid = 4 hei = 4 xOffset = -16 yOffset = 1 elseif size == 4 then sprite = 10 wid = 6 hei = 6 xOffset = -24 yOffset = 1 elseif size == 5 then sprite = 328 wid = 8 hei = 7 xOffset = -16 yOffset = -1 spriteSecond = 324 widSecond = 4 heiSecond = 5 xOffsetSecond = -48 elseif size == 6 then sprite = 116 wid = 12 hei = 9 yOffset = -1 xOffset = -48 end else if size < 4 then sprite = 144 wid = 3 hei = 3 xOffset = -19 yOffset = 3 else sprite = 192 wid = 4 hei = 4 xOffset = -17 yOffset = 3 end end -- loop through rows for h = from, math.min(8 * hei - 1, to), 1 do for x = 0, 8 * wid - 1, 1 do inSprite = (sprite + 16 * (hei - 1)) + x // 8 - 16 * (h // 8) val = peek4(2 * 0x4000 + 64 * inSprite + (x % 8) + 8 * (7 - (h % 8))) if not (val == 0) then pix(baseX + x + xOffset, baseY - h + yOffset, val) end end end if spriteSecond > 0 then for h = math.max(from + 1, 8 * (hei - heiSecond)), math.min(8 * hei - 1, to), 1 do hEff = h - (8 * (hei - heiSecond)) - 1 for x = 0, 8 * widSecond - 1, 1 do inSprite = (spriteSecond + 16 * (heiSecond - 1)) + x // 8 - 16 * (hEff // 8) val = peek4(2 * 0x4000 + 64 * inSprite + (x % 8) + 8 * (7 - (hEff % 8))) if not (val == 0) then pix(baseX + x + xOffsetSecond, baseY - h, val) end end end end end -------- TEXT DISPLAYING -------- -- called every frame function drawText() print(t.text, 12, 10, 14) if g.tick % 2 == 0 and string.len(t.target) > 0 then t.text = t.text .. string.sub(t.target, 1, 1) t.target = string.sub(t.target, 2, -1) end end -- called when you want to change what text is being displayed function changeText(target) t.text = "" t.target = target end -------- EVENT HANDLING -------- -- names are: "W", "T", "F", "M" function actionButtonClicked(name) -- evolve the tree evolveTree(name) -- respond to evolution changeText(tree.describe) if tree.dies then g.gameState = "type" g.growHeight = 0 elseif tree.grows then g.gameState = "type" g.growHeight = 0 else g.gameState = "type" end end function potButtonClicked(name) g.fading = 1 state.pot = name g.gameState = "decide" if state.pot == "green" then state.potSprId = 448 elseif state.pot == "blue" then state.potSprId = 452 elseif state.pot == "pink" then state.potSprId = 456 end end function landSelectionButtonClicked(bool) if bool then g.gameState = "plant" g.donePlanting = 0 changeText("") else -- reset pixel values for i=0, 240, 1 do pixels[i] = {} for j=0, 136, 1 do pixels[i][j] = 0 end end -- regenerate the background g.genStep = 0 for i=0, 8, 1 do generate() end changeText("") g.validDrawLedge = 240 end end function plantButtonClicked() state.size = 1 if g.tries > 0 then g.gameState = "type" if g.tries == 1 then changeText(narrativeFlavor.saplingPlanted.iter2) else changeText(narrativeFlavor.saplingPlanted.iter3) end else changeText(narrativeFlavor.saplingPlanted.iter1.screen1) g.donePlanting = 1 end end function returnToTitleButtonClicked() g.mode = "title" g.fading = 0 g.potX = 136 changeText("") state.list = {} state.numActions = 0 state.size = 0 state.inPot = true state.isAlive = true tree.dies = false tree.grows = false tree.describe = "" end function retryButtonClicked(bool) g.admiring = 0 g.retrying = bool g.fading = 1 changeText("") g.tries = g.tries + 1 g.sequentialTries = g.sequentialTries + 1 if not bool then g.sequentialTries = 0 end end function nextStepRemorse() g.admiring = g.admiring - 1 if g.admiring == 2 then changeText(narrativeFlavor.fail.screen2) elseif g.admiring == 1 then changeText(narrativeFlavor.fail.screen3) end end function nextStepAdmire() if g.admiring == 4 then changeText(narrativeFlavor.admire.screen2) elseif g.admiring == 3 then changeText(narrativeFlavor.admire.screen3) elseif g.admiring == 2 then changeText(narrativeFlavor.admire.screen4) elseif g.admiring == 1 then changeText(narrativeFlavor.admire.screen5) end g.admiring = g.admiring - 1 end -------- GROWTH AND NARRATIVE LOGIC -------- tree = { dies = false, -- true if the plant should die grows = false, -- true if the plant should grow to the next stage describe = "" -- the text to be displayed for this narrative } state = { list = {}, -- list of actions the player has made numActions = 0, -- number of actions the player has made (updated externally) size = 1, -- 1 through 6 (updated externally) inPot = true, -- (updated externally) pot = "green", potSprId = 448, isAlive = true } growthFlavor = { water = {str1 = 'Not too much!', str2 = "It's important to stay hydrated.", str3 = 'The source of life.'}, trim = {str1 = 'A little touch-up.', str2 = 'Just a trim.', str3 = 'Removing the old is as important as\ncultivating the new.'}, fertilize = {str1 = 'Sometimes we need a little bit more\nsupport.', str2 = 'She needs her nutrients too!', str3 = 'For you, little Bonsai.'}, move = {str1 = "You can't always grow in the\nsame spot.", str2 = 'Environment makes a difference!', str3 = "Maybe there's a better place\nto grow."} } narrativeFlavor = { pot = "A tree is a tree; a pot is only a pot.\n It does not become a Bonsai until\n the two are combined and form\n a harmony together.", saplingPlanted = { iter1 = { screen1 = "You have planted your first sapling!\n\nRemember, this is just the first step\non this journey. Growth is\nall about persistence.", screen2 = "A tree is a delicate thing.\nLike you, in some way or another.\nIt needs water, fertilizer,\nfrequent trimming,\nand careful positioning.\nIt begs for constant care and balance.\nAnd it can get temperamental\nwhen the environment gets harsh.\n\nDespite that, it always\nhas the capability to grow." }, iter2 = "This cutting came from a dying tree.\nIt is a memento of failure.\nBut like a freshly grown sapling,\nit yearns for new life.\nYou choose persistence.\nThat, in itself,\nis the most arduous task.", iter3 = "What is it that motivates you to persist?\nThis thing is fragile and unpredictable.\nIt shrivels up when you least expect it.\nIt falls apart despite your best efforts.\n\nStill, you find it deserving of your love.\nPerhaps that is enough." }, fail = { screen1 = "You did your best, but...", screen2 = "In the end, it died anyway.\nSometimes these things\nare out of your control.", screen3 = "It looks like a healthy branch survived.\n Retrieve a cutting and try again?", yesScreen = "Whatever happens, spring will return again.\n And this time, life will blossom.", noScreen = "Maybe she blossoms in another life.\nFor now, you are content\njust to watch the mountains.", }, admire = { screen1 = "You watch her petals sway\nin the breeze. To think all this\ncame from a little\nsapling.\n\nAnd a lot\nof hard work.", screen2 = "Perhaps the tree does not care about\nbloom or failure. She cares about\nblooming now\nor blooming later.\n\nIt does not matter\nhow slowly you go\nso long as you\ndo not stop.", screen3 = "In death there is new life.\nIn her petals are the fragrance\nof every past life.\nThe air now is only\nsweeter for it.", screen4 = "It feels like a lifetime ago you embarked\non this journey. You think\nyou have changed just\nas much as she has.\nYou washed, fed,\nclothed yourself.\nYou greeted the\nsun as it rose.\nYou climbed\nthe mountain.\nYou did not stop\nwhen you fell.", screen5 = "Today you blossom too.\nWhat a miraculous thing." } } -- called every time the player takes an action, update "tree" map -- uses "state" to determine the consequences of an action function evolveTree(name) --initialize to nothing tree.grows = false tree.dies = false -- add to the list of actions state.list[state.numActions] = name state.numActions = state.numActions + 1 --consider growing or dying if state.numActions % 3 == 0 then if state.size == 1 then tree.grows = true elseif state.size == 2 then if not (state.list[0] == state.list[1]) and not (state.list[1] == state.list[2]) and not (state.list[0] == state.list[2]) then tree.grows = true else tree.dies = true end elseif state.size == 3 then fertilize = countInstances(state.list, 3, "F") trim = countInstances(state.list, 3, "T") if fertilize >= 0 and trim == 0 then tree.grows = true else tree.dies = true end elseif state.size == 4 then water = countInstances(state.list, 3, "W") trim = countInstances(state.list, 3, "T") move = countInstances(state.list, 3, "M") if water == 2 and (trim > 0 or move > 0) then tree.grows = true else tree.dies = true end elseif state.size == 5 then water = countInstances(state.list, 3, "W") trim = countInstances(state.list, 3, "T") move = countInstances(state.list, 3, "M") if water > 0 and trim > 0 and move > 0 then tree.grows = true else tree.dies = true end end state.numActions = 0 state.list = {} end --visual reactions to the plant if name == "M" then if g.potX < 148 then g.potX = 150 + math.floor(6 * math.random()) else g.potX = 136 + math.floor(6 * math.random()) end end --select type growthTable = {} if name == "W" then growthTable = growthFlavor.water elseif name == "T" then growthTable = growthFlavor.trim elseif name == "F" then growthTable = growthFlavor.fertilize else growthTable = growthFlavor.move end --choose randomly r = math.floor(3 * math.random()) if r == 0 then tree.describe = growthTable.str1 elseif r == 1 then tree.describe = growthTable.str2 else tree.describe = growthTable.str3 end end -------- MUSIC -------- function updateMusic() if g.mode == "title" then if not (g.music == "title") then g.music = "title" playMusic(g.music) end elseif g.mode == "pot" then if not (g.music == "pot") then g.music = "pot" playMusic(g.music) end elseif g.mode == "game" then if g.gameState == "die" or g.gameState == "remorse" then if not (g.music == "remorse") then g.music = "remorse" playMusic(g.music) end elseif g.gameState == "admire" then if not (g.music == "admire") then g.music = "admire" playMusic(g.music) end else if not (g.music == "game") then g.music = "game" playMusic(g.music) end end end end function playMusic(scene) music() if (scene == "title") then music(01,00,00,true) end if (scene == "pot") then music(01,00,00,true) end if (scene == "game") then music(00,00,00,true) end if (scene == "remorse") then music(01,00,00,true) end if (scene == "admire") then music(02,00,00,true) end end -------- UTILITY -------- function sget(s, sx, sy) return peek4(2 * (0x04000) + 64 * s + 8 * sy + sx) -- get sprite pixel end function countInstances(list, length, value) count = 0 for i = 0, length-1, 1 do if list[i] == value then count = count + 1 end end return count end