picotron cartridge // www.picotron.net version 2 :: gfx/ :: map/ :: sfx/ :: 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 :: art.lua --[[pod_format="raw",created="2024-03-31 01:52:08",modified="2024-04-17 14:41:47",revision=674]] 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) 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-17 14:41:47",revision=671]] 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-10 01:58:59",revision=384]] 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(30*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:move() 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 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 NC0xNyAxNDo0MTo0NyIscmV2aXNpb249MTE4N11dbHo0AOIcAAASZAAA8Rp7WzBdPXtibXA9cHh1 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 Go5VAG_OCvAFqqCVBiXg8P8AOvAMCh8TGvAIOi7BAPAiHgAuOvAFCi4AThrwAiouJD4K8AIKFA4A DgQQHgAa4DoALgAEDxQzCvAACi4AHiQNPgoAUQAuEAMkCgDgICQQFBAq8AAKHhQANCOwAKBeJBAa 8AEKfhQeSgAhLkAIANIaYBQQSuAK7xgK4ArsBAChGswa8AAKzArwAQUAfxqsGvACypDZACfwDl1K 8AZaLxMK8AYKTgQeCvAGGh4TBBMq8AUKIA5DOgHwByAeBD4a8AMKLhAELgAOCvADCkMkEwCdABAw ugBAAgoOQ7sAsAIKDgMODxQuFA4AdQEwEB0QwgDTBAogDRAUEDrwAQrGCgUAIBqmLgAQpiYAEIZh ABCGAQIfhqABJ-1iYGAE-x4P-xUS-x4j-xUo-x4R-xU2-x4G-xU_3x7-FUZ-Hv8VSj8e-xUM8Bj_ Cg8e-gHwMP4FBT7wPD4FnhUO8EAOFZ518DZ1rvUE8Bz1BM71Qv4A9T7_BPU6-gv1MP4c9Rj_Ch3_ Th3_Ti3_TE3_Sl0DAE9N-kw9AwAEES05AAUDACAN-k8DNP81DREABVkABTIAAmIAQW3_SH0DAPtY jf5Gnf5Grf5Ezf5C3f5C7f5A-QH_Pv0C-j79A-48-QX_Ov0H-jj9Cf42-Qv_NP0N-jL9D-4w-RH_ Lv0T-iz9Ff4q-Rj_Jv0b-iT9Hv4g-SH_Hv0k-hr9Kf4U-S7_EP00-gj9Pd79GXoBdC01LjE1ODMB AASEAVcxNC44MBcAAY4BGTOOAfAnQEAE8P9aIh8Y8CZCXvAgQq7wG0L_AfAWMv4CIh7wEEL_AUJe 8ApC-gIyrvAFQv4CQv4A8AEiCADwPQbg-gFCfni_0M4yToheGL7AfkJOSO4YrsBOIn4oPvgBvrDe mL4YDhi_oB4CnjjuSB4YzpAeAgeOCB4YrjheCO6AHgIHfhguGH4ofhgNANAPDwduCE4YTih_KP4A HQBgDX4IThgeDwDwGgKAHgIdB24IXjhuOP4DoB4NBw1uGF4YLlj_AgcdwB4dB27I-gMHPRfAGgDy BP4UBy03HcAuHQf_Dwc9Nw0aFw4YAHANLUcdSi6wGQCRCB8OHUctah7QGQDwCAVsFy0nDkoO8AEe HQf_AD1cLRdOKvAEHADwBc4tNywtF37wBy4dfgc9Vy0nfvALGABgPgctBxs3DwAQDg8AQAc9B1sN APEdEh4tJ3snfvAVHg1He37wGC4NJx1bXvAbPgcdFyte8B8uF47wIq7wJm7wKx6qBR-kQwMJFjFD Ax80tQEdMG7wCbUBMc7wA7UBIQLgtAHyIgjA-gFC-g6wzjLOuL6QfkJ_mF5YvoBOIp44bqgOGM5w 7jgeeF4YLhjecB4CnniuKD60AQCnAVGeKE4o3g0AowheCG4YTjjOF6C1AZBuGB4oLkjOR6C1AfAD B144Xojed6AeAh0Xjoj_ApewIQGzF-4Qx8AeHSf_C6enAUIX-ge3qAGGJ-4DJx8OZy2rAVQn3jdc F64BRjeOZ2ytAUY3Tqd8rgEo9wGtARbHrQEXh6wBGUerAS8XLasBXvAm2W8b8Bn_CPAS-g7wDf4U 8Aj_GPAG-gx6bvAE7tr_APADfmr_DvAC-h-wAP4h4A4K-gd6-gAIAPEgAGpeCv4C0A4K-gEafhr_ A9AK-gQaTgr_BsAK-gYaHgr_CLAK-gga-gmwCg4K-iEGAPYKIqAeCv4Reo6gDgr_A_r_AaAOCq56 -hCgDiMAICDABgBAGgceB2UA8AcO9wLgCg4KTvcD-w8H0AoOCh79BvcGEwBwDvcG-QjQGhAAEAf8 BiD3HQYA8Qv9HuAKLvcbHvAAXof_Adcu4P4h8AD_AoD_BCcBP---fSkBJvAvFz8b8Cl_8CPe8B7_ A-AY-gAqXvAS-gE6jvAO-gE63vAK7kr_A-AHzjr_CfAFnjr_DfAFbir_ACru8AP_BVonAWHwAf4C Om4JAPADDgrOKp4K-gPwAA4K7jpeCv4ECgCB-gM6Hgr_BeA4AdAG4Ar_Fip_0Ar_EUqu_wBR-gs6 -gEeAfAFBkr_BcAeCv4BSv4J0A4K3jr_CDdAAGGuKv4Gp_BNAVEM9wHwACwAIPcILwGv-gD3DuAO Cq73FVABcSFgEEAA_wtw-xIY8Bz_MPAK-jzwAv5A8AX_NvAX-hzwaVYAJy00JAo0MS40qREfM1YA B-8F7j8d-h3wCv4FPf4TPb7wAv4uPd5gADPwBhIPHQAeAA7gXx7wM-8SBn8enxIADgIA-x3wFk0P Hm0OLQ4dDs0OXA79BvAKjUx9Dv0CXq0OHR4dDp3wAv1A8AX9NvAX-YQAKvEPpw8e8E8OIA7wRw4g DhAO8EkOcA7wKD7wEg7wKF4g-wD-Fi1e-SfwCp0_rW59cv0M8AL9ATL9BXJdUv0C8AX9InK98Bf9 FlKEACkRJoQA8DUQDvBPDvBIDhAPEiAO8EgeDXAO8EMNQB0gDgANwE3wNB4dAA0gjS79DBBN8BVN AA7NTv0X8AqdDg0ePRJdTo2SbRL9AZ0A-woi-QSSTXL9AfAFnRL9FRIeAi4SrfAX-RViowAp8Ar- WC8e8BEW8ClO8EMPElAeBz5N8D1tbv0KjQDxGi0yHRKNTk1CLUJtHr3wCn3CXS5NMg3SHR4CDUKt 8ALNgl1CbZJNIh4ilQCPIv0HQi1yPiKVAC7wSHMfHnAe8EYO8BQm8B0u8B0m8B8O8AMO8Ew_8AkW 8CIeUC7wRh4wLxIODZAe8AMW8CINUA4tDg0OTfA9zQ4dIk1iXT4ATfAVog0ijQ6yDWItXiJtICLw BL8A8xESLQ7yAl6CHULwAo2yLj1yDS6STQJeUr3wBZ0yXQK9csAAfz0yTVIdgm3FACmhmibwTSbw rhbwRgUC8UtAFvAqMg8S8AkO8CkNANItAFIwIg4wQtAy8BN9ok1iHQ4CHTIAHS6AIvAAElCyDiIt 0h4iDfIDLj0QQvAB8gFOQj8TIi0SPlI_8gnwAo3yCzxiPD1yDjIdUj27AP8CEq1yLSI_Ag5SPR5N 8Bc98gq8ACrwSPovFvBNLvCtBgXwIgaABmA-HjAG8A0y8BtCQF1gMoAFBpBCwBLwBA8SANIcXfID sFLAMvAALQzyAF1yDBIccgwyMELwAFIQoi0SDOI9EgxPEy1SK3IMYskA-x5NQjsSK_I98gjwAQwi DBIc4jtyWyJbPbJbYvAFPPIXDPIBHDIs8BcSHPIKHLLDACjzExpPHpAe8LsuAC8W8CFeoA7wAy4w LfA2HhAO8EQegA4ATrDdAPQHMB4ADhAOMAZe8AcywDLQXlBCYA4AHuYA8Q9CsH6iLgIOMg5CflKw UsCyMB4HXgJe8gMOB25iDxLoAMDijgxiPxOiK44SazLkACDibuMA8RJiKyJ_8gbwAXIbUk4iW1Jb Ijtegoti8AVSO-ICe-ICC1LnAB-y4wQp8Tk4BTAF8Es18EtF8Hs-HvAeFfAarjAG8AoG8AgfE5BN oC4XbmAG4F6gFaAtAg2wMoAuB54gQsCOMD7AQsBCcB4HroIuAg4iXgfaAOCCLQD_A_IeB54CDTI_ EtgA8B3CzlI9Em0C3gJtMg1i8AESLXKubRItYi0CnlJNovABch0yfgJtUl0iPV6CjdkA-wE9DvIB 3bINQp3wF3JN8gRNOgUlD7UgGg86AP---------------------------------------------- -yTwI2CABPD-JL8U8ED_AvA8-gbwOT8V-gTwNz3_BfA1Tf4H8DNN-gjwMk3_CvAwTf4L8C9dBQD4 AE3_DPAuXf4N8C1N-g3wLgUAMwzwLwUAMQsPDwcAEDwmAPAMCTzwLBxN-gg88C4cPf4HLA8X8DFN -gULHAsMCQDwrAQMCwwLDPAzTb4tLg8ZHAsc8DNdjj0uGjzwNV1ObR4qPPA2-QFKPPA3zXos8DkK Tdoc8Dv6AwzwO5oMivA7amx68DpafHrwOVofHAxpavA4WqlaOfA0WslKOfA0SgDpKknwMyogmS8Q KQpZ8DQKSEn4BPAw_BHwLmgPCvgM8CtoFygn_AfwKfgDNzgXqPAoJ-gMB7jwIgf4EieI8CH4FgeI 8CD4GAd48CD4GSc48B-4IfAf_CLwHfggBxgGAPEHFxjwHPghByjwG-gl8Bv4JvAaKAn4IgYA8CMO CfgE8BoYCfgOGSgJ_ADwGRgJ_A8ZGAmYB1jwGAgZ_BAJKAmIB1jwGQn4ERkoCRgJWBkAVAn4Eik4 CwDxAhQZGBlYF1jwFwn4FRkIGWgHCwCBGBno8BYJ_Bk_AGQUGfgVGRgLAFAUCTgZ6AkAEBpyAIIT GfgaGYgXOAkARvgA8BIIABEbiACBEQn4HAmoB0gJACQZmAkAsPgB8BAZ_BspqAc4CQCmHBm4Bzjw Dwn4HQkAocgHGPAQCfgcKdhOACApyGUAMBOpuH0A8AEPSXgZqPAVGfgOGbgZiPAXQgDyAQggGPAa KfgbGQjwHyn4HAkHABAZBgDwJBo5DwzwHin4GFkG8B8Z_BdpLfAdGfgUaQYJTfAcGfgReQZt8B4J _A6ZbRXwHhn4CpmNJQgAUAapFm1VCQDyQgK5Fn2F8B4ZyMkGjcXwHgmYuc3V8B8JWKnd9QLwH8kG zfUFAAXwHpkVjfUN8B5prfUPAAXwHQ0ZvfUV8Bvd9RjwGY0FDfUc8Bkt9STwGT0FDQIAovUc8Bgt 9SbwFy0QAEMFDfUdEgAGJACkHvAVPfUo8BQtFRIAhiDwFC31KvASJACFIvASLfUs8BASAAEUAIUQ LfUsAAXwD14AABYAmQ8G8A899SoAFRgAA1gAiw8t9S0ABfAM7wNuLTI5LjEwFTVIMzguNyw1D49A AAEEBPEt---DbxTwRe7wPD8Vfile8Dhdjile8Dc9DkluCW7wNj0OWe7wNT0OaW4KbvA0HT5p7vA0 DU5Z-gDwNG5JBgDwhClurxnwNN7c8DQZjvwB8DQZbvwDEB8P8DAZXvwDEBvwMRle-AILACvwMW6c 2-Axbozb8DJejJsfHyvwMl58iyg78DJebEsIGygnG-AzXlwrOEsfDgcL8DReLB8XGyhLCBsfDivw Mx57HxcYCxcPDisYW-AzDpsPFwsnHw47GEvwMx5LHxdLFx8OSwhL8DM_Ky8XuxYA8CcNTgwLFrsI W-AzPR4s6xgr8DM9DhwALKsoO-AzLQ5siyhLHxzwNYxrGFsGDxAfHPA0jADLBi8KAPJJMqyrFgU- EBXwMQwAfKsGG0Ql8DCc20QVFPAvrMtEJZTwJ4xFixUkRaTwJIwFNBV7JQQF9AHwInwVRCV7JfQB FfAgfAWEBWsl9AMF8CBsBZQFaxr0BfAgXAoA8UEG8B9cBZQVawoF9AbwHkwABZQVWw8MCgX0B-Ae LAAldAUEFTsTGvQH8CEVBBVkBRQFSgUapAW08B8VChQlRAUUGlQKpAXE8BwVAwpEJSQFpA4A8AYa FQQKdCUEBbQKlAXU8BgVxCXECoQKAFAFAwrEFQwA8Ark8BYFAwr0FwX0APAVBQr0GBX0APATFfQa CABgEgX0EgqECgDzABEF9BMKdAAF9ALwDwX0FAsAcA4F9BUKZBALABANCwARdAsAQQwF9BYhADQD 8AsLAKEE8AoF9B8AFfQDCQAQEB0AMgr0IAgAUNQV9BAQGwDyAQgF5AX0CApkIBX0AvAI9AANADIl 9AENAIUJCkQQFRQl5A4AQQAVRAUOAGAV9AgKRAA6ATAI9AEbAB80DQACwRX0DQAF9AXwCPQDBQsA MwTwCQsAUAQq1PALDACADCAaBBq08AwMAMAICiQQCjQalPAN9AJjAKAkAApUCoTwDvQCVwAADgBA GmTwDw4AkgoKJBVUClTwEA0AYTQFVBo0BQ4A8QQEdfQBCjQFZAokBfAR5FVkBfQADwCBFAXwEvQN BeQNAHAEBfATBfQMHACzJAVkCgXwFAX0CxUOAMHwFQX0DBrkCiQFClQNAHALOvQCevAXaQBgFFpE 6-AYCgBSZBoU6xYLAIB0CgTbBivwGaUAVIQK6xYbFwBBywYrBg0AUQkKdArbDQASFyUAAA0AMQvw GAwAhGs-BTsGGwYLKQAxS2IrDwABUABEVBorgg8AUdS1WuIbDABiGgVkdfIOGADyEhtlbfIOOwYL AhvwGo0CDfISKwYLQvAZLfIcC2LwGT0CDQIAEPJIBVLyJfAYLRAAgAIN8h7wFy3ySAUCEAABEgAw FT3ySAUUEhIAAEgFEPJIBQIQADACDfJIBRDySAUnAg0UAGUQLfIu8A9cAJ8CDfIk8A498i4oBSwP oAknD4gK-yAg-xT-NfEBfPQ--gEE-xU9BP4BBP08DgcAIDseBwBBLfQ3LggATwT_NQQKAP80BFIB IfQ4YgExHfQ6cQFyDfQ9-gH0Pw8_Mf--6JQBH-2TAf92H1xiAxQfMuYJAfIrGN8W8EAuvw8e8D0u 7R7wOx79Ag7wOh79Ax7wOQ79Ax8RDg3wNRwezXwOHPAxHAAcDt0MDRwNXPAxTAoA9gYcDQwODPAx DCAe-QEMPQwO8DYO-QgGAGAtTh1ObS4PALAFHg0O8DcOXQ79AAgAQE0e-QEhAFE9Hj0OzSoAUB5N Dr0eCQBQDl0OnQotAPANHh0_LQ6NCi7wOA5NTp0KDvA5Hv0EDvA6Dk0_rQcA8YAtDm0ObR7wOw4d Hk0eXT7wOh4dfk0eHS7wOT5Afk0e8EEezQ4NAvA-Hs0PGGLwOi6tC3Ib8DkOnRtiO-A0Cz6dC2Ib DSvwMgILDR6dG1IbPQIL8DASC70bUhtdAgvwLA0LIhutC1IbfQIL8CodCzIbfStCG50CCwLwKB0L Uis9G2ILvRsC8CcdC3JbYhvNCwsA8gDyBBvdG-AmLQvyAxvtAgsKALAL-QAb8CU9C-ICGwoA8AQC CBfwED0L8gEb-QIL8AIIN-AODgDxAAv9AwvwAwg38A09C-IAGw4AQBhH8AsOAFAL-QIODR4AYAcY N-AJTRIAMU0OvRMATBgHGCcTAEgAV-AIEgBhBAgQV-AHEgAjPR4SAHIgRwAvFfADFQAiDs0VADkw RykTALAC8AMIMDcpDfACXZQAFS0VAHBAB0kd8AFdtwBQHR7NDhs8AEFZrSC9EQAhDt0RAEkgSf0M EAAwKf0OEADSEg7dDgIL8Ar9DwvyBAwAOgv9DgwAEQULAFQMjSD9AQ0A9AoNbfAEG-IFzR4CC-AO TfAFC-IGzQ4SC-AoCQBwHQ698gW9HgoA8AJeEE5tws0OIgvwIA0Abr1y3QsA8QwaZW4L-REeIgvw FhUORU4QLgv9EQ4yC-AVhZ4KAPBN8BaFTgAeEAv9EB4i8BeFbi0L-Q8eMgAL8BXVHRD9EQ5CK-AU tWAL-Q0uMkvwE2UQJWALEv0JLpIr8BKFgAsy-QQ_0hvwEVWwC2LdPvICG-AQVbAL8gI_8gYr8A4L ACIdGwgAQB4b8A0IACAfCwgApvIgG-AMVaDyIgsHAGCw8iEb8AskAGcgG-ALZaAIAD8L8AwIAAEA TAAACABhHgvwD1WgbAABCAAQHIcA8ACgC-IbG-ARRcAL8hkb8BIIAEAYG-ATCABAFxvwFAgAQRUr 8BUIAD8L8BcIAA0hNdAIAG8WReAL8hQIABQjExsIAE8LEvAVCQANHxtEAABi8ADyFPAXBwAfA-IE FQ-ICCcPOgD---------------dQbT01fX0= :: gfx/.info.pod b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTAzLTI5IDAxOjE0OjUxIixzdG9yZWQ9IjIwMjQtMDMt MjkgMDE6MTQ6NTEiXV1sejQABAAAAAMAAAAwbmls :: library.lua --[[pod_format="raw",created="2024-04-10 00:24:20",modified="2024-04-17 14:41:47",revision=104]] 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"}}, } 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-17 14:41:47",revision=1056]] -- 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-17 14:41:47",revision=92]] 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) if self.fairy ~= nil then self.fairy:draw() end 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) 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-14 20:06:16",revision=296]] DrawerScene = { extension = 0, behind = nil, inset = 60, } 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 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 end function DrawerScene:update() if btnp(5) 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 end function DrawerScene:draw() self.behind:draw() draw_drawer(self.extension, self.inset) 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-17 14:41:47",revision=279]] -- 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 = {} 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(16, 240-100, 135-49) palt(30, false) palt(0, true) spr(21+flr(2*t()%11), 240-100, 135-52) -- countertop! draw_counter(20) if collides(fairy, book_1) then spr(18, book_1.left, book_1.top) else spr(17, book_1.left, book_1.top) end if collides(fairy, book_2) then spr(20, book_2.left, book_2.top) else spr(19, book_2.left, book_2.top) end if customer_visible then bob(customer_sprite, 240-96, 7, 96, 128, customer_bob) end if not hides_fairy then fairy:draw() end 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() fairy:move() cabinet:update(fairy.x, fairy.y) if btnp(4) then local glow = Glow:new(fairy.x, fairy.y) glow.start_color = 7 glow.end_color = 12 add(animations, glow) local drawer = cabinet:drawer_at(fairy.x, fairy.y) if drawer then change_scene(DrawerScene:new(drawer)) end if collides(fairy, book_1) then change_scene(BookScene:new(007, book_pages[1])) end if collides(fairy, book_2) then change_scene(BookScene:new(012, book_pages[2])) end end if btnp(5) then add(animations, Glow:new(fairy.x, fairy.y)) if cabinet.hover_plant ~= nil then change_scene(Conversation:new(get_conversation(cabinet.hover_plant))) 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-03-29 01:14:51",modified="2024-04-05 14:54:05",revision=1117]] -- 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) fairy:draw() -- countertop! draw_counter(14) if customer_visible then bob(customer_sprite, 240-96, 7, 96, 128, customer_bob) end 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() 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 :: [eoc]