diff --git a/atelier2.p64 b/atelier2.p64 index 2a9d0ae..9a18e92 100644 --- a/atelier2.p64 +++ b/atelier2.p64 @@ -4,6 +4,1009 @@ version 2 :: gfx/ :: map/ :: sfx/ +:: 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 +:: screen_drawer.lua +--[[pod_format="raw",created="2024-04-05 00:59:25",modified="2024-04-05 00:59:26",revision=1]] + +:: 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 +:: art.lua +--[[pod_format="raw",created="2024-03-31 01:52:08",modified="2024-04-12 14:41:51",revision=629]] +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-14 02:34:28",revision=631]] +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 +:: 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 +NC0xNCAwMzoyMjo1NiIscmV2aXNpb249MTEyMF1dbHo0AJgZAABjXQAA8Rp7WzBdPXtibXA9cHh1 +AEMgEBAE8PAsZmxhZ3M9MCxwYW5feD0wLjM3NQwA_wJ5PS0wLjEyNSx6b29tPTV9LDoAkCR6cAoP +HU8eCgcAcD8ODx4KYBoJAP8CDRpQCh8dPw4dClAKDx1fDg0IAAT-Aw8eClAKDl8ODgpQCn4KUJrw +A4sAJqUGOrAKHxMKsAoeBADwAKAaHhqQCgMOEQqQCgMPEgcAPQ4dAQYArw4KkAo_CpBa8AV9ACYQ +Jn0AER1xAP8GYDoPFy46MAo9HxweHxIKMAodbxwPCAACIF8cIAD-ARodPxwODxIaQBpeGmB68ASE +ACJRCAgECQACABIQCAAfGQ4AFh8J9QAm-yAQLxyQPgAuUC4AHiAuEC4gLjAOEA4wHgBeEF5ALBos +YDwaPFAcEAogHIAa0ArwOWgAJccgLDAsUAwADDAMAAwIADAcEBwIABEQAgD-EVAcAAwQDAAcYCwQ +LIAcGhyQHxwaHpAeCgAegB4aEB6QfwAl8EnIZATw-7X-Dw-wG47wNf8YHf4V-RL_Bv0mcP0a-hn9 +D-4P-R9w-Rb_Hv0M-hr9FnD9D-4m-Qj_Je0_rXD9B-4w-QT_O51wnVf_Od3_QI1wnQf_P73_Qhdd +CgDyAECd-kQHXXCd-kJtDx-_RQsAYg0PFj0vHxkAaAf_Qh8WXw0ARW8f-kMNAE9-H-5CDQBeCYIA +Dw0AFAnDAA8NACETTx8BDw0AWk8-H-5GDQAqDlsADw0AwC-_QwwAT2FfH_7H-igOADAm594QAGGu +R74n-iUSAHAhV94Xbgc_FgBxfjf_Ayf_IhcAcBxXfieeF54XAHFeJ-4IJ-4gFwCQGEduZx4nfheO +GQBxThf_DCf_HhkAkBRHXleeJ24XfhkAcT4X-hA3-hoZAKARN15H-gIHbhduGgCRLhdu9wOuR-4V +HACQCPcE-gcXXhdeGwCyHhdON-4CN65X-hAmAaABZz5X-hEnThdOzwDBHhdOF25HvjfOR-4MIACx +TsdOV-4Hx04XPhe_APA_F04XXicuN75H3jf_CAddcK0uJ26n-gdXvhc_Fx4dFy4PFm8fBz4nXhd_ +J_433mf_AQddcL2ON-4Jh-4IBw49TlwOB84HvkfOR-4A9wDVAPspzT49Lv0Ap-0XLh087hcerT5n +nkf_DX1w-VMevQ4HHv0HV35n-gaNcP2BBz2eh86dcP2Zjt1w-bADAF-w----3z0FFBwxvAVQ-xQB +1B4CALAEuQQeBAk-Dxk9CQkAGp0GADEPFQ4IAIcMDgS5BAwO1AMAH_y4BSKfICAE-xQR9A4eAwAC +wDT5BjQeNAl-Dzl9CQkAMY0ZjQgAL-0EBwALMg8VDgkAHgwIAH-5BjQMDvQOBAASPx78DtYAJXLU +DxTwAdQOBAD-EsQe8AHEDvACtB7wAqQe8AOUHvAEdC7wBVQu8Adu8P--q2YAJf8J_TAg_gqA_QTQ +_gDwAdnwAtnwA7nw---8UAAlAEQCH-M9ACfwCKIq8A0KAwrwDBoDCvAISgMACvAICgMgCAAjBToI +AFAKAxADAAIAZBrwBAoAAwIAHwoOAApEAToAAwIA8A5KwAr-EgEKwCrOKuAKzgrwARquGvACCq4K +8AMajlUAb44K8AWqoMYAJ8AAOvAMCh8TGvAIOi7BAPAiHgAuOvAFCi4AThrwAiouJD4K8AIKFA4A +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-kw9AwAEES05AAUDADAN-v8BACQ1DREABVkABTIAAmIAQW3_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 +AASEAVcxNC44MBcAAY4BGTOOAfB0QEAE8P9bPxjwJq7wIe7wHf4E8Bj_BCge8BL_BEhe8Ar_Bziu +8AX_B0j_APAB-gVI-gbg-gFIfni_0M44ToheGL7AfkhOSO4YrsBOKH4oPvgBvrDemL4YDhi_oM44 +7kgeGM6QLgeOCB4YrjheCO6ALgd_GC4Yfih_GO6ALg8PB24IThg5ALD_AIAuBw1_CE4YHg4A8BkC +gC4dB24IXjhuOP4DoB4NBw1uGF4YLlj_AgcdwB4dB27I-gMHPRfAGgDyBP4UBy03HcAuHQf_Dwc9 +Nw0aFw4YAHANLUcdSi6wGQCRCB8OHUctah7QGQDwCAVsFy0nDkoO8AEeHQf_AD1cLRdOKvAEHADw +Bc4tNywtF37wBy4dfgc9Vy0nfvALGABgPgctBxs3DwAQDg8AQAc9B1sNAPAdEh4tJ3snfvAVHg1H +e37wGC4NJx1bXvAbPgcdFyte8B8uF47wIq7wJm7wKx6YBS--5DMDCRYxMwMfNKUBF5Bu8An_BzjO +8AOlASAC4KQB8SAIwP4BSP4OsM44zri_kH5IfpheWL6ATiieOG6oDhjOcO44HnheGC4Y3nDOeK4o +PqQBAJgBUJ4oTijeDACiCF4IbhhOOM4XoKUB8A5uGB4oLkjOR6AuBw0HXjheiN53oC4dF46I-gKX +sBEBsxf_EMfAHh0n-gunlwFCF-4Ht5gBhif_AycfDmctmwFUJ943XBeeAUY3jmdsnQFGN06nfJ4B +KPcBnQEWx50BF4ecARlHmwEvFy2bAV7wJtlvG-AZ-gjwEv4O8A3_FPAI-hjwBv4Mem7wBO7a-gDw +A35q-g7wAv4f8AD_IeAOCv4Hev4ACADxIABqXgr_AtAOCv4BGn4a-gPQCv4EGk4K-gbACv4GGh4K +-giwCv4IGv4JsAoOCv4hBgD2CiKgHgr_EXqOoA4K-gPq-gGgDgquev4QoA4jACAgwAYAQBoHHgdl +APAHDvcC4AoOCk73A-8PB9AKDgoe-Qb3BhMAcA73Bv0I0BoQABAH3AYg9x0GAPEK-R7gCi73Gx7w +AF6H-gHXLuD_IfAA-gKA-loIT----30pASbwLxc-G-ApfvAj3vAe-gPwGP4AKl7wEv4BOo7wDv4B +Ot7wCu5K-gPwB846-gnwBZ46-g3wBW4q-gAq7vAD-gVaJwFh8AH_AjpuCQDwAw4KziqeCv4D8AAO +Cu46Xgr_BAoAgf4DOh4K-gXgOAHQBuAK-hYqftAK-hFKrvsAUf4LOv4BHgHwBQZK-gXAHgr_AUr_ +CdAOCt46-gg3QABhrir_BqfgTQFRDPcB8AAsACD3CC8Br-4A9w7gDgqu9xVQAXEhYBBAAPsLcP8S +GPAc-jDwCv488AL_QPAF-jbwF-4c8GlWAHYtMC4wMjUwAQAUNGMANDIuM2MAHzNjAAf-Be4-Hf4d +8Ar_BT3_Ez2_8AL_Lj3ebQBA8AYSDx0AHgAO4F8e8DP-EgZ-Hp8SAA4CAP8d8BZNDx5tDi0OHQ7N +DlwO-QbwCo1MfQ79Al6tDh0eHQ6d8AL9QPAF-TbwF-2RADfxD6cPHvBPDiAO8EcOIA4QDvBJDnAO +8Cg_8BIO8CheIBkB-xYtXv0n8AqdPq1ufXL9DPAC-QEy-QVyXVL9AvAF-SJyvfAX-RZSkQA2ESaR +APA1EA7wTw7wSA4QDxIgDvBIHg1wDvBDDUAdIA4ADcBN8DQeHQANII0u-QwQTfAVTQAOzU79F-AK +nQ4NHj0SXU6Nkm0S-QGqAP8KIv0Ekk1y-QHwBZ0S-RUSHgIuEq3wF-0VYrAANvAK-1gvHvARFvAp +TvBDDxJQHgc_TfA9bW79CpoA8RotMh0SjU5NQi1CbR698Ap9wl0uTTIN0h0eAg1CrfACzYJdQm2S +TSIeIqIAjyL9B0Itcj4iogA78EhzHx5wHvBGDvAUJvAdLvAdJvAfDvADDvBMPvAJFvAiHlAu8EYe +MC8SDg2QHvADFvAiDVAOLQ4NDk3wPc0OHSJNYl0_AE3wFaINIo0Osg1iLV4ibSAi8ATMAPMREi0O +8gJegh1C8AKNsi49cg0ukk0CXlK98AWdMl0CvXLNAH89Mk1SHYJt0gA2oZom8E0m8K4W8EYsAvFL +QBbwKjIPEvAJDvApDQDSLQBSMCIOMELQMvATfaJNYh0OAh0yAB0ugCLwABJQsg4iLdIeIg3yAy49 +EELwAfIBTkI-EyItEj5SPvIJ8AKN8gs8Yjw9cg4yHVI9yAD-AhKtci0iPgIOUj0eTfAXPfIKyQAz +DysZK-8KPg8e4A6gDiAOsA7wBP8SEC59Qq1C-RDwAFIAeB-wOgD------------------------- +----------------------9M8CNggATw-yS-FPBA-gLwPP4G8Dk-Ff4E8Dc9-gXwNU3_B-AzTf4I +8DJN-grwME3_C-AvXQUA_ABN-gzwLl3_DfAtTf4N8C4FADMM8C8FADELDw8HABA8JgDwDAk88Cwc +Tf4IPPAuHD3_BywPF-AxTf4FCxwLDAkA8KwEDAsMCwzwM02_LS4PGRwLHPAzXY49Lho88DVdTm0e +KjzwNv0BSjzwN816LPA5Ck3aHPA7_gMM8DuaDIrwO2psevA6Wnx68DlaHxwMaWrwOFqpWjnwNFrJ +SjnwNEoA6SpJ8DMqIJkvDCkKWfA0CkhJ_ATwMPgR8C5oDwr4DPAraBcoJ-gH8Cn4Azc4F6jwKCf4 +DAe48CIH_BIniPAh_BYHiPAg_BgHePAg_BknOPAf_CHwH-gi8B34IAcYBgDxBxcY8Bz4IQco8Bv4 +JfAb_CbwGigJ_CIGAPAjDgn4BPAaGAn4DhkoCfgA8BkYCfgPGRgJmAdY8BgIGfgQCSgJiAdY8BkJ +_BEZKAkYCVgZAFQJ_BIpOAsA8QIUGRgZWBdY8BcJ_BUZCBloBwsAgRgZ6PAWCfgZPgBkFBn4FRkY +CwBQFAk4GegJABAacgCCExn4GhmIFzgJAEb4APASCAARG4gAgREJ_BwJqAdICQAkGZgJALD4AfAQ +GfgbKagHOAkAphwZuAc48A8J_B0JAKHIBxjwEAn4HCnYTgAgKchlADATqbh9APABD0l4GajwFRn4 +Dhm4GYjwF0IA8gEIIBjwGin4GxkI8B8p_BwJBwAQGQYA8CMaOQjwHin4GFkI8B8Z_BdpLfAdGfgU +aQgJTfAcGfgReQht8B4J_A6ZbRXwHhn4CpmNJQgAUAapGG1VCQDyQgK5GH2F8B4ZyMkIjcXwHgmY +uc3V8B8JWKnd9QLwH8kIzfUFAAXwHpkVjfUN8B5prfUPAAXwHQ0ZvfUV8Bvd9RjwGY0FDfUc8Bkt +9STwGT0FDQIAovUc8Bgt9SbwFy0QAEMFDfUdEgAGJACkHvAVPfUo8BQtFRIAhiDwFC31KvASJACF +IvASLfUs8BASAAEUAIUQLfUsAAXwD14AABYAiQbwDz31KgAVFwADVwCLDy31LQAF8AztA24tMjku +MTC4M0gzOC43zzMP8DkAAQIE8S3--8NvFPBF7vA8PxV_KV7wOF2OKV7wNz0OSW4JbvA2PQ5Z7vA1 +PQ5pbgpu8DQdPmnu8DQNTln_APA0bkkGAPCEKW6vGfA03tzwNBmO-AHwNBlu-AMQHw-wMBle-AMQ +G-AxGV78AgsAK-Axbpzb8DFujNvwMl6Mmx8fK-AyXnyLKDvwMl5sSwgbKCcb8DNeXCs4Sx8OBwvw +NF4sHxcbKEsIGx8OK-AzHnsfFxgLFw8OKxhb8DMOmw8XCycfDjsYS-AzHksfF0sXHw5LCEvwMz4r +Lxe7FgDwJw1ODAsWuwhb8DM9HizrGCvwMz0OHAAsqyg78DMtDmyLKEsfHPA1jGsYWwYPDB8c8DSM +AMsGLwoA8kkyrKsWBT8MFfAxDAB8qwYbRCXwMJzbRBUU8C_sy0QllPAnjEWLFSRFpPAkjAU0FXsl +BAX0AfAifBVEJXsl9AEV8CB8BYQFayX0AwXwIGwFlAVrGvQF8CBcCgDxQAbwH1wFlBVrCgX0BvAe +TAAFlBVbBAoF9AfwHiwAJXQFBBU7FBr0B-AhFQQVZAUUBUoFGqQFtPAfFQoUJUQFFBpUCqQFxPAc +FQQKRCUkBaQOAPAGGhUECnQlBAW0CpQF1PAYFcQlxAqECgBQBQQKxBUMAPAK5PAWBQQK9BcF9ADw +FQUK9BgV9ADwExX0GggAYBIF9BIKhAoA8wARBfQTCnQABfQC8A8F9BQLAHAOBfQVCmQQCwAQDQsA +EXQLAEEMBfQWIQA0A-ALCwChBPAKBfQfABX0AwkAEBAdADIK9CAIAFDUFfQQEBsA8gEIBeQF9AgK +ZCAV9ALwCPQADQAyJfQBDQCFCQpEEBUUJeQOAEEAFUQFDgBgFfQICkQAOQEwCPQBGwAfNA0AAsEV +9A0ABfQF8Aj0AwULADME8AkLAFAEKtTwCwwAgAwgGgQatPAMDADACAokEAo0GpTwDfQCYwCgJAAK +VAqE8A70AlcAAA4AQBpk8A8OAJIKCiQVVApU8BANAGE0BVQaNAUOAPEEBHX0AQo0BWQKJAXwEeRV +ZAX0AA8AgRQF8BL0DQXkDQBwBAXwEwX0DBwAsyQFZAoF8BQF9AsVDgDB8BUF9Awa5AokBQpUDQBw +Czr0AnrwF2kAYBRaROvwGAoAUmQaFOsWCwCAdAoE2wYr8BmlAFSECusWGxcAQcsGKwYNAFEJCnQK +2w0AEhclAAANADEL8BgMAIRrPwU7BhsGCykAMUtjKw8AAVAARFQaK4MPAFHUtVrjGwwAYhoFZHXz +DhgA8hIbZW3zDjsGCwMb8BqNAw3zEisGC0PwGS3zHAtj8Bk9Aw0CABDzRgVS8yXwGC0QAIADDfMe +8Bct80YFAhAAARIAMBU980YFFBMSAABGBRDzRgUCEAAwAw3zRgUQ80YFJwMNFABlEC3zLvAPXACf +Aw3zJPAOPfMuJwUsD50JJw_FCv8gIP8UwTTxAXz0P-4BBP8VPQT_AQT9PA4HACA7HgcAQS30Ny4I +AE8E-jUECgD-NARSASH0OGIBMR30OnEBcg30Pf4B9D_xPDH--_iUAR-9kwH-dh9cYgMUHzLlCQHy +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-10 01:58:59",revision=35]] +plant_descriptions = { +[-1]={{"i don't know what that is. where did you find this?"}}, +[14]={{"this is foxglove"}}, +} +function get_conversation(plant) + local id = plant[1] + return plant_descriptions[id] or plant_descriptions[-1] +end + +:: main.lua +--[[pod_format="raw",created="2024-04-02 02:59:37",modified="2024-04-14 03:22:56",revision=1000]] +-- 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(title_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-14 03:22:56",revision=27]] +BookScene = { + extension = 0, + behind = nil, + inset = 60, +} + +function BookScene:new(background) + c = {height=0, behind=nil, background=background} + + 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 +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 +end + +function BookScene:draw() + self.behind:draw() + + spr(007, 20, 135-self.height) +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 03:22:56",revision=281]] +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-14 03:22:56",revision=205]] +-- 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=80, right=144, top=100, bottom=164} + +shop_screen = {} +function shop_screen:draw() + cls() + + cabinet:draw() + + -- alchemist! + bob(alchemist_sprite, 0, 7, 96, 128, alchemist_bob) + + palt(30, true) + palt(0, false) + spr(16, 240-110, 135-36) + palt(30, false) + palt(0, true) + spr(21+flr(2*t()%8), 240-110, 135-39) + + -- countertop! + draw_counter(14) + + 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 + + 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() + 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)) end + if collides(fairy, book_2) then change_scene(BookScene:new(007)) 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 +:: 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 :: story.txt --[[pod_format="raw",created="2024-03-30 15:58:22",modified="2024-04-11 01:41:32",revision=208]] ATELIER HESTER @@ -182,938 +1185,11 @@ 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-12 14:41:51",revision=629]] -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-10 01:58:59",revision=627]] -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 -NC0xMiAxNDo0MTo1MSIscmV2aXNpb249MTA1MF1dbHo0AJQUAADWVQAA8Rp7WzBdPXtibXA9cHh1 -AEMgEBAE8PAsZmxhZ3M9MCxwYW5feD0wLjM3NQwA_wJ5PS0wLjEyNSx6b29tPTV9LDoAkCR6cAoP -HU8eCgcAcD8ODx4KYBoJAP8CDRpQCh8dPw4dClAKDx1fDg0IAAT-Aw8eClAKDl8ODgpQCn4KUJrw -A4sAJqUGOrAKHxMKsAoeBADwAKAaHhqQCgMOEQqQCgMPEgcAPQ4dAQYArw4KkAo_CpBa8AV9ACYQ -Jn0AER1xAP8GYDoPFy46MAo9HxweHxIKMAodbxwPCAACIF8cIAD-ARodPxwODxIaQBpeGmB68ASE -ACJRCAgECQACABIQCAAfGQ4AFh8J9QAm-yAQLxyQPgAuUC4AHiAuEC4gLjAOEA4wHgBeEF5ALBos -YDwaPFAcEAogHIAa0ArwOWgAJccgLDAsUAwADDAMAAwIADAcEBwIABEQAgD-EVAcAAwQDAAcYCwQ -LIAcGhyQHxwaHpAeCgAegB4aEB6QfwAaDx4DNVD-FAHUHgIAsAS5BB4ECT8PGT0JCQAanQYAMQ8V -DggAhwwOBLkEDA7UAwAf7HsAIp8gIAT-FBH0Dh4DAALANPkGNB40CX8POX0JCQAxjRmNCAAv-QQH -AAsyDxUOCQAeDAgAf-kGNAwO9A4EABI-HvwO1gAlctQPFPAB1A4EAP8SxB7wAcQO8AK0HvACpB7w -A5Qe8AR0LvAFVC7wB27w--_rZgAl-wn5MCD6CoD5BND6APAB2fAC2fADufD---xQACVf8P----M9 -ACfwCKIq8A0KAwrwDBoDCvAISgMACvAICgMgCAAjBToIAFAKAxADAAIAZBrwBAoAAwIAHwoOAApE -AToAAwIA8A5KwAr-EgEKwCrOKuAKzgrwARquGvACCq4K8AMajlUAb44K8AWqoMYAJ8AAOvAMCh8T -GvAIOi7BAPAiHgAuOvAFCi4AThrwAiouJD4K8AIKFA4ADgQQHgAa4DoALgAEDxQzCvAACi4AHiQN -PgoAUQAuEAMkCgDgICQQFBAq8AAKHhQANCOwAKBeJBAa8AEKfhQeSgAhLkAIANIaYBQQSuAK7xgK -4ArsBAChGswa8AAKzArwAQUAfxqsGvACypDZACfwDl1K8AZaLxMK8AYKTgQeCvAGGh4TBBMq8AUK -IA5DOgHwByAeBD4a8AMKLhAELgAOCvADCkMkEwCdABAwugBAAgoOQ7sAsAIKDgMODxQuFA4AdQEw -EB0QwgDTBAogDRAUEDrwAQrGCgUAIBqmLgAQpiYAEIZhABCGAQIfhqABJ-1iYGAE-x4P-xUS-x4j --xUo-x4R-xU2-x4G-xU_3x7-FUZ-Hv8VSj8e-xUM8Bj_Cg8e-gHwMP4FBT7wPD4FnhUO8EAOFZ51 -8DZ1rvUE8Bz1BM71Qv4A9T7_BPU6-gv1MP4c9Rj_Ch3_Th3_Ti3_TE3_Sl0DAE9N-kw9AwAEES05 -AAUDADAN-v8BACQ1DREABVkABTIAAmIAQW3_SH0DAPtYjf5Gnf5Grf5Ezf5C3f5C7f5A-QH_Pv0C --j79A-48-QX_Ov0H-jj9Cf42-Qv_NP0N-jL9D-4w-RH_Lv0T-iz9Ff4q-Rj_Jv0b-iT9Hv4g-SH_ -Hv0k-hr9Kf4U-S7_EP00-gj9Pd79GXoBdC01LjE1ODMBAASEAVcxNC44MBcAAY4BGTOOAfMgQEAE -8P8HjxjwJt7wIf4D8B3_CPAY-gvwFP4Q8A-_FfAL-hnwBf4b8AT_HPAE-hsMACIbBwUAwAP_Gxfw -Av4cBwbwAQYAMBcO4AcA8QIHLsD_HQYHBi7A-hwGBwY_sBUADw8ACKAGBwYHPqBOV-4SCgByLqBO -Fnf_DhUA8wU_JzZH-gwGFwYHLrAuFxY3Nhf_CxoA8AE3Njc2-ggGBwYXLrA_Jkc2HAAQASoAID6w -NgBBNjc27ioAQcAuJkcPADFXBi4uAELQPhc2EgAAiAARFyUAdNBORzZHRjcUAFA_0H5XRiIAEhci -AEE_8AG_MwARFhEAQD7wAu4uAPAIJwYHBic_8AbuVzY3JhcGJy7wDO5HNjcUAEEQzmcmKgDwABW_ -AFcGFwA_8BquADdO8NECUCLO8CdeqQUbhskBNjIuOEMDETkNAAFDAx00tQHRYl8Y8B-_APAV-gvw -D60BURHwDv4RCAACEAAABAAQEhQAtBfwC-4TZ-AF-hN3BQBjEofwBP4TBQCQA-4Uh-AC-hSHxgEh -FXfGASEUh8YBIhSHqQEiFHeqAQQQACIThxAAIhOXEAAhDtcQAFB_d473BZwBNE73GMoBI-cYxwEl -9xTEASb3DcMBNhb3DMEBJvcGvgE4FvcBvwEp9wK8ARrXtgECxgEPuAGQ9Cz-Fl8b8CXO8CD_AfAb --gbwFv4L8BD_EfAN-hTwBP4e8AH_IOD_IsD_JaD_JpD_J3D_KWD_KlAOCv4pQAUAsiowDgoOCv4j -Hw8uCgDwKB99QC4K-hwtJx0nUB4K-hktJy03HUAeCv4VPSctNz1QPgr_EC03LTdNJ1AuCv4MPTct -J10nHQ4NADAJLUcNADAtBy5DAEAFPTc9DgD0AF5gHgr_Ai1HLTddFz1_cAsAci2ukE4Kbj0MAHCe -4D4KTh1XVgByLW7wBT4KTkoAc37wCC4KThcMAFAMHgpOHQsA8QaO8A5_F10XPY7wEm5NFy0HjvAW -Xh0IAPAEGl4HHRd_8B3_AfAgzvAknvAoLmMBL-_hZAEmshQfG-ArXvAnnvAkaQG1HP4F8Bj_CfAU --g1tAdIJ-hfwB-4a8AX_HPADeQHwA-AA-iHg-iOw-iQPD6D_JAcdgF0BgVcNcA4K-h1XDgBhGlct -Fx1gdgFSFkctVw0LAFAURx1HbUEBUxI3LTcdhwF0ECctJw0HDYwBRQ8XHRePAUYKFy0HkgFHCS0X -HZQBWAcdFy0nlgFHHQctF5gBRQ0nHReaASANJz0ABJwBVi0XLScNngE1Jx13ngE1Fy1XngEfTZ0B -ZA-gDBoPOgD--------------------------------------------------6TwI2CABPD-JL8U -8ED_AvA8-gbwOT8V-gTwNz3_BfA1Tf4H8DNN-gjwMk3_CvAwTf4L8C9dBQD4AE3_DPAuXf4N8C1N --g3wLgUAMwzwLwUAMQsPDwcAEDwmAPAMCTzwLBxN-gg88C4cPf4HLA8X8DFN-gULHAsMCQDwrAQM -CwwLDPAzTb4tLg8ZHAsc8DNdjj0uGjzwNV1ObR4qPPA2-QFKPPA3zXos8DkKTdoc8Dv6AwzwO5oM -ivA7amx68DpafHrwOVofHAxpavA4WqlaOfA0WslKOfA0SgDpKknwMyogmS8MKQpZ8DQKSEn4BPAw -_BHwLmgPCvgM8CtoFygn_AfwKfgDNzgXqPAoJ-gMB7jwIgf4EieI8CH4FgeI8CD4GAd48CD4GSc4 -8B-4IfAf_CLwHfggBxgGAPEHFxjwHPghByjwG-gl8Bv4JvAaKAn4IgYA8CMOCfgE8BoYCfgOGSgJ -_ADwGRgJ_A8ZGAmYB1jwGAgZ_BAJKAmIB1jwGQn4ERkoCRgJWBkAVAn4Eik4CwDxAhQZGBlYF1jw -Fwn4FRkIGWgHCwCBGBno8BYJ_Bk_AGQUGfgVGRgLAFAUCTgZ6AkAEBpyAIITGfgaGYgXOAkARvgA -8BIIABEbiACBEQn4HAmoB0gJACQZmAkAsPgB8BAZ_BspqAc4CQCmHBm4BzjwDwn4HQkAocgHGPAQ -CfgcKdhOACApyGUAMBOpuH0A8AEPSXgZqPAVGfgOGbgZiPAXQgDyAQggGPAaKfgbGQjwHyn4HAkH -ABAZBgDwIxo5CPAeKfgYWQjwHxn4F2kt8B0Z_BRpCAlN8BwZ_BF5CG3wHgn4DpltFfAeGfgKmY0l -CABQBqkYbVUJAPJCArkYfYXwHhnIyQiNxfAeCZi5zdXwHwlYqd31AvAfyQjN9QUABfAemRWN9Q3w -Hmmt9Q8ABfAdDRm99RXwG931GPAZjQUN9RzwGS31JPAZPQUNAgCi9RzwGC31JvAXLRAAQwUN9R0S -AAYkAKQe8BU99SjwFC0VEgCGIPAULfUq8BIkAIUi8BIt9SzwEBIAARQAhRAt9SwABfAPXgAAFgCJ -BvAPPfUqABUXAANXAIsPLfUtAAXwDO0Dbi0yOS4xMC4xXDM4Ljc1LjEeMQIE8S3--8NvFPBF7vA8 -PxV_KV7wOF2OKV7wNz0OSW4JbvA2PQ5Z7vA1PQ5pbgpu8DQdPmnu8DQNTln_APA0bkkGAPCEKW6v -GfA03tzwNBmO-AHwNBlu-AMQHw-wMBle-AMQG-AxGV78AgsAK-Axbpzb8DFujNvwMl6Mmx8fK-Ay -XnyLKDvwMl5sSwgbKCcb8DNeXCs4Sx8OBwvwNF4sHxcbKEsIGx8OK-AzHnsfFxgLFw8OKxhb8DMO -mw8XCycfDjsYS-AzHksfF0sXHw5LCEvwMz4rLxe7FgDwJw1ODAsWuwhb8DM9HizrGCvwMz0OHAAs -qyg78DMtDmyLKEsfHPA1jGsYWwYPDB8c8DSMAMsGLwoA8kkyrKsWBT8MFfAxDAB8qwYbRCXwMJzb -RBUU8C_sy0QllPAnjEWLFSRFpPAkjAU0FXslBAX0AfAifBVEJXsl9AEV8CB8BYQFayX0AwXwIGwF -lAVrGvQF8CBcCgDxQAbwH1wFlBVrCgX0BvAeTAAFlBVbBAoF9AfwHiwAJXQFBBU7FBr0B-AhFQQV -ZAUUBUoFGqQFtPAfFQoUJUQFFBpUCqQFxPAcFQQKRCUkBaQOAPAGGhUECnQlBAW0CpQF1PAYFcQl -xAqECgBQBQQKxBUMAPAK5PAWBQQK9BcF9ADwFQUK9BgV9ADwExX0GggAYBIF9BIKhAoA8wARBfQT -CnQABfQC8A8F9BQLAHAOBfQVCmQQCwAQDQsAEXQLAEEMBfQWIQA0A-ALCwChBPAKBfQfABX0AwkA -EBAdADIK9CAIAFDUFfQQEBsA8gEIBeQF9AgKZCAV9ALwCPQADQAyJfQBDQCFCQpEEBUUJeQOAEEA -FUQFDgBgFfQICkQAOQEwCPQBGwAfNA0AAsEV9A0ABfQF8Aj0AwULADME8AkLAFAEKtTwCwwAgAwg -GgQatPAMDADACAokEAo0GpTwDfQCYwCgJAAKVAqE8A70AlcAAA4AQBpk8A8OAJIKCiQVVApU8BAN -AGE0BVQaNAUOAPEEBHX0AQo0BWQKJAXwEeRVZAX0AA8AgRQF8BL0DQXkDQBwBAXwEwX0DBwAsyQF -ZAoF8BQF9AsVDgDB8BUF9Awa5AokBQpUDQBwCzr0AnrwF2kAYBRaROvwGAoAUmQaFOsWCwCAdAoE -2wYr8BmlAFSECusWGxcAQcsGKwYNAFEJCnQK2w0AEhclAAANADEL8BgMAIRrPwU7BhsGCykAMUtj -Kw8AAVAARFQaK4MPAFHUtVrjGwwAYhoFZHXzDhgA8hIbZW3zDjsGCwMb8BqNAw3zEisGC0PwGS3z -HAtj8Bk9Aw0CABDzRgVS8yXwGC0QAIADDfMe8Bct80YFAhAAARIAMBU980YFFBMSAABGBRDzRgUC -EAAwAw3zRgUQ80YFJwMNFABlEC3zLvAPXACfAw3zJPAOPfMuJwUsD50JJw_FCv8gIP8UgjHxAXz0 -P-4BBP8VPQT_AQT9PA4HACA7HgcAQS30Ny4IAE8E-jUECgD-NARSASH0OGIBMR30OnEBcg30Pf4B -9D8nOjH--_iUAR-9kwH-dh9cYgMUHzLlCQHyKxjfFvBALr8PHvA9Lu0e8Dse-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-10 01:58:59",revision=35]] -plant_descriptions = { -[-1]={{"i don't know what that is. where did you find this?"}}, -[14]={{"this is foxglove"}}, -} -function get_conversation(plant) - local id = plant[1] - return plant_descriptions[id] or plant_descriptions[-1] -end - -:: main.lua ---[[pod_format="raw",created="2024-04-02 02:59:37",modified="2024-04-12 14:41:51",revision=951]] --- 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") - -DEBUG = true - -scene = { - before=function() end, - draw=function() end, - update=function() end -} -previous_scene = scene - -animations = {} - -script = {} - -function _init() - vid(3) - change_scene(title_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_conversation.lua ---[[pod_format="raw",created="2024-04-05 14:55:45",modified="2024-04-12 14:41:51",revision=118]] -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-12 14:41:51",revision=273]] -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-12 14:41:51",revision=158]] --- 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 - -shop_screen = {} -function shop_screen.draw() - cls() - - cabinet:draw() - - -- alchemist! - bob(alchemist_sprite, 0, 7, 96, 128, alchemist_bob) - - palt(30, true) - palt(0, false) - spr(16, 240-110, 135-36) - palt(30, false) - palt(0, true) - - -- countertop! - draw_counter(14) - - local book1 = {left=10, right=74, top=100, bottom=164} - if collides(fairy, book1) then spr(18, book1.left, book1.top) - else spr(17, book1.left, book1.top) end - - local book2 = {left=80, right=144, top=100, bottom=164} - if collides(fairy, book2) then spr(20, book2.left, book2.top) - else spr(19, book2.left, book2.top) end - - if customer_visible then - bob(customer_sprite, 240-96, 7, 96, 128, customer_bob) - end - - 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() - 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 - 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-12 14:41:51",revision=538]] -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, false), -Script.once(function() -- person appearss - alchemist_sprite = 193 - customer_visible = true - customer_sprite = 201 - return false -end, false), -Script.len(function(s) -- door closes - door_open = easeTrig(1-(s.timer/s.length)) -end, 0.5, false), -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 +:: .info.pod +b64$LS1bW3BvZCxjcmVhdGVkPSIyMDI0LTA0LTEyIDE2OjM3OjU3IixydW50aW1lPTUsc3RvcmVk +PSIyMDI0LTA0LTE0IDAzOjIyOjU3Iix3b3Jrc3BhY2VzPXt7bG9jYXRpb249Im1haW4ubHVhIzE1 +Iix3b3Jrc3BhY2VfaW5kZXg9MX0se2xvY2F0aW9uPSJzX3Nob3AubHVhIzM4Iix3b3Jrc3BhY2Vf +aW5kZXg9MX0se2xvY2F0aW9uPSJzX2RyYXdlci5sdWEjMSIsd29ya3NwYWNlX2luZGV4PTF9LHts +b2NhdGlvbj0ic19ib29rLmx1YSMzOSIsd29ya3NwYWNlX2luZGV4PTF9LHtsb2NhdGlvbj0iZ2Z4 +LzAuZ2Z4Iix3b3Jrc3BhY2VfaW5kZXg9Mn19XV1sejQABAAAAAMAAAAwbmls :: [eoc]