0,]']±>Sï}WÿÍu§ðp8·d%qy)6o;]ÉA¦ösï÷ôôô”°ÂVl†3??????????????? !"$$%'()*+,-/////////////////@4 7à9 ;€=€>€>€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€ 012345555555555555555555555555‡………me eô… …HaŠ@d `………neeô… …IaŠ@d d d dd ddd DD™& & & &FFFFFF&&&& & & & &ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD'T)©©©T*©T*©©©©©©T(©T)©©……¥g……ýŠ@d `…ø…neie öŠ@d@`…… … … … … …I…@ d dÈD'ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD'ô'ÈD' &™& & & &&&FFFF&&&& & & & &D)©©©6(©©e)©e)©T)©©8(©T(©T)©©4Á@r$ö5-- Assembled by the RiFT bundler rift_crapt=function() -- Returns the swizzle, using k -- at pos i function getSwizzle(k,i) local iSwizzle=1+((i-1)%#k) local swizzleCh=k:sub(iSwizzle,iSwizzle) return string.byte(swizzleCh+i*9) end function encrapt(d,k) local s="" for i=1,#d do local swizzle=getSwizzle(k,i) local asc=string.byte(d:sub(i,i)) s=s..string.format("%2x",(asc+swizzle)&0xff) end return s end function decrapt(d,k) local s="" local iSwizzle=1 for i=1,#d,2 do local hex=d:sub(i,i+1) local asc=tonumber(hex,16) local swizzle=getSwizzle(k,iSwizzle) local c=string.char((asc-swizzle)&0xff) s=s..c iSwizzle=iSwizzle+1 end return s end end rift_date=function() function daysInYear(yr) return ( yr % 4 == 0 and (yr % 100 ~= 0 or yr % 400 == 0) ) and 366 or 365 end function tab_overflow(seed, table) for i = 1, #table do if seed - table[i] <= 0 then return i, seed end seed = seed - table[i] end end -- https://otland.net/threads/how-convert-timestamp-to-date-type.251657/#post-2442023 function dateFromUnix(unix_time) local year = 1970 local days = math.ceil(unix_time/86400) local month = 0 while days >= daysInYear(year) do days = days - daysInYear(year) year = year + 1 end local month,days=tab_overflow(days, {31,(daysInYear(year) == 366 and 29 or 28),31,30,31,30,31,31,30,31,30,31}) local hours=math.floor(unix_time / 3600 % 24) local minutes=math.floor(unix_time / 60 % 60) local seconds=math.floor(unix_time % 60) return { year=year, month=month, day=days, hour=hours, minute=minutes, second=seconds, } end function keyFromDate(month,day) return string.format("%02d%02d",day,month) end end rift_draw=function() function drawFinger(x,y) local def = getFingerDef() drawObj(def) end function drawButton(i,x,y,w,h,state) local bg,fg=15,13 if state then bg,fg = 14,4 end rect(x,y,w,h,bg) print(i,x+7,y+7,fg,false,5) end function draw(ps) for i,p in ipairs(ps) do rX(p,CAM.rx) rY(p,CAM.ry) rZ(p,CAM.rz) pp(p,CAM) end table.sort(ps, function(a,b) return a.pz>b.pz end) for i,p in ipairs(ps) do circ(p.px,p.py,1,p.c) end end function getFingerDef() return { ps={ {x=-1,y=-1,z=0}, {x=-1,y=0,z=0}, {x=0,y=-1,z=0}, }, quads={}, tris={ {1,2,3}, }, } end function getBoxDef() local t0x0,t0y0,t0x1,t0y1=0,0,32,32 local t1x0,t1y0,t1x1,t1y1=32,0,64,32 return { ps={ {x=-1,y=1,z=-1}, {x=1,y=1,z=-1}, {x=-1,y=-1,z=-1}, {x=1,y=-1,z=-1}, {x=-1,y=1,z=1}, {x=1,y=1,z=1}, {x=-1,y=-1,z=1}, {x=1,y=-1,z=1}, }, quads={ {{p=2, t={x=t0x0, y=t0y0}}, {p=1, t={x=t0x1, y=t0y0}}, {p=3, t={x=t0x1, y=t0y1}}, {p=4, t={x=t0x0, y=t0y1}}}, {{p=5, t={x=t0x0, y=t0y0}}, {p=6, t={x=t0x1, y=t0y0}}, {p=8, t={x=t0x1, y=t0y1}}, {p=7, t={x=t0x0, y=t0y1}}}, {{p=1, t={x=t0x0, y=t0y0}}, {p=5, t={x=t0x1, y=t0y0}}, {p=7, t={x=t0x1, y=t0y1}}, {p=3, t={x=t0x0, y=t0y1}}}, {{p=6, t={x=t0x0, y=t0y0}}, {p=2, t={x=t0x1, y=t0y0}}, {p=4, t={x=t0x1, y=t0y1}}, {p=8, t={x=t0x0, y=t0y1}}}, {{p=1, t={x=t1x0, y=t1y0}}, {p=2, t={x=t1x1, y=t1y0}}, {p=6, t={x=t1x1, y=t1y1}}, {p=5, t={x=t1x0, y=t1y1}}}, {{p=3, t={x=t1x0, y=t1y0}}, {p=4, t={x=t1x1, y=t1y0}}, {p=8, t={x=t1x1, y=t1y1}}, {p=7, t={x=t1x0, y=t1y1}}}, }, tris={ }, } end function getBoxSideDef() local tx0,ty0,tx1,ty1=0,0,31,31 return { ps={ {x=-1,y=0,z=-1}, {x=1,y=0,z=-1}, {x=-1,y=0,z=1}, {x=1,y=0,z=1}, }, quads={ {{p=2, t={x=t0x0, y=t0y0}}, {p=1, t={x=t0x1, y=t0y0}}, {p=3, t={x=t0x1, y=t0y1}}, {p=4, t={x=t0x0, y=t0y1}}}, }, tris={ } } end function drawObj(boxDef) local ps=boxDef.ps for i=1,#ps do local p=ps[i] rX(p, CAM.rx) rY(p, CAM.ry) rZ(p, CAM.rz) pp(p, CAM) end for i,q in ipairs(boxDef.quads) do local p1=ps[q[1].p] local p2=ps[q[2].p] local p3=ps[q[3].p] local p4=ps[q[4].p] drawTri(p1,p2,p3, q[1].t, q[2].t, q[3].t) drawTri(p3,p4,p1, q[3].t, q[4].t, q[1].t) end for i,t in ipairs(boxDef.tris) do local p1=ps[t[1]] local p2=ps[t[2]] local p3=ps[t[3]] tri(p1.x,p1.y, p2.x,p2.y, p3.x,p3.y, 12) end end end rift_scenesintro=function() function doSceneIntro(t) cls() print("TIC-80 BOOM!", 60, 50, 12, false, 2) print("(code) jtruk x Gasman (music)", 90, 120, 12) end end rift_sceneswalkup=function() local M=math local S,PI,ABS=M.sin,M.pi,M.abs local TAU=PI*2 local yLastBounce=0 function doSceneWalkUp(t) cls() local bounces=14 local yBounce=ABS(S(t*PI*bounces)*.5) CAM.y=2-yBounce CAM.x=S(t*PI*bounces+PI/2)*.25 CAM.z=CAM_Z_FAR-t*(CAM_Z_FAR-CAM_Z_NEAR) CAM.ry=t*TAU*2 if yBounce > yLastBounce then sfx(0,35,2) end local def=getBoxDef() drawObj(def) yLastBounce = yBounce end end rift_scenesboxopengood1=function() local M=math local S,C,POW,PI,ABS,MIN=M.sin,M.cos,M.pow,M.pi,M.abs,M.min local TAU=PI*2 local tSceneF=0 function BDR2(y) local fl=S(tSceneF*PI)*.5+.5 if y>=0 and y<136 then local bgR,bgG,bgB=255*fl,255*fl,255*fl setRGB(0, bgR,bgG,bgB) fadeColour(1,bgR,bgG,bgB,150,90,220) fadeColour(2,bgR,bgG,bgB,10,70,150) fadeColour(3,bgR,bgG,bgB,0,30,80) end end function doSceneBoxOpenGood1(t) cls() tSceneF=t BDR=BDR2 CAM.y=2-t*20 CAM.x=0 CAM.z=CAM_Z_EXPLODE CAM.ry=t*TAU*2 local def=getBoxDef() drawObj(def) end end rift_scenesboxopengood2=function() local M=math local S,C,POW,PI,ABS,MIN=M.sin,M.cos,M.pow,M.pi,M.abs,M.min local TAU=PI*2 local firstEntry=true function doSceneBoxOpenGood2(t) cls() BDR=BDR0 if firstEntry then music(0) firstEntry=false end CAM.y=1 --1+S(t)*2 CAM.x=0 CAM.z=CAM_Z_EXPLODE+MIN(t/2,1)*(CAM_Z_NEAR-CAM_Z_EXPLODE) CAM.ry=t*2 local ps={} local nPoints=100 local cakeR=.9 local cakeH=.4 for i=1,nPoints do local a=i/nPoints * TAU local cX,cZ=S(a)*cakeR,C(a)*cakeR -- top and bottom table.insert(ps, {x=cX, y=cakeH, z=cZ, c=2}) table.insert(ps, {x=cX, y=-cakeH, z=cZ, c=2}) -- stripe table.insert(ps, {x=cX, y=S(6*TAU*(i/nPoints))*.6*cakeH, z=cZ, c=12}) end local nCandles=10 local nCandlesY=10 local candleH=cakeH*1.2 local nFlameY=10 local flameH=cakeH*.1 local candleR=cakeR*.8 for iR=1,nCandles do local a=iR/nCandles * TAU local x=S(a)*candleR local z=C(a)*candleR for iY=1,nCandlesY do local y=cakeH + candleH * iY/nCandlesY table.insert(ps, {x=x, y=y, z=z, c=12}) end -- flame for iY=1,nFlameY do local y=cakeH + candleH + flameH * iY/nFlameY local aCan=a local d=S(iY+t*4)*.1 x = x + C(aCan)*d z = z + S(aCan)*d table.insert(ps, {x=x, y=y, z=z, c=4}) end end draw(ps) local animSpeed=4 local yBase=120 local yLine=yBase-ABS(S(t*animSpeed)*10) local yFlex=yBase-8-ABS(S(t*animSpeed-.2)*10) printOutline("Happy ToBirthday!", 30,yLine) printOutline("^", 108,yFlex) end end rift_scenesboxopenbad2=function() local M=math local S,C,POW,PI,ABS,MIN=M.sin,M.cos,M.pow,M.pi,M.abs,M.min local TAU=PI*2 local firstEntry=true function doSceneBoxOpenBad2(t) tMin=math.min(t,1) cls() BDR=BDR0 if firstEntry then music(1,-1,-1,false) firstEntry=false end CAM.y=1-tMin*1 --1+S(t)*2 CAM.x=0 CAM.z=CAM_Z_EXPLODE+tMin*(CAM_Z_NEAR-CAM_Z_EXPLODE) CAM.ry=t*TAU*2 local ps={} -- a little pile of dust local yBase=-1 local nLayers=10 local layerHeight=.05 for iLayer = 1,nLayers do local y = yBase+layerHeight*iLayer local layerDensity = 1 - (iLayer/nLayers) local r = layerDensity * .9 local nPsInLayer = (layerDensity + 1) * 20 for i = 1,nPsInLayer do local a=i/nPsInLayer * TAU local x=S(a)*r local z=C(a)*r table.insert(ps, {x=x, y=y+S(i)*layerHeight*.5, z=z, c=15}) end end local def=getBoxSideDef() trM(def, 0,-1,0) drawObj(def) draw(ps) for i=0,10 do local x=120+S(i)*30+S(i+t*30)*10 local y=80-(t*200+i*10)%30 circ(x,y,3,15) end local animSpeed=4 local yBase=120 local yLine=yBase-ABS(S(t*animSpeed)*10) local yFlex=yBase-8-ABS(S(t*animSpeed-.2)*10) printOutline("ToDay is not the day!", 10,yLine) printOutline("^", 20,yFlex) end function printOutline(t,x,y) print(t, x+1,y+1,15, false,2) print(t, x,y,12, false,2) end end rift_3d=function() local M=math local S,C,POW=M.sin,M.cos,M.pow function tr(p,x,y,z) p.x,p.y,p.z=p.x+x,p.y+y,p.z+z end -- Translate model function trM(m,x,y,z) for i,p in ipairs(m.ps) do tr(p,x,y,z) end end function rX(p,r) local s,c,y,z=S(r),C(r),p.y,p.z p.y=y*c-z*s p.z=y*s+z*c end function rY(p,r) local s,c,x,z=S(r),C(r),p.x,p.z p.x=x*c-z*s p.z=x*s+z*c end function rZ(p,r) local s,c,x,y=S(r),C(r),p.x,p.y p.x=x*c-y*s p.y=x*s+y*c end function pp(p, cam) local zD=(cam.z-p.z)/10 p.px=120+(p.x-cam.x)/zD*10 p.py=68-(p.y-cam.y)/zD*10 p.pz=zD end function bezier(t, p0, p1, p2, p3) local c = 3 * (p1 - p0) local b = 3 * (p2 - p1) - c local a = p3 - p0 - c - b return ((a * POW(t, 3)) + (b * POW(t, 2)) + (c * t) + p0) end function drawTri(p1,p2,p3, t1,t2,t3) ttri( p1.px,p1.py, p2.px,p2.py, p3.px,p3.py, t1.x,t1.y, t2.x,t2.y, t3.x,t3.y, 0,-1, p1.pz,p2.pz,p3.pz ) end end rift_scenes=function() I_CURRENT_SCENE = 1 CURRENT_T_IN_SCENE = 0 -- each scene runs 0-t inclusive... SCENES = { {id='intro', t=200}, {id='walk-up', t=300}, {id='pin-entry', t=100}, {id='walk-back', t=150}, {id='box-open', t=100}, {id='in-the-box', t=nil}, } function incT() CURRENT_T_IN_SCENE = CURRENT_T_IN_SCENE + 1 local currentScene = SCENES[I_CURRENT_SCENE] local currentSceneLen = currentScene.t if currentSceneLen ~= nil and CURRENT_T_IN_SCENE > currentSceneLen then CURRENT_T_IN_SCENE = 0 I_CURRENT_SCENE = I_CURRENT_SCENE + 1 end end -- tUnit -> 0 - 1 function getScene() local currentScene = SCENES[I_CURRENT_SCENE] return { id = currentScene.id, t = CURRENT_T_IN_SCENE, tUnit = (currentScene.t ~= nil) and (CURRENT_T_IN_SCENE / currentScene.t) or CURRENT_T_IN_SCENE / 100 } end end rift_scenespinentry=function() local M=math local MIN=M.min local BUTTON_STATE={} local tButtonLast=-1 function doScenePinEntry(t) for i=0,9 do BUTTON_STATE[i+1] = false end local tButton=MIN(1+(t*4)//1,#KEY) if tButton ~= tButtonLast then sfx(1,60,10) end local iButton=KEY:sub(tButton,tButton) BUTTON_STATE[iButton + 1] = true for i,state in ipairs(BUTTON_STATE) do local v=i-1 local yButton=v//5 local xButton=v%5 local x=20+xButton*40 local y=20+yButton*40 drawButton(v,x,y,38,38,state) end drawFinger(40,50) tButtonLast=tButton end end rift_sceneswalkback=function() local M=math local S,PI,ABS=M.sin,M.pi,M.abs local TAU=PI*2 local yLastBounce=0 function doSceneWalkBack(t) cls() local bounces=4 local yBounce=ABS(S(t*PI*bounces)*.5) CAM.y=2-yBounce CAM.x=S(t*PI*bounces+PI/2)*.25 CAM.z=CAM_Z_NEAR+t*(CAM_Z_EXPLODE-CAM_Z_NEAR) CAM.ry=t*TAU*2 if yBounce > yLastBounce then sfx(0,35,2) end local def=getBoxDef() drawObj(def) yLastBounce = yBounce end end rift_scenesboxopenbad1=function() local M=math local S,C,POW,PI,ABS,MIN=M.sin,M.cos,M.pow,M.pi,M.abs,M.min local TAU=PI*2 local firstEntry=true local tSceneF=0 function BDR1(y) if y>=0 and y<136 then local fl=S(tSceneF*PI)*.5+.5 local bgR,bgG,bgB=fl*255,fl*0,fl*0 setRGB(0, bgR,bgG,bgB) fadeColour(1,bgR,bgG,bgB,150,90,220) fadeColour(2,bgR,bgG,bgB,10,70,150) fadeColour(3,bgR,bgG,bgB,0,30,80) end end function doSceneBoxOpenBad1(t) cls() tSceneF=t BDR=BDR1 CAM.y=2 CAM.x=0 CAM.z=CAM_Z_EXPLODE CAM.ry=t*TAU*2 local def=getBoxDef() drawObj(def) for i=0,10 do local x=120+math.random(-30,30) local y=80+math.random(-30,30) local s=math.random(5,30) local c=math.random(2,5) circ(x,y,s,c) end end function printOutline(t,x,y) print(t, x+1,y+1,15, false,2) print(t, x,y,12, false,2) end end package.path = package.path .. ";/Users/matthew/Development/tic80/2024-fieldfx-tic-80-boom/?.lua" -- gasman KEY=nil local DATA=nil local FN=nil CAM={x=0,y=0,z=0,rx=0,ry=0,rz=0} CAM_Z_FAR=20 CAM_Z_NEAR=3 CAM_Z_EXPLODE=6 BDR=nil rift_3d() rift_crapt() rift_date() rift_draw() rift_scenes() rift_scenesintro() rift_sceneswalkup() rift_scenespinentry() rift_sceneswalkback() rift_scenesboxopengood1() rift_scenesboxopengood2() rift_scenesboxopenbad1() rift_scenesboxopenbad2() function BDR0(y) if y>=0 and y<136 then local bgR,bgG,bgB=255-y,20,60+y setRGB(0, bgR,bgG,bgB) fadeColour(1,bgR,bgG,bgB,150,90,220) fadeColour(2,bgR,bgG,bgB,10,70,150) fadeColour(3,bgR,bgG,bgB,0,30,80) end end function setRGB(c,r,g,b) local a=16320+c*3 poke(a,r) poke(a+1,g) poke(a+2,b) end function BOOT() local utime=tstamp() local d=dateFromUnix(utime) KEY=keyFromDate(d.month,d.day) -- t=time --FN=load("local t,fn,cam = ... " .. DATA) end function fadeColour(i,r0,g0,b0,r1,g1,b1) local fade=1-((CAM.z-CAM_Z_NEAR)/CAM_Z_FAR) setRGB(i, r0+(r1-r0)*fade, g0+(g1-g0)*fade, b0+(b1-b0)*fade) end function TIC() poke(0x3ffb,0) -- Remove mouse local good=(KEY=="1106") and true or false local scene = getScene() if scene.id == 'intro' then BDR=BDR0 doSceneIntro(scene.tUnit) elseif scene.id == 'walk-up' then BDR=BDR0 doSceneWalkUp(scene.tUnit) elseif scene.id == 'pin-entry' then BDR=BDR0 doScenePinEntry(scene.tUnit) elseif scene.id == 'walk-back' then BDR=BDR0 doSceneWalkBack(scene.tUnit) elseif scene.id == 'box-open' then if good then doSceneBoxOpenGood1(scene.tUnit) else doSceneBoxOpenBad1(scene.tUnit) end else if good then doSceneBoxOpenGood2(scene.tUnit) else doSceneBoxOpenBad2(scene.tUnit) end end incT() end