picotron cartridge // www.picotron.net version 2 :: gfx/ :: map/ :: sfx/ :: art.lua --[[pod_format="raw",created="2024-03-31 01:52:08",modified="2024-04-29 15:31:52",revision=710]] function bob(s, x, y, w, h, t) sspr(s, 0, 0, w, h, x+t/2, y-t/2, w-t, h+t) end function ragged_box(x1, y1, x2, y2) ragged_box_color(x1, y1, x2, y2, 15) end function ragged_box_color(x1, y1, x2, y2, bgcolor) rectfill(x1+1, y1+1, x2, y2, bgcolor) sspr(004, 0,0, 8,2, x1+1, y1, x2-x1, 2) sspr(004, 0,0, 8,2, x1+1, y2, x2-x1, 2) sspr(004, 0,0, 2,4, x1, y1, 2, y2-y1) sspr(004, 0,0, 2,4, x2, y1+2, 2, y2-y1) end function easeTrig(t) if t<0 then return 0 end if t>1 then return 1 end return 0.5-0.5*cos(t/2) end function easeAccelerate(t) if t<0 then return 0 end if t>1 then return 1 end return t*t end function easeDecelerate(t) if t<0 then return 0 end if t>1 then return 1 end return 1-(1-t)*(1-t) end function easeSine(t) if t<0 then return 0 end if t>1 then return 1 end return sin(t/4) end -- add newlines to a string to fit it into lines. function wrap(str, line_length) -- thanks to https://stackoverflow.com/questions/17586/best-word-wrap-algorithm, i did not feel like thinking this out myself local words = split(str, " ", false) local output = "" local c = 0 for w in all(words) do while sub(w, 1, 1) == "\n" do output = output .. "\n" c = 0 w = sub(w, 2) end if c + print(w,0,-10) > line_length then if c > 0 then output = output .. "\n" c = 0 end end output = output .. w .. " " c += print(w,0,-10) + print(" ", 0, -10) end return output end function collides(position, object) add(collider_renders, object) return position.x < object.right and position.x > object.left and position.y > object.top and position.y < object.bottom end :: cabinet.lua --[[pod_format="raw",created="2024-04-03 19:46:51",modified="2024-04-23 02:36:18",revision=694]] Cabinet = {} function Cabinet:new(x, y, gaps) local c = { x=40, y=10, drawers = {}, shelves = {}, hover_plant = nil, height = 4*(gaps+16) } -- populate the big drawers local xoff = x for i=0,0 do for j=0,1 do add(c.drawers, Drawer:new(xoff + gaps + i*(gaps+32), y + gaps + j*(gaps+32), 009, 32)) end end xoff += gaps + (gaps + 32) -- populate ssmall drawers for i=0,3 do for j=0,3 do add(c.drawers, Drawer:new(xoff + gaps + i*(gaps+16), y + gaps + j*(gaps+16), 008, 16)) end end xoff += gaps + 4*(gaps+16) local s = Shelf:new(xoff+gaps, y + gaps, 76, 32) add(s.plants, {13, 4}) add(s.plants, {14, 14}) add(c.shelves, s) local s = Shelf:new(xoff+gaps, y + 3*gaps + 32, 76, 32) add(s.plants, {15, 10}) add(c.shelves, s) setmetatable(c, self) self.__index = self return c end function Cabinet:draw() -- cabinet! rectfill(self.x, self.y, 230, self.y + self.height, 2) -- drawers for a in all(self.drawers) do a:draw() end -- plant shelves for s in all(self.shelves) do s:draw(self.hover_plant) end end function Cabinet:update(x,y) for d in all(self.drawers) do if d:contains(x,y) then d.offset = 4 else d.offset = 0 end end local closest_distance = 1000 local closest_plant = nil for s in all(self.shelves) do for p in all(s.plants) do local dist = abs(p[2] + s.x - x+16) + abs(s.y + 24 - y) if dist < closest_distance then closest_distance = dist closest_plant = p end end end if closest_distance < 32 then self.hover_plant = closest_plant else self.hover_plant = nil end end function Cabinet:drawer_at(x, y) for d in all(self.drawers) do if d:contains(x,y) then return d end end return nil end Drawer = {} function Drawer:new(x, y, sprite, size) local c = {x=x, y=y, sprite=sprite, size=size, offset=0} setmetatable(c, self) self.__index = self return c end function Drawer:draw() rectfill(self.x+2, self.y+2, self.x+self.size-3, self.y+self.size-3, 0) spr(self.sprite, self.x, self.y+self.offset) end function Drawer:contains(x, y) return x >= self.x and x <= self.x + self.size and y >= self.y and y <= self.y + self.size end Shelf = {} function Shelf:new(x, y, width, height) local c = {x=x, y=y, width=width, height=height, plants={}} setmetatable(c, self) self.__index = self return c end function Shelf:draw(highlighted) rectfill(self.x, self.y, self.x + self.width, self.y + self.height, 0) for p in all(self.plants) do if highlighted ~= p then palt(0, true) palt(10, true) end spr(p[1], self.x+p[2], self.y + self.height - 32+2) palt(10, false) palt(0, true) end end :: conversation.lua --[[pod_format="raw",created="2024-04-03 02:38:22",modified="2024-04-10 14:42:28",revision=642]] default_script = { {"welcome to Atelier Hester!", talk_sprite} } Conversation = {} function Conversation:new(script, final) local c = {script=script or default_script, final=final or function() end, index=1} setmetatable(c, self) self.__index = self return c end function Conversation:before() self.behind = scene self.before = function() end -- only ddo othis the firstt time this scene is played end function Conversation:update() local now = self.script[self.index] if now.during ~= nil then now.during() end if btnp(4) or btnp(5) then if now.after ~= nil then now.after() end if self.index < #self.script then self.index += 1 else --self:after() end end end function Conversation:draw() self.behind:draw() ragged_box(30, 100, 240-30, 130) color(0) print(self.script[self.index][1], 34, 104) end function Conversation:after() self.final() --change_scene(self.behind) end :: fairy.lua --[[pod_format="raw",created="2024-04-03 17:32:32",modified="2024-04-23 03:08:39",revision=432]] Fairy = { velocity = 1, accel_frames = 20, min_velocity = 0, max_velocity = 3, f = false } function Fairy:new(ff) local f = ff or {x=120, y=68} setmetatable(f, self) self.__index = self return f end function Fairy:draw() if flr(10*t()) % 2 == 0 then spr(5, self.x-8, self.y-8, self.f) else spr(6, self.x-8, self.y-8, self.f) end end function Fairy:update() if self.velocity < self.max_velocity then self.velocity += (self.max_velocity - self.min_velocity) / self.accel_frames end if btn(0) and self.x > 0 then self.x -= self.velocity end if btn(1) and self.x < 240 then self.x += self.velocity end if btn(2) and self.y > 0 then self.y -= self.velocity end if btn(3) and self.y < 135 then self.y += self.velocity end if not (btn(0) or btn(1) or btn(2) or btn(3)) then self.velocity = self.min_velocity end if btn(1) then self.f = false end if btn(0) then self.f = true end if btnp(4) then local glow = Glow:new(self.x, self.y) glow.start_color = 7 glow.end_color = 12 add(animations, glow) end if btnp(5) then local glow = Glow:new(self.x, self.y) add(animations, glow) end end Glow = {} function Glow:new(x,y) local g = {x=x, y=y, t=0, length=0.7, radius=10, start_color=8, end_color=9} setmetatable(g, self) self.__index = self return g end function Glow:draw() for i=0,4 do local eff_radius = self.t*self.radius / self.length if eff_radius - i >= 0 then local c = self.start_color if i < (self.t/self.length)*4 then c = self.end_color end circ(self.x, self.y, eff_radius-i, c) end end end function Glow:update() self.t += 1/30.0 return self.t < self.length end :: gfx/0.gfx b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTAzLTI5IDAxOjE0OjUxIixtb2RpZmllZD0iMjAyNC0w NC0yOSAxNzo1MDoyMSIscmV2aXNpb249MTI4Nl1dbHo0AGAeAAAZZwAA8Rp7WzBdPXtibXA9cHh1 AEMgEBAE8PAsZmxhZ3M9MCxwYW5feD0wLjM3NQwA_wJ5PS0wLjEyNSx6b29tPTV9LDoAkCR6cAoP HU8eCgcAcD8ODx4KYBoJAP8CDRpQCh8dPw4dClAKDx1fDg0IAAT-Aw8eClAKDl8ODgpQCn4KUJrw A4sAJqUGOrAKHxMKsAoeBADwAKAaHhqQCgMOEQqQCgMPEgcAPQ4dAQYArw4KkAo_CpBa8AV9ACYQ Jn0AER1xAP8GYDoPFy46MAo9HxweHxIKMAodbxwPCAACIF8cIAD-ARodPxwODxIaQBpeGmB68ASE ACJRCAgECQACABIQCAAfGQ4AFh8J9QAmshEfHJAeED5QPhBeAgD-CSBOEE5QLBosYDwaPFAcEAog HIAa0ArwOWIAJtQDLxwwLlAuMC5QPhA_BACRYC4QLoAeGh6QBACfCgAegB4aEB6QaAAl8DHIZATw -7X-Dw-wG47wOPIa-hXyEv4G8iSgEv8YF-4Z-Q-_D-0dAoAC-RX_Hv0M-hr9FQJwAv0O-ib9CP4l 7T6dDgDwBAb_MP0E-juNAnACjVf_Od3_QH0LAKIH-j_9Dx-_QRdNDgBhQJ0c-kIHDQBG-kJtPAwA VA0PFj1MDwCGB-5CG3z_QloMAC9BegsALhdqWgBHCg0KLQ8ALwdNDQACP2z_Qw0AHj9c-kQNACs- TP5FDQAzOB1vDg8ALw2JDQAKMjz_Rg0AKHkHDgAPGwAHHJknAARPAD49SQegAA8NALcv-kMMABpH HV8LDQ8AKA14DQAXiFkALB14DQBUXO7H-igPALQl594bXK5Hvif_JRMA8QEgV94Xbgc_G1x_N-4D J-4iGADxBC1o-htXfieeF54bXF4n-ggn-iAYAPMGbRj_GEduZx4nfheOG1xOF-4MJ-4ergDzAxRH XleeJ24XfhtcPhf_EDf_GhkA8wYRN15H-gIHbhduG1wuF273A65H-hUcAPQHCPcE-gcXXhdeG1we F043-gI3rlf_EDEB8wkBZz5X-hEnThdOG0weF04Xbke_N85H-gwgAPEMTsdOV-4Hx04XPhc_G1wX ThdeJy43vkfeN-4IIgDxEJ0uJ26n-gdXvhc_Fx4dFy4LbAc_J14XfifuN95n-gEkAPIKrY43-gmH -ggHDj1OXA4Hzge_R85H-gD3ANcA8Ai9Pj0u-QCn-RcuHTzuFx6tPmeeR-4NbawE0FIevQ4HHv0H V35n-ganBHD9gAc9nofOvQRA-ZiOzQcAF64FAPsDgAL9rQKQAv2rArDyq-D----hZwVVMTQuNjJo BSE0NHYFAWkFHDHRBVD-FAHUHgIAsAS5BB4ECT8PGT0JCQAanQYAMQ8VDggAhwwOBLkEDA7UAwAf 7OQFIp8gIAT-FBH0Dh4DAALANPkGNB40CX8POX0JCQAxjRmNCAAv-QQHAAsyDxUOCQAeDAgAf-kG NAwO9A4EABI-HvwO1gAlctQPFPAB1A4EAP8SxB7wAcQO8AK0HvACpB7wA5Qe8AR0LvAFVC7wB27w --_rZgAl-wn5MCD6CoD5BND6APAB2fAC2fADufD---xwBy-zATrzGP4V8xL_BvMj0BP-GxVwB2Mc A7AD-RNwB2UUE5AD-QxwB1MDkAP9BHAHQwOQA21wBwALAAZwBwIOAANwBwANAARwBwIMAAVwBwIo AAP6Bg8NABU-gAN9DQBFA2gAAVUHDw0AHAFIBw8NACkBfwUPDQBdAUUHDw0AKQ5bAA8NAMEv-kMM AAw-oANdDAAsA3EHAQ4AGCZwBwESAB0hbwcBFwAdHG4HARcAD20HAQEZAA9tBwEBGQAPbQcEAeQA D20HBQImAQ9tBwcBIAAPbQcKTwOQA31tBw1PA5ADjW0HCE8DkAOdbQcDAKkEGVBtBwASABJ_bQcA CwAwlo7NBwAQrAUA8B6qE6AD-VTzAv0U8wOtE8AD7fMmTfMK8AJTrfMD8AOj8AAjPXPwJkPwIqPw NDOGByv-ln4FKC0zhwcWMn8FHDLPBfAK8P_iKvANCgMK8AwaAwrwCEoDAArwCAoDIAgAIwU6CABQ CgMQAwACAGQa8AQKAAMCAB8KDgAKRAE6AAMCAPAOSsAK-xIBCsAqzirgCs4K8AEarhrwAgquCvAD Go5VAGyOCvAFqqDHAGQ1LjE1ODMBAATQAFcxNC44MBcAAdoAHjPaAMAAOvAMCh8TGvAIOi7VAPAi HgAuOvAFCi4AThrwAiouJD4K8AIKFA4ADgQQHgAa4DoALgAEDxQzCvAACi4AHiQNPgoAUQAuEAMk CgDgICQQFBAq8AAKHhQANCPEAKBeJBAa8AEKfhQeSgAhLkAIANIaYBQQSuAK7xgK4ArsBAChGswa 8AAKzArwAQUAfxqsGvACypDtADvwDl1K8AZaLxMK8AYKTgQeCvAGGh4TBBMq8AUKIA5DYgHwByAe BD4a8AMKLhAELgAOCvADCkMkEwCxABAwzgBAAgoOQ88AsAIKDgMODxQuFA4AnQEwEB0Q1gDTBAog DRAUEDrwAQrGCgUAIBqmLgAQpiYAEIZhABCGKQIfhsgBQD----NRADbwJ0BABPD-WiIfGPAmQl7w IEKu8BtC-gHwFjL_AiIe8BBC-gFCXvAKQv4CMq7wBUL_AkL_APABIggA8D0G4P4BQn54vtDOMk6I Xhi_wH5CTkjuGK7ATiJ_KD74Ab6w3pi_GA4YvqAeAp447kgeGM6QHgIHjggeGK44XgjugB4CB34Y Lhh_KH4YDQDQDw8HbghOGE4ofij_AB0AYA1_CE4YHg8A8BoCgB4CHQduCF44bjj_A6AeDQcNbhhe GC5Y-gIHHcAeHQduyP4DBz0XwBoA8gT_FActNx3ALh0H-g8HPTcNGhcOGABwDS1HHUousBkAkQgf Dh1HLWoe0BkA8AgFbBctJw5KDvABHh0H-gA9XC0XTirwBBwA8AXOLTcsLRd_8AcuHX4HPVctJ37w CxgAYD4HLQcbNw8AEA4PAEAHPQdbDQDxHRIeLSd7J37wFR4NR3t_8BguDScdW17wGz4HHRcrXvAf LheO8CKu8CZu8CseqQQf5CcKCRYxqAQfNLUBHTBu8Am1ATHO8AO1ASEC4LQB8iIIwP4BQv4OsM4y zri_kH5CfpheWL6ATiKeOG6oDhjOcO44HnheGC4Y3nAeAp54rig_tAEApwFRnihOKN4NAKMIXghu GE44zhegtQGQbhgeKC5IzkegtQHwAwdeOF6I3negHgIdF46I-gKXsCEBsxf_EMfAHh0n-gunpwFC F-4Ht6gBhif_AycfDmctqwFUJ943XBeuAUY3jmdsrQFGN06nfK4BKPcBrQEWx60BF4esARlHqwEv Fy2rAV7wJtlvG-AZ-gjwEv4O8A3_FPAI-hjwBv4Mem7wBO7a-gDwA35q-g7wAv4f8AD_IeAOCv4H ev4ACADxIABqXgr_AtAOCv4BGn4a-gPQCv4EGk4K-gbACv4GGh4K-giwCv4IGv4JsAoOCv4hBgD2 CiKgHgr_EXqOoA4K-gPq-gGgDgquev4QoA4jACAgwAYAQBoHHgdlAPAHDvcC4AoOCk73A-8PB9AK Dgoe-Qb3BhMAcA73Bv0I0BoQABAH5wUg9x0GAPEK-R7gCi73Gx7wAF6H-gHXLuD_IfAA-gKA-poE T----30pASbwLxc-G-ApfvAj3vAe-gPwGP4AKl7wEv4BOo7wDv4BOt7wCu5K-gPwB846-gnwBZ46 -g3wBW4q-gAq7vAD-gVaJwFh8AH_AjpuCQDwAw4KziqeCv4D8AAOCu46Xgr_BAoAgf4DOh4K-gXg OAHQBuAK-hYqftAK-hFKrvsAUf4LOv4BHgHwBQZK-gXAHgr_AUr_CdAOCt46-gg3QABhrir_Bqfg TQFRDPcB8AAsACD3CC8Br-4A9w7gDgqu9xVQAXEjYBBAABv1PwAnLTQMCTQxLjSREB8zPwB4DucG Dz0ACh81uwAsDz8A-3UPbxsaDzoA---------wf9YmBgBP8eD-8VEv8eI-8VKP8eEf8VNv8eBv8V Pt8e-xVGfx7-FUo-Hv8VDPAY-goPHv4B8DD_BQU_8Dw_BZ4VDvBADhWedfA2da71BPAc9QTO9UL_ APU_-gT1Ov4L9TD_HPUY-god-k4d-k4t-kxN-kpdAwBPTf5MPQMABBEtOQAFAwAhDf4pCCQ1DREA BVkABTIAAmIAQW3_SH0DAP9Yjf5Gnf5Grf5Ezf5C3f5C7f5A-QH_Pv0C-j79A-48-QX_Ov0H-jj9 Cf42-Qv_NP0N-jL9D-4w-RH_Lv0T-iz9Ff4q-Rj_Jv0b-iT9Hv4g-SH_Hv0k-hr9Kf4U-S7_EP00 -gj9Pd79GXoBIw75CA8-AP9VDi4DD3kAHP8LcP8SGPAc-jDwCv488AL_QPAF-jbwF-4c8GlWAC-- Be4-Hf4d8Ar_BT3_Ez2_8AL_Lj3eYAAz8AYSDx0AHgAO4F8e8DP-EgZ-Hp8SAA4CAP8d8BZNDx5t Di0OHQ7NDlwO-QbwCo1MfQ79Al6tDh0eHQ6d8AL9QPAF-TbwF-2EACrxD6cPHvBPDiAO8EcOIA4Q DvBJDnAO8Cg_8BIO8CheIP8A-xYtXv0n8AqdPq1ufXL9DPAC-QEy-QVyXVL9AvAF-SJyvfAX-RZS hAApESaEAPA1EA7wTw7wSA4QDxIgDvBIHg1wDvBDDUAdIA4ADcBN8DQeHQANII0u-QwQTfAVTQAO zU79F-AKnQ4NHj0SXU6Nkm0S-QGdAP8KIv0Ekk1y-QHwBZ0S-RUSHgIuEq3wF-0VYqMAKfAK-1gv HvARFvApTvBDDxJQHgc_TfA9bW79Co0A8RotMh0SjU5NQi1CbR698Ap9wl0uTTIN0h0eAg1CrfAC zYJdQm2STSIeIpUAjyL9B0Itcj4ilQAu8EhzHx5wHvBGDvAUJvAdLvAdJvAfDvADDvBMPvAJFvAi HlAu8EYeMC8SDg2QHvADFvAiDVAOLQ4NDk3wPc0OHSJNYl0_AE3wFaINIo0Osg1iLV4ibSAi8AS- APMREi0O8gJegh1C8AKNsi49cg0ukk0CXlK98AWdMl0CvXLAAH89Mk1SHYJtxQApoZom8E0m8K4W 8EYFAvFLQBbwKjIPEvAJDvApDQDSLQBSMCIOMELQMvATfaJNYh0OAh0yAB0ugCLwABJQsg4iLdIe Ig3yAy49EELwAfIBTkI-EyItEj5SPvIJ8AKN8gs8Yjw9cg4yHVI9uwD-AhKtci0iPgIOUj0eTfAX PfIKvAAq8Ej6LxbwTS7wrQYF8CIGgAZgPx4wBvANMvAbQkBdYDKABQaQQsAS8AQPEgDSHF3yA7BS wDLwAC0M8gBdcgwSHHIMMjBC8ABSEKItEgziPRIMTxMtUityDGLJAP8eTUI7EiviPfII8AEMIgwS HOI7clsiWz2yW2LwBTzyFwzyARwyLPAXEhzyChyywwAo8xMaTx6QHvC7LgAvFvAhXqAO8AMuMC3w Nh4QDvBEHoAOAE6w3QD0BzAeAA4QDjAGXvAHMsAy0F5QQmAOAB7mAPEPQrB_oi4CDjIOQn5SsFLA sjAeB14CXvIDDgduYg8S6ADA4o4MYj8ToiuOEmsy5AAg4m7jAPESYisifvIG8AFyG1JOIltSWyI7 XoKLYvAFUjvyAnvyAgtS5wAf8uMEKfE5OAUwBfBLNfBLRfB7Px7wHhXwGq4wBvAKBvAIHxOQTaAu F25gBuBeoBWgLQINsDKALgeeIELAjjA_wELAQnAeB66CLgIOIl4H2gDggi0A-gPiHgeeAg0yPhLY APAdws5SPRJtAt4CbTINYvABEi1yrm0SLWItAp5STaLwAXIdMn4CbVJdIj1ego3ZAP4BPQ7yAd2y DUKd8BdyTfIETToFDzIHGA86AP------------8kAY4d-wAeFzbwCgcwBvALBhAG8AwFAA-wFwsG MAbwCBZQFvAFBx8ccAbwAwcvGi8cED4G8AEHbxoeTQbwAAfdBQBzHQutBvAABgcA-wgtC50G8AEG vQbwAwadBvAFFl0W8AhWwBIVJQAuEfF6--r2BvA6Bv8aBAbwORb_BAbwOBb_BQbwNxb_BhbwNRb_ CAbwNBb_CQbwMxb_CwbwMRb_DBbwLib_DhbwLBb_EhbwKCb_FBbwJhb_FxbwJBb_GRbwISb_Gxbw Hxb_HxbwHBb_ISbwGRb_JBbwFxb_JhbwFRb_KQbwFAb_KhbwEhb_KxbwEQb_LQYGAHYW8A8G-i8G BgBPMAbwDgYAmVEwnxjwAAkAUw0GUAYNDAASnQgAEGD8ARkDCgASthAAE5AYAE_gBvACCAAII2ZA EAA-UAYwCgAdUFbwA-Yw8gEfYy8CFB8yXQMnDzoA-----------------9nwI2CABPD-JL8U8ED_ AvA8-gbwOT8V-gTwNz3_BfA1Tf4H8DNN-gjwMk3_CvAwTf4L8C9dBQD4AE3_DPAuXf4N8C1N-g3w LgUAMwzwLwUAMQsPDwcAEDwmAPAMCTzwLBxN-gg88C4cPf4HLA8X8DFN-gULHAsMCQDwrAQMCwwL DPAzTb4tLg8ZHAsc8DNdjj0uGjzwNV1ObR4qPPA2-QFKPPA3zXos8DkKTdoc8Dv6AwzwO5oMivA7 amx68DpafHrwOVofHAxpavA4WqlaOfA0WslKOfA0SgDpKknwMyogmS8QKQpZ8DQKSEn4BPAw_BHw LmgPCvgM8CtoFygn_AfwKfgDNzgXqPAoJ-gMB7jwIgf4EieI8CH4FgeI8CD4GAd48CD4GSc48B-4 IfAf_CLwHfggBxgGAPEHFxjwHPghByjwG-gl8Bv4JvAaKAn4IgYA8CMOCfgE8BoYCfgOGSgJ_ADw GRgJ_A8ZGAmYB1jwGAgZ_BAJKAmIB1jwGQn4ERkoCRgJWBkAVAn4Eik4CwDxAhQZGBlYF1jwFwn4 FRkIGWgHCwCBGBno8BYJ_Bk_AGQUGfgVGRgLAFAUCTgZ6AkAEBpyAIITGfgaGYgXOAkARvgA8BII ABEbiACBEQn4HAmoB0gJACQZmAkAsPgB8BAZ_BspqAc4CQCmHBm4BzjwDwn4HQkAocgHGPAQCfgc KdhOACApyGUAMBOpuH0A8AEPSXgZqPAVGfgOGbgZiPAXQgDyAQggGPAaKfgbGQjwHyn4HAkHABAZ BgDwJBo5DwzwHin4GFkG8B8Z_BdpLfAdGfgUaQYJTfAcGfgReQZt8B4J_A6ZbRXwHhn4CpmNJQgA UAapFm1VCQDyQgK5Fn2F8B4ZyMkGjcXwHgmYuc3V8B8JWKnd9QLwH8kGzfUFAAXwHpkVjfUN8B5p rfUPAAXwHQ0ZvfUV8Bvd9RjwGY0FDfUc8Bkt9STwGT0FDQIAovUc8Bgt9SbwFy0QAEMFDfUdEgAG JACkHvAVPfUo8BQtFRIAhiDwFC31KvASJACFIvASLfUs8BASAAEUAIUQLfUsAAXwD14AABYAmQ8G 8A899SoAFRgAA1gAiw8t9S0ABfAM7wNuLTI5LjEwHTlIMzguNzQ5D5ZDAAEEBPEt---DbxTwRe7w PD8Vfile8Dhdjile8Dc9DkluCW7wNj0OWe7wNT0OaW4KbvA0HT5p7vA0DU5Z-gDwNG5JBgDwhClu rxnwNN7c8DQZjvwB8DQZbvwDEB8P8DAZXvwDEBvwMRle-AILACvwMW6c2-Axbozb8DJejJsfHyvw Ml58iyg78DJebEsIGygnG-AzXlwrOEsfDgcL8DReLB8XGyhLCBsfDivwMx57HxcYCxcPDisYW-Az DpsPFwsnHw47GEvwMx5LHxdLFx8OSwhL8DM_Ky8XuxYA8CcNTgwLFrsIW-AzPR4s6xgr8DM9DhwA LKsoO-AzLQ5siyhLHxzwNYxrGFsGDxAfHPA0jADLBi8KAPJJMqyrFgU-EBXwMQwAfKsGG0Ql8DCc 20QVFPAvrMtEJZTwJ4xFixUkRaTwJIwFNBV7JQQF9AHwInwVRCV7JfQBFfAgfAWEBWsl9AMF8CBs BZQFaxr0BfAgXAoA8UEG8B9cBZQVawoF9AbwHkwABZQVWw8MCgX0B-AeLAAldAUEFTsTGvQH8CEV BBVkBRQFSgUapAW08B8VChQlRAUUGlQKpAXE8BwVAwpEJSQFpA4A8AYaFQQKdCUEBbQKlAXU8BgV xCXECoQKAFAFAwrEFQwA8Ark8BYFAwr0FwX0APAVBQr0GBX0APATFfQaCABgEgX0EgqECgDzABEF 9BMKdAAF9ALwDwX0FAsAcA4F9BUKZBALABANCwARdAsAQQwF9BYhADQD8AsLAKEE8AoF9B8AFfQD CQAQEB0AMgr0IAgAUNQV9BAQGwDyAQgF5AX0CApkIBX0AvAI9AANADIl9AENAIUJCkQQFRQl5A4A QQAVRAUOAGAV9AgKRAA6ATAI9AEbAB80DQACwRX0DQAF9AXwCPQDBQsAMwTwCQsAUAQq1PALDACA DCAaBBq08AwMAMAICiQQCjQalPAN9AJjAKAkAApUCoTwDvQCVwAADgBAGmTwDw4AkgoKJBVUClTw EA0AYTQFVBo0BQ4A8QQEdfQBCjQFZAokBfAR5FVkBfQADwCBFAXwEvQNBeQNAHAEBfATBfQMHACz JAVkCgXwFAX0CxUOAMHwFQX0DBrkCiQFClQNAHALOvQCevAXaQBgFFpE6-AYCgBSZBoU6xYLAIB0 CgTbBivwGaUAVIQK6xYbFwBBywYrBg0AUQkKdArbDQASFyUAAA0AMQvwGAwAhGs-BTsGGwYLKQAx S2IrDwABUABEVBorgg8AUdS1WuIbDABiGgVkdfIOGADyEhtlbfIOOwYLAhvwGo0CDfISKwYLQvAZ LfIcC2LwGT0CDQIAEPJIBVLyJfAYLRAAgAIN8h7wFy3ySAUCEAABEgAwFT3ySAUUEhIAAEgFEPJI BQIQADACDfJIBRDySAUnAg0UAGUQLfIu8A9cAJ8CDfIk8A498i4oBSwPoAknD4gK-yAg-xTEGvEB fPQ--gEE-xU9BP4BBP08DgcAIDseBwBBLfQ3LggATwT_NQQKAP80BFIBIfQ4YgExHfQ6cQFyDfQ9 -gH0P70wMf--6JQBH-2TAf92H1z2GyID5gnyKxjfFvBALr8PHvA9Lu0e8Dse-QIO8Doe-QMe8DkO -QMfEQ4N8DUcHs18DhzwMRwAHA7dDA0cDVzwMUwKAPYGHA0MDgzwMQwgHv0BDD0MDvA2Dv0IBgBg LU4dTm0uDwCwBR4NDvA3Dl0O-QAIAEBNHv0BIQBRPR49Ds0qAFAeTQ69HgkAUA5dDp0KLQDwDR4d Pi0OjQou8DgOTU6dCg7wOR79BA7wOg5NPq0HAPGALQ5tDm0e8DsOHR5NHl0_8DoeHX5NHh0u8Dk_ QH5NHvBBHs0ODQLwPx7NDxhi8DourQtyG-A5Dp0bYjvwNAs_nQtiGw0r8DICCw0enRtSGz0CC-Aw Egu9G1IbXQIL8CwNCyIbrQtSG30CC-AqHQsyG30rQhudAgsC8CgdC1IrPRtiC70bAvAnHQtyW2Ib zQsLAPIA8gQb3RvwJi0L8gMb7QILCgCwC-0AG-AlPQvyAhsKAPAEAggX8BA9C-IBG-0CC-ACCDfw Dg4A8QAL-QML8AMIN-ANPQvyABsOAEAYR-ALDgBQC-0CDg0eAGAHGDfwCU0SADFNDr0TAEwYBxgn EwBIAFfwCBIAYQQIEFfwBxIAIz0eEgByIEcALxXwAxUAIg7NFQA5MEcpEwCwAvADCDA3KQ3wAl2U ABUtFQBwQAdJHfABXbcAUB0ezQ4bPABBWa0gvREAIQ7dEQBJIEn9DBAAMCn9DhAA0hIO3Q4CC-AK -Q8L8gQMADoL-Q4MABEFCwBUDI0g-QENAPQKDW3wBBvyBc0eAgvwDk3wBQvyBs0OEgvwKAkAcB0O vfIFvR4KAPACXhBObcLNDiIL8CANAG69ct0LAPEMGmVuC-0RHiIL8BYVDkVOEC4L-REOMgvwFYWe CgDwTfAWhU4AHhAL-RAeIvAXhW4tC-0PHjIAC-AV1R0Q-REOQivwFLVgC-0NLjJL8BNlECVgCxL9 CS6SK-AShYALMv0EPtIb8BFVsAti3T7yAhvwEFWwC-ICPvIGK-AOCwAiHRsIAEAeG-ANCAAgHwsI AKbyIBvwDFWg8iILBwBgsPIhG-ALJABnIBvwC2WgCAA-C-AMCAABAEwAAAgAYR4L8A9VoGwAAQgA EByHAPAAoAvyGxvwEUXAC-IZG-ASCABAGBvwEwgAQBcb8BQIAEEVK-AVCAA-C-AXCAANITXQCABv FkXgC-IUCAAUIxMbCABPCxLwFQkADR8bRAAAYvAA8hTwFwcAHwPyBBUPyAgnDzoA------------ ---3UG09NX19 :: gfx/.info.pod b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTAzLTI5IDAxOjE0OjUxIixzdG9yZWQ9IjIwMjQtMDMt MjkgMDE6MTQ6NTEiXV1sejQABAAAAAMAAAAwbmls :: library.lua --[[pod_format="raw",created="2024-04-10 00:24:20",modified="2024-04-29 16:05:11",revision=200]] plant_descriptions = { [-1]={{"i don't know what that is. where did you find this?"}}, [13]={{"these are chives. are we sure this is for alchemy?"}}, [14]={{"this is foxglove"}}, } ingredient_descriptions = { ["reagent green"]={{"blah blah reagent green blah blah"}} } function get_conversation(plant) local id = plant[1] return plant_descriptions[id] or plant_descriptions[-1] end book_pages = { [1]={ "hester's big book of recipes! alchemists only! dangerous recipes!", "format: \nrecipe notes \n \ningredient 1 \ningredient 2 \ningredient 3" }, [2]={ "\nBarthow's Encyclopaedia of Botanicals and Components", "A comprehensive reference to help identify all ingredients an alchemist needs." } } :: main.lua --[[pod_format="raw",created="2024-04-02 02:59:37",modified="2024-04-29 15:34:08",revision=1153]] -- this is atelier hester! -- except for the one line in _init that does change_screen(shop_screen) -- this is just a file that sets up the framework we're using: -- change_scene to change the displayed sscene -- _update and _draw to run the current scene -- and some stuff for setting animations. include("art.lua") include("script.lua") include("s_title.lua") include("s_shop.lua") include("s_conversation.lua") include("s_drawer.lua") include("s_book.lua") DEBUG = true scene = { before=function() end, draw=function() end, update=function() end } previous_scene = scene animations = {} script = {} collider_renders = {} function _init() vid(3) change_scene(shop_screen) end function _draw() scene:draw() for anim in all(animations) do if anim.draw ~= nil then anim:draw() end end if DEBUG then rectfill(0,0,90,10, 7) print("animations: "..#animations, 0,0,0) rectfill(0,10,90,20,7) print("script nodes: "..#script, 0,10, 0) for r in all(collider_renders) do rect(r.left, r.top, r.right, r.bottom, 9) end while #collider_renders > 0 do deli(collider_renders) end end end function _update() if #script == 0 or not script[1].blocking then scene:update() end local new_animations = {} for anim in all(animations) do local result = anim:update() if result then add(new_animations, anim) end end animations = new_animations if #script > 0 then local result = script[1]:update() if not result then deli(script, 1) end end end function change_scene(new_scene) if new_scene.before ~= nil then new_scene:before() end scene = new_scene end function play_script(s) for action in all(s) do add(script, action) end end :: map/0.map b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTAzLTI5IDAxOjE0OjUxIixtb2RpZmllZD0iMjAyNC0w NC0wNSAxMzo1NDowNiIscmV2aXNpb249NjgzXV1sejQAaAAAAFgQAADwCHt7Ym1wPXVzZXJkYXRh KCJpMTYiLDMyAwAvIjABAP--------------------vxCCIpLGhpZGRlbj1mYWxzZSxwYW5feD0w CADSeT0wLHRpbGVfaD0xNgoAEHcKAIB6b29tPTF9fQ== :: map/.info.pod b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTAzLTI5IDAxOjE0OjUxIixzdG9yZWQ9IjIwMjQtMDMt MjkgMDE6MTQ6NTEiXV1sejQABAAAAAMAAAAwbmls :: s_book.lua --[[pod_format="raw",created="2024-04-14 02:34:41",modified="2024-04-23 02:42:38",revision=126]] BookScene = { extension = 0, behind = nil, inset = 60, } function BookScene:new(background, pages) c = {height=0, behind=nil, background=background, pages=pages, index=1, fairy=nil} setmetatable(c, self) self.__index = self return c end function BookScene:before() self.behind = scene play_script({ Script.len(function(s) self.height = 115*easeDecelerate(s.timer/s.length) end, 0.5) }) self.before = function() end self.fairy = self.behind.fairy end function BookScene:update() if btnp(5) then play_script({ Script.len(function(s) self.height = 115*(1-easeAccelerate(s.timer/s.length)) end, 0.5), Script.once(function(s) change_scene(self.behind) end) }) end self.fairy:update() end function BookScene:draw() self.behind:draw(true) spr(self.background, 20, 135-self.height) print(wrap(self.pages[self.index],80), 36, 135-self.height+10, 20) print(wrap(self.pages[self.index+1],80), 130, 135-self.height+10, 20) if self.fairy ~= nil then self.fairy:draw() end end :: s_conversation.lua --[[pod_format="raw",created="2024-04-05 14:55:45",modified="2024-04-14 02:34:19",revision=129]] default_script = { {"welcome to Atelier Hester!", talk_sprite} } Conversation = {} function Conversation:new(script, final) local c = {script=script or default_script, final=final or function() end, index=1} setmetatable(c, self) self.__index = self return c end function Conversation:before() self.behind = scene self.before = function() end -- only ddo othis the firstt time this scene is played end function Conversation:update() local now = self.script[self.index] if now.during ~= nil then now.during() end if btnp(4) or btnp(5) then if now.after ~= nil then now.after() end if self.index < #self.script then self.index += 1 else self:after() end end end function Conversation:draw() self.behind:draw() ragged_box(30, 100, 240-30, 130) color(0) print(wrap(self.script[self.index][1], 240-68), 34, 104) end function Conversation:after() self:final() change_scene(self.behind) end :: s_drawer.lua --[[pod_format="raw",created="2024-04-05 00:59:36",modified="2024-04-29 15:59:50",revision=379]] DrawerScene = { extension = 0, behind = nil, inset = 60, contents = { title = "reagent green", small_graphic = 128, large_graphic = 129, }, fairy = nil, interior_collider = {}, contents_collider = {} } function DrawerScene:new(drawer) c = {extension=0, behind=nil, inset=60} if drawer.size > 16 then c.inset=30 end setmetatable(c, self) self.__index = self c.interior_collider = {left=c.inset, top=0, right=240-c.inset, bottom=c.extension} c.contents_collider = { left=120-96/2, top=10, right=120+96/2, bottom=10+96, } return c end function DrawerScene:before() self.behind = scene play_script({ Script.len(function(s) self.extension = 115*easeDecelerate(s.timer/s.length) end, 0.5) }) self.before = function() end self.fairy = self.behind.fairy end function DrawerScene:update() self.interior_collider.bottom = self.extension if (btnp(5) or btnp(4)) and not collides(self.fairy, self.interior_collider) then play_script({ Script.len(function(s) self.extension = 115*(1-easeAccelerate(s.timer/s.length)) end, 0.5), Script.once(function(s) change_scene(self.behind) end) }) end if collides(self.fairy, self.contents_collider) then if btnp(4) then add(self.behind.tray, {self.contents.small_graphic}) end if btnp(5) then change_scene(Conversation:new(ingredient_descriptions[self.contents.title])) end end self.fairy:update() end function DrawerScene:draw() self.behind:draw() draw_drawer(self.extension, self.inset) spr(self.contents.large_graphic, self.contents_collider.left, self.extension - 115 + self.contents_collider.top) self.fairy:draw() end function draw_drawer(distance, inset) rectfill(inset, -1, 240-inset, distance, 20) fillp(0b1010110110110101) rectfill(inset, -1, inset+40, distance, 20 | 21<<8) fillp() for i=1,4 do rect(inset-i, -i, 240-inset+i, distance+i, 4) end rectfill(inset-10, distance, 240-inset+10, distance+10, 4) rect(inset-10, distance+10, 240-inset+10, distance+10, 20) spr(10, inset-10-32, distance, true) spr(10, 240-inset+10, distance) rectfill(inset+10, distance+10+1, 240-inset-10, distance+10+2, 9) spr(11, 120-16, distance+10+1) end :: s_shop.lua --[[pod_format="raw",created="2024-04-05 14:55:27",modified="2024-04-29 17:50:21",revision=430]] -- this manages the main shop interface, where you look at the cupboard and plantss -- and sstuff. include("art.lua") include("fairy.lua") include("cabinet.lua") include("library.lua") cabinet = Cabinet:new(40, 10, 2) --fairy = Fairy:new() alchemist_sprite = 192 alchemist_bob = 0 customer_sprite = 0 customer_bob = 0 customer_visible = false door_open = 0 book_1 = {left=10, right=74, top=100, bottom=164} book_2 = {left=70, right=134, top=100, bottom=164} shop_screen = { fairy = Fairy:new(), tray = {}, -- list of selected ingredients, up to 3? tray_slots = {} } for i=1,3 do shop_screen.tray_slots[i] = { left=108+i*32, right=108+i*32+32, top=135-4-32, bottom=135-4 } end function shop_screen:draw() cls() cabinet:draw() -- alchemist! bob(alchemist_sprite, 0, 7, 96, 128, alchemist_bob) palt(30, true) palt(0, false) spr(64, 240-100, 135-49) palt(30, false) palt(0, true) spr(72+flr(2*t()%11), 240-100, 135-52) -- countertop! draw_counter(20) if collides(self.fairy, book_1) then spr(18, book_1.left, book_1.top) else spr(17, book_1.left, book_1.top) end if collides(self.fairy, book_2) then spr(20, book_2.left, book_2.top) else spr(19, book_2.left, book_2.top) end for idx, box in ipairs(self.tray_slots) do local ingredient = self.tray[idx] if ingredient ~= nil then spr(ingredient[1], box.left, box.top) end end if customer_visible then bob(customer_sprite, 240-96, 7, 96, 128, customer_bob) end self.fairy:draw() draw_door(door_open) end function draw_counter(height) rectfill(0, 135-height, 240, 135, 4) for i=1,height do rectfill(0,135-height, 0.5*i*i, 135-i, 4+16) rectfill(240,135-height, 240-0.5*i*i, 135-i, 4+16) end line(0,135-height, 240, 135-height, 4+16) end function shop_screen:update() self.fairy:update() cabinet:update(self.fairy.x, self.fairy.y) if btnp(4) then local drawer = cabinet:drawer_at(self.fairy.x, self.fairy.y) if drawer then change_scene(DrawerScene:new(drawer)) end if collides(self.fairy, book_1) then change_scene(BookScene:new(007, book_pages[1])) end if collides(self.fairy, book_2) then change_scene(BookScene:new(012, book_pages[2])) end if cabinet.hover_plant ~= nil and #self.tray < #self.tray_slots then add(self.tray, cabinet.hover_plant) end end if btnp(5) then add(animations, Glow:new(self.fairy.x, self.fairy.y)) if cabinet.hover_plant ~= nil then change_scene(Conversation:new(get_conversation(cabinet.hover_plant))) end for idx, box in ipairs(self.tray_slots) do if collides(self.fairy, box) then deli(self.tray, idx) end end end end function draw_door(open) palt(0x00, true) if open >=0.0 then fillp(0b1111111111111111) end if open > 0.1 then fillp(0b1011010111100101) end if open > 0.2 then fillp(0b1010010110100101) end if open > 0.4 then fillp(0b1010000110100100) end if open > 0.7 then fillp(0x0000) end rectfill(240-(96*open), 135-128, 240, 135, 0x00) sspr(200, 0,0,96,128, 240-(96*open), 135-128, 96*open, 128) palt() fillp() end :: s_title.lua --[[pod_format="raw",created="2024-04-10 01:43:09",modified="2024-04-10 15:04:40",revision=101]] title_screen = { continue=false } function title_screen:update() if btnp(2) or btnp(3) then self.continue = not self.continue end if btnp(4) and not self.continue then change_scene(shop_screen) play_script(the_script) end end function title_screen:draw() cls() print("Atelier Hester ", 120-(68/2), 50, 7) print("Start", 120-25/2, 70, 7) print("Continue", 120-39/2, 90, 7) local y = 70 if self.continue then y=90 end rect(120-50/2, y-5, 120+50/2-1, y+7+5, 7) end :: screen_drawer.lua --[[pod_format="raw",created="2024-04-05 00:59:25",modified="2024-04-05 00:59:26",revision=1]] :: script.lua --[[pod_format="raw",created="2024-04-04 01:01:55",modified="2024-04-14 03:09:34",revision=554]] Script = {} -- sscriptanim generates animation functions and adds the boilerplate we want -- can track time, but generally the ssystem we're working with is that -- animations are objects which repeatedly get :update() called on them -- they run at least once, every frame, *until they return false*. -- so keep returning true to keep playing, rerturn false to end -- the blocking argument determines whether update() is called on the underlying -- scene, i think. -- the ScriptAnim.len variant will take nil returnss as carte blanche to keep -- running, checking for exactly the value false to cancel out. function Script.len(func, len, blocking) local b = blocking if b == nil then b = true end return { timer = 0, length=len, blocking=b, update=function(self) -- we wrap the function we got passsed so that it'll update the timer -- and end appropriately self.timer += 1/60.0 if func(self) == false then return false end return self.timer < self.length end } end -- ScriptAnim.once is cnofusingly named, and will call func(self) every frame -- until it returns false. function Script.once(func, blocking) local b = blocking if b == nil then b = true end return { timer=0, blocking=b, update=function(self) self.timer += 1/60.0 return func(self) end } end -- stay in this script node until func(self) sets self.done to true function Script.waitTilAfter(func, blocking) local b = blocking if b == nil then b = true end return { first=true, done=false, timer=0, blocking=b, update=function(self) if self.first then func(self) self.first = not self.first end return not self.done end } end -- functions for making a cnoversation script line that bobs the alchemist or the -- custmoer respectively function A(arg) arg.during=function() alchemist_bob=abs(5*sin(3*t())) end arg.after=function() alchemist_bob=0 end return arg end function B(arg) arg.during=function() customer_bob=abs(5*sin(3*t())) end arg.after=function() customer_bob=0 end return arg end -- here's a sample script for a guy walking in and asking for flibbertygibbets the_script = { Script.len(function(s) -- open door door_open = easeTrig(s.timer/s.length) end, 0.5), Script.once(function() -- person appearss alchemist_sprite = 193 customer_visible = true customer_sprite = 201 return false end), Script.len(function(s) -- door closes door_open = easeTrig(1-(s.timer/s.length)) end, 0.5), Script.waitTilAfter(function(s) -- cnoversation starts change_scene(Conversation:new({ A{"Welcome to Atelier Hester!"}, B{"hey do yuo have flibbertygibbetss"}, A{"Fresh out, sorry."} }, function() s.done = true end)) end, false), Script.len(function(s) -- open door door_open = easeTrig(s.timer/s.length) end, 0.5), Script.once(function() -- person appearss alchemist_sprite = 192 customer_visible = false return false end), Script.len(function(s) -- door closes door_open = easeTrig(1-(s.timer/s.length)) end, 0.5), } :: sfx/0.sfx b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTAzLTI5IDAxOjE0OjUxIixtb2RpZmllZD0iMjAyNC0w NC0wNSAxMzo1NDowNiIscmV2aXNpb249NjY4XV1sejQAEAEAAFEHAADwJ3B4dQADKAAAAwAED0AQ Ag4AAaABIAKgDgAPEAAN8MoBAgMEBQYHAA--kAgJCgsPDA8NDw4PDxAA8AANDxEPEg8TDxQPFQ8W DxcTAPEBDxgPGQ8aDxsPHA8dDx4PHxQA8QAgDyEPIg8jDyQPJQ8mDycUAPEAKA8pDyoPKw8sDy0P Lg8vFADxADAPMQ8yDzMPNA81DzYPNxQA-wU4DzkPOg87DzwPPQ8_Dz8AD--w-wEA6-8nWgEQBg8g EAEgASAB8AACEAIMEAEgDyEgATAPQPDDDygP--DGD-gKD-8PgA-3Dw0B8AkBEAYMMAD-OR--AQDc v-gPQAANQP--sPBwCgD--2Qf-wEAl1D-----Hw== :: sfx/.info.pod b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTAzLTI5IDAxOjE0OjUxIixzdG9yZWQ9IjIwMjQtMDMt MjkgMDE6MTQ6NTEiXV1sejQABAAAAAMAAAAwbmls :: shop.lua --[[pod_format="raw",created="2024-04-23 01:22:37",modified="2024-04-23 01:22:37",revision=0]] -- this manages the main shop interface, where you look at the cupboard and plantss -- and sstuff. include("art.lua") include("fairy.lua") include("cabinet.lua") cabinet = Cabinet:new(40, 10, 2) fairy = Fairy:new() alchemist_sprite = 192 alchemist_bob = 0 customer_sprite = 0 customer_bob = 0 customer_visible = false door_open = 0 shop_screen = {} function shop_screen.draw() cls() cabinet:draw() -- alchemist! bob(alchemist_sprite, 0, 7, 96, 128, alchemist_bob) spr(64, 240-96, 135-96) -- countertop! draw_counter(14) if customer_visible then bob(customer_sprite, 240-96, 7, 96, 128, customer_bob) end draw_door(door_open) fairy:draw() end function draw_counter(height) rectfill(0, 135-height, 240, 135, 4) for i=1,height do rectfill(0,135-height, 0.5*i*i, 135-i, 4+16) rectfill(240,135-height, 240-0.5*i*i, 135-i, 4+16) end line(0,135-height, 240, 135-height, 4+16) end function shop_screen.update() fairy:move() cabinet:update(fairy.x, fairy.y) if btnp(4) then local drawer = cabinet:drawer_at(fairy.x, fairy.y) if drawer then change_scene(DrawerScene:new(drawer)) end end end function draw_door(open) palt(0x00, true) if open >=0.0 then fillp(0b1111111111111111) end if open > 0.1 then fillp(0b1011010111100101) end if open > 0.2 then fillp(0b1010010110100101) end if open > 0.4 then fillp(0b1010000110100100) end if open > 0.7 then fillp(0x0000) end rectfill(240-(96*open), 135-128, 240, 135, 0x00) sspr(200, 0,0,96,128, 240-(96*open), 135-128, 96*open, 128) palt() fillp() end :: story.txt --[[pod_format="raw",created="2024-03-30 15:58:22",modified="2024-04-11 01:41:32",revision=208]] ATELIER HESTER welcome to atelier phoebe 2! this is my document for recording story ideas! please don't read this; it is all the spoilers! if you want to know what happens i recommend playing the game, that is the proper way to experience this :) -------------- main gameplay interface, you're shown a gridd of cubbiess which contain various ingredients you look at the things in the cubbies and label them? labeling could be hard with just o/x you have twwo books, one of recipes and one of ingredients? drag a label from the book to the drawer/plant? -------------- plot ddetails follow!!! main character amnesia from alchemy gone wrong. main character badly in debt to loan shark everyone in town has some debt and don't talk about it most people don't like main character mc has to mend relationships with everyone in order to gather everyone together to defeat loan shark player controls a fairy assistant for alchemy possibly fairy is new to the atelier? early dialog esstablishes it's common knowledge that fairies can blink white (o) to confirm things or red (x) to be uncertain / ask a question maybe other colors at other timess but you get it, those are our two verbs - ask about something and suggest something interface is an apothecary cabinet you can open the drawerss of and ask about. you have to suggest ingredients to mix together for the cauldron at the beginning MC is unsure and doesn't know about your suggestions - "i guess i can look that up?", "maybe i'll try this?" because the player is guiding them. towards the end MC responds as though teaching the player fairy, like "that's right, that'll work!" and "good job, yeah!" to communicate that the MC is more confident and getting their mlemory of alchemy back the town generally ddoesn't like the alchemisst just because she's been kindda nasty and rude at times, just petty disagreements that have boiled over. she's known to be a decent alchemist though i guesss endgame is that you rally the town together to break free of the loan shark; it's hard too convince townsfolk both because they don't like you at first and also because the loans ARE legitimate. but it turnss out that the rest of the town also has debt to the shark and if you convince everyone you can both 1. achieve independence from the supplies he sells (maybe he's the intermediary with the trader? or buys and ressells everything at a markup?) 2. convince people to just reject the loanss/debt; quesstion here of whether they do this by force, whether cops exist, idk, this is explicitly passtoral fantasy. maybe at the end the player will muse about whether it's good to have mob rule, "no one in toown liked me, what if they threatened to burn down my shop?" "yeah, that would suck. maybe we could build something. but right now rule by mob is better than rule by loan shark!" idk this feels overly didactic but you get the idea this is really getting into the weeds of how we view the justice system but maybe he threatens to say "i'll send for the king's knights!" and the crowd is like "you can do that if you want, but by the time they get here your house will be burned down. alternately, you can keep your house and try to be friendly. maybe even contribute to the town. it's up to you. burn down your storehouse or genuinely connect with people?" definitely overly preachy but i like that ------------------ script!!!!!!!!!!!! ------------------ title screen new game or load? new game -> hester with her back to cauldrron holding a little fairy doll in pieces fairy shakes and then comes to life hester: "ahhh, the synthesis wworked! ... i think" hester: "a fairy like you should be a good help around the shop." hester: "you might noot be able to speak but you can flash white for yes and red for not sure" the whole time there's more and more bubbling in the cauldron hester: "you can be my hands across the atelier!" explosion! soot-covered hester stands up "what just happened." "wait a second. who am i." "alchemy books? a cauldron?" outside view of shop, Atelier Hester on the sign "Hester..." back inside "i must be an alchemist..." loan shark arrives "hester! you got the latest payment for me, girlie?" "i'm afraid i don't knwo who i am - can you help me?" "nice try. remember you owe me 4000Z by the end of the month. have a nice day!!!" loan shark leaves (SAVE POINT) "am i... in debt?" "i don't know hwo to do alchemy... but maybe these books..." (player opens books) "it looks like this one has recipes... this one has infoormation about ingredients... my head..." (when quit uot of both books, old man comes in) "hey, hester. can i get that purified water?" "i don't knwo who i am" "sorry, i can't hear so good these days - purified water? my usual order?" (moves on when you've crafted purified water) "thank you, hester. this will help me out. here's your payment." (old man leaves) "i guess i'll just try to... be an alchemist and pay off my debts..." (SAVE POINT) at the beginning MC is unsure and doesn't know about your suggestions - "i guess i can look that up?", "maybe i'll try this?" because the player is guiding them. towards the end MC responds as though teaching the player fairy, like "that's right, that'll work!" and "good job, yeah!" to communicate that the MC is more confident and getting their mlemory of alchemy back the town generally ddoesn't like the alchemisst just because she's been kindda nasty and rude at times, just petty disagreements that have boiled over. she's known to be a decent alchemist though i guesss endgame is that you rally the town together to break free of the loan shark; it's hard too convince townsfolk both because they don't like you at first and also because the loans ARE legitimate. but it turnss out that the rest of the town also has debt to the shark and if you convince everyone you can both 1. achieve independence from the supplies he sells (maybe he's the intermediary with the trader? or buys and ressells everything at a markup?) 2. convince people to just reject the loanss/debt; quesstion here of whether they do this by force, whether cops exist, idk, this is explicitly passtoral fantasy. maybe at the end the player will muse about whether it's good to have mob rule, "no one in toown liked me, what if they threatened to burn down my shop?" "yeah, that would suck. maybe we could build something. but right now rule by mob is better than rule by loan shark!" idk this feels overly didactic but you get the idea this is really getting into the weeds of how we view the justice system but maybe he threatens to say "i'll send for the king's knights!" and the crowd is like "you can do that if you want, but by the time they get here your house will be burned down. alternately, you can keep your house and try to be friendly. maybe even contribute to the town. it's up to you. burn down your storehouse or genuinely connect with people?" definitely overly preachy but i like that :: .info.pod b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTA0LTIzIDAxOjEzOjI4IixydW50aW1lPTUsc3RvcmVk PSIyMDI0LTA0LTI5IDE3OjUwOjIxIix3b3Jrc3BhY2VzPXt7bG9jYXRpb249InNfc2hvcC5sdWEj MSIsd29ya3NwYWNlX2luZGV4PTF9LHtsb2NhdGlvbj0iZ2Z4LzAuZ2Z4Iix3b3Jrc3BhY2VfaW5k ZXg9Mn19XV1sejQABAAAAAMAAAAwbmls :: [eoc]