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-23 02:42:09",revision=695]] 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) if DEBUG then rect(object.left, object.top, object.right, object.bottom, 8) end 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 NC0yMyAwMzoxOTo0NSIscmV2aXNpb249MTI2NF1dbHo0ANMdAAAZZwAA8Rp7WzBdPXtibXA9cHh1 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 vQbwAwadBvAFFl0W8AhWwBIVJQK8Id-2MPAPBv8aMAbwDgb_BgD-LlEwnxjwAAkAUw0GUAYNDAAS nQgAEGD8ARkDCgASthAAE5AYAE_gBvACCAAII2ZAEAA-UAYwCgAdUFbwA-Yw8gEfYy8CFB8yXQMn DzoA-----------------9nwI2CABPD-JL8U8ED_AvA8-gbwOT8V-gTwNz3_BfA1Tf4H8DNN-gjw Mk3_CvAwTf4L8C9dBQD4AE3_DPAuXf4N8C1N-g3wLgUAMwzwLwUAMQsPDwcAEDwmAPAMCTzwLBxN -gg88C4cPf4HLA8X8DFN-gULHAsMCQDwrAQMCwwLDPAzTb4tLg8ZHAsc8DNdjj0uGjzwNV1ObR4q PPA2-QFKPPA3zXos8DkKTdoc8Dv6AwzwO5oMivA7amx68DpafHrwOVofHAxpavA4WqlaOfA0WslK OfA0SgDpKknwMyogmS8QKQpZ8DQKSEn4BPAw_BHwLmgPCvgM8CtoFygn_AfwKfgDNzgXqPAoJ-gM B7jwIgf4EieI8CH4FgeI8CD4GAd48CD4GSc48B-4IfAf_CLwHfggBxgGAPEHFxjwHPghByjwG-gl 8Bv4JvAaKAn4IgYA8CMOCfgE8BoYCfgOGSgJ_ADwGRgJ_A8ZGAmYB1jwGAgZ_BAJKAmIB1jwGQn4 ERkoCRgJWBkAVAn4Eik4CwDxAhQZGBlYF1jwFwn4FRkIGWgHCwCBGBno8BYJ_Bk_AGQUGfgVGRgL AFAUCTgZ6AkAEBpyAIITGfgaGYgXOAkARvgA8BIIABEbiACBEQn4HAmoB0gJACQZmAkAsPgB8BAZ _BspqAc4CQCmHBm4BzjwDwn4HQkAocgHGPAQCfgcKdhOACApyGUAMBOpuH0A8AEPSXgZqPAVGfgO GbgZiPAXQgDyAQggGPAaKfgbGQjwHyn4HAkHABAZBgDwJBo5DwzwHin4GFkG8B8Z_BdpLfAdGfgU aQYJTfAcGfgReQZt8B4J_A6ZbRXwHhn4CpmNJQgAUAapFm1VCQDyQgK5Fn2F8B4ZyMkGjcXwHgmY uc3V8B8JWKnd9QLwH8kGzfUFAAXwHpkVjfUN8B5prfUPAAXwHQ0ZvfUV8Bvd9RjwGY0FDfUc8Bkt 9STwGT0FDQIAovUc8Bgt9SbwFy0QAEMFDfUdEgAGJACkHvAVPfUo8BQtFRIAhiDwFC31KvASJACF IvASLfUs8BASAAEUAIUQLfUsAAXwD14AABYAmQ8G8A899SoAFRgAA1gAiw8t9S0ABfAM7wNuLTI5 LjEwHTlIMzguNzQ5D5ZDAAEEBPEt---DbxTwRe7wPD8Vfile8Dhdjile8Dc9DkluCW7wNj0OWe7w NT0OaW4KbvA0HT5p7vA0DU5Z-gDwNG5JBgDwhClurxnwNN7c8DQZjvwB8DQZbvwDEB8P8DAZXvwD EBvwMRle-AILACvwMW6c2-Axbozb8DJejJsfHyvwMl58iyg78DJebEsIGygnG-AzXlwrOEsfDgcL 8DReLB8XGyhLCBsfDivwMx57HxcYCxcPDisYW-AzDpsPFwsnHw47GEvwMx5LHxdLFx8OSwhL8DM_ Ky8XuxYA8CcNTgwLFrsIW-AzPR4s6xgr8DM9DhwALKsoO-AzLQ5siyhLHxzwNYxrGFsGDxAfHPA0 jADLBi8KAPJJMqyrFgU-EBXwMQwAfKsGG0Ql8DCc20QVFPAvrMtEJZTwJ4xFixUkRaTwJIwFNBV7 JQQF9AHwInwVRCV7JfQBFfAgfAWEBWsl9AMF8CBsBZQFaxr0BfAgXAoA8UEG8B9cBZQVawoF9Abw HkwABZQVWw8MCgX0B-AeLAAldAUEFTsTGvQH8CEVBBVkBRQFSgUapAW08B8VChQlRAUUGlQKpAXE 8BwVAwpEJSQFpA4A8AYaFQQKdCUEBbQKlAXU8BgVxCXECoQKAFAFAwrEFQwA8Ark8BYFAwr0FwX0 APAVBQr0GBX0APATFfQaCABgEgX0EgqECgDzABEF9BMKdAAF9ALwDwX0FAsAcA4F9BUKZBALABAN CwARdAsAQQwF9BYhADQD8AsLAKEE8AoF9B8AFfQDCQAQEB0AMgr0IAgAUNQV9BAQGwDyAQgF5AX0 CApkIBX0AvAI9AANADIl9AENAIUJCkQQFRQl5A4AQQAVRAUOAGAV9AgKRAA6ATAI9AEbAB80DQAC wRX0DQAF9AXwCPQDBQsAMwTwCQsAUAQq1PALDACADCAaBBq08AwMAMAICiQQCjQalPAN9AJjAKAk AApUCoTwDvQCVwAADgBAGmTwDw4AkgoKJBVUClTwEA0AYTQFVBo0BQ4A8QQEdfQBCjQFZAokBfAR 5FVkBfQADwCBFAXwEvQNBeQNAHAEBfATBfQMHACzJAVkCgXwFAX0CxUOAMHwFQX0DBrkCiQFClQN AHALOvQCevAXaQBgFFpE6-AYCgBSZBoU6xYLAIB0CgTbBivwGaUAVIQK6xYbFwBBywYrBg0AUQkK dArbDQASFyUAAA0AMQvwGAwAhGs-BTsGGwYLKQAxS2IrDwABUABEVBorgg8AUdS1WuIbDABiGgVk dfIOGADyEhtlbfIOOwYLAhvwGo0CDfISKwYLQvAZLfIcC2LwGT0CDQIAEPJIBVLyJfAYLRAAgAIN 8h7wFy3ySAUCEAABEgAwFT3ySAUUEhIAAEgFEPJIBQIQADACDfJIBRDySAUnAg0UAGUQLfIu8A9c AJ8CDfIk8A498i4oBSwPoAknD4gK-yAg-xTEGvEBfPQ--gEE-xU9BP4BBP08DgcAIDseBwBBLfQ3 LggATwT_NQQKAP80BFIBIfQ4YgExHfQ6cQFyDfQ9-gH0P70wMf--6JQBH-2TAf92H1z2GyID5gny KxjfFvBALr8PHvA9Lu0e8Dse-QIO8Doe-QMe8DkO-QMfEQ4N8DUcHs18DhzwMRwAHA7dDA0cDVzw MUwKAPYGHA0MDgzwMQwgHv0BDD0MDvA2Dv0IBgBgLU4dTm0uDwCwBR4NDvA3Dl0O-QAIAEBNHv0B IQBRPR49Ds0qAFAeTQ69HgkAUA5dDp0KLQDwDR4dPi0OjQou8DgOTU6dCg7wOR79BA7wOg5NPq0H APGALQ5tDm0e8DsOHR5NHl0_8DoeHX5NHh0u8Dk_QH5NHvBBHs0ODQLwPx7NDxhi8DourQtyG-A5 Dp0bYjvwNAs_nQtiGw0r8DICCw0enRtSGz0CC-AwEgu9G1IbXQIL8CwNCyIbrQtSG30CC-AqHQsy G30rQhudAgsC8CgdC1IrPRtiC70bAvAnHQtyW2IbzQsLAPIA8gQb3RvwJi0L8gMb7QILCgCwC-0A G-AlPQvyAhsKAPAEAggX8BA9C-IBG-0CC-ACCDfwDg4A8QAL-QML8AMIN-ANPQvyABsOAEAYR-AL DgBQC-0CDg0eAGAHGDfwCU0SADFNDr0TAEwYBxgnEwBIAFfwCBIAYQQIEFfwBxIAIz0eEgByIEcA LxXwAxUAIg7NFQA5MEcpEwCwAvADCDA3KQ3wAl2UABUtFQBwQAdJHfABXbcAUB0ezQ4bPABBWa0g vREAIQ7dEQBJIEn9DBAAMCn9DhAA0hIO3Q4CC-AK-Q8L8gQMADoL-Q4MABEFCwBUDI0g-QENAPQK DW3wBBvyBc0eAgvwDk3wBQvyBs0OEgvwKAkAcB0OvfIFvR4KAPACXhBObcLNDiIL8CANAG69ct0L APEMGmVuC-0RHiIL8BYVDkVOEC4L-REOMgvwFYWeCgDwTfAWhU4AHhAL-RAeIvAXhW4tC-0PHjIA C-AV1R0Q-REOQivwFLVgC-0NLjJL8BNlECVgCxL9CS6SK-AShYALMv0EPtIb8BFVsAti3T7yAhvw EFWwC-ICPvIGK-AOCwAiHRsIAEAeG-ANCAAgHwsIAKbyIBvwDFWg8iILBwBgsPIhG-ALJABnIBvw C2WgCAA-C-AMCAABAEwAAAgAYR4L8A9VoGwAAQgAEByHAPAAoAvyGxvwEUXAC-IZG-ASCABAGBvw EwgAQBcb8BQIAEEVK-AVCAA-C-AXCAANITXQCABvFkXgC-IUCAAUIxMbCABPCxLwFQkADR8bRAAA YvAA8hTwFwcAHwPyBBUPyAgnDzoA---------------3UG09NX19 :: gfx/.info.pod b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTAzLTI5IDAxOjE0OjUxIixzdG9yZWQ9IjIwMjQtMDMt MjkgMDE6MTQ6NTEiXV1sejQABAAAAAMAAAAwbmls :: library.lua --[[pod_format="raw",created="2024-04-10 00:24:20",modified="2024-04-23 03:19:45",revision=180]] 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-23 03:19:45",revision=1131]] -- 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 = {} 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) 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-23 03:19:45",revision=358]] 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-23 03:19:45",revision=394]] -- 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(hide_fairy) 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 if not hides_fairy then self.fairy:draw() end draw_door(door_open) for idx, box in ipairs(self.tray_slots) do if collides(self.fairy, box) then end end 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 PSIyMDI0LTA0LTIzIDAzOjE5OjQ1Iix3b3Jrc3BhY2VzPXt7bG9jYXRpb249Im1haW4ubHVhIzUy Iix3b3Jrc3BhY2VfaW5kZXg9MX0se2xvY2F0aW9uPSJsaWJyYXJ5Lmx1YSM2Iix3b3Jrc3BhY2Vf aW5kZXg9MX0se2xvY2F0aW9uPSJzX3Nob3AubHVhIzMwIix3b3Jrc3BhY2VfaW5kZXg9MX0se2xv Y2F0aW9uPSJzX2RyYXdlci5sdWEjNjQiLHdvcmtzcGFjZV9pbmRleD0xfSx7bG9jYXRpb249Imdm eC8wLmdmeCIsd29ya3NwYWNlX2luZGV4PTJ9fV1dbHo0AAQAAAADAAAAMG5pbA== :: [eoc]