chameleonic/chameleonic.p8

2274 lines
89 KiB
Plaintext
Raw Normal View History

2022-12-17 20:16:26 +00:00
pico-8 cartridge // http://www.pico-8.com
version 39
2022-12-17 20:16:26 +00:00
__lua__
-- setup
2022-12-17 20:16:26 +00:00
modules={}
2022-12-18 04:38:49 +00:00
real_modules={}
2022-12-17 20:16:26 +00:00
function _init()
2022-12-29 22:54:08 +00:00
-- printh("restarting")
_doall("init")
end
2022-12-17 20:16:26 +00:00
function _update()
2023-01-03 02:40:28 +00:00
_doall("update") end
2022-12-17 20:16:26 +00:00
function _draw()
_doall("draw") end
function music_on()
if (stat(54) ~= 0) music(0)
persist.music=true
persist:write()
menuitem(3, "music: on", music_off)
end
function music_off()
music(-1)
persist.music=false
persist:write()
menuitem(3, "music: off", music_on)
end
2023-01-01 22:55:02 +00:00
function gsv(s,sep1,sep2)
local ret=split(s,sep1 or "\n")
for i,v in ipairs(ret) do
2023-01-01 22:55:02 +00:00
ret[i] = type(v) == "string" and split(v,sep2 or "`") or {v} end
return ret
end
Better debug mouse (#20) Debug mouse is now its own module, so it can be separated from the hint system, since it is useful for more than just positioning hints. It now has the following enhancements: 1. Clock-based table cyclng now has a helper function (cycle) 2. Debug mouse color cycling is distinct from hint color cycling, so debug position readout remains legible 3. Debug position readout now stays on screen even when the cursor is near or past the edges 4. Debug cursor cycles between a mouse sprite specifically marking the exact pixel that is being sampled, an "X" for text character sizing, and a "□" for positioning the centered 3x3 characters often used as hint target markers 5. Map cell coordinates (in square brackets) are displayed in addition to pixel coordnates (in parentheses) Sprite 50 is now the mouse cursor. Color 15 is color cycling for debug readouts. Debug mouse features can be disabled by commenting out `add(real_modules, debugmouse)`. I've done a little bit of golfing but this is stiill a token expense. I'm going to write a crappy sprintf function to save tokens everywhere we're assembling strings from their component parts. Simplify debug info display. Save tokens by omitting parentheses and map coordinates. Adjust location to match. Instead of cycling between symbols, the cursor shape can be chosen by using left, right, or both mouse buttons. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/20 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 00:31:34 +00:00
function cycle(tbl,period)
period = period or 1
return tbl[t()%period*#tbl\period+1]
end
mnames={}
function names(root)
local n=mnames[root]
if(n)return all(n)
n={root.."0", root, root.."2", root.."3"}
mnames[root]=n
return all(n)
end
2022-12-17 20:16:26 +00:00
function _doall(x)
for n in names(x) do
2022-12-17 20:16:26 +00:00
for mod in all(modules) do
local f=mod[n]
if (f) f(mod)
2022-12-17 20:16:26 +00:00
end
end
end
-- source: https://www.lexaloffle.com/bbs/?pid=78990
gaps=split"57,23,10,4,1"
2022-12-17 20:16:26 +00:00
--{701,301,132,57,23,10,4,1}
function shellsort(a)
for gap in all(gaps) do
for i=gap+1,#a do
local x,j=a[i],i-gap
2022-12-17 20:16:26 +00:00
while j>=1 and a[j].key>x.key do
a[j+gap]=a[j]
j-=gap
end
a[j+gap]=x
end
end
end
function linefill(ax,ay,bx,by,r,c)
if(c) color(c)
local dx,dy=bx-ax,by-ay
-- avoid overflow
-- credits: https://www.lexaloffle.com/bbs/?tid=28999
2022-12-23 02:30:05 +00:00
local n,d=_mnmx(abs(dx),abs(dy))
n/=d
2022-12-17 20:16:26 +00:00
d*=sqrt(n*n+1)
if(d<0.001) return
local ca,sa=dx/d,-dy/d
2022-12-17 20:16:26 +00:00
-- polygon points
2022-12-23 02:30:05 +00:00
local spans={}
local function calcxy(u,v) return ax+u*ca+v*sa,ay-u*sa+v*ca end
local x0,y0=calcxy(0,r)
2022-12-23 02:32:14 +00:00
for s in all{{0,-r},{d,-r},{d,r},{0,r}} do
local x1,y1=calcxy(unpack(s))
local _x1,_y1=x1,y1
if(y0>y1) x0,y0,x1,y1=x1,y1,x0,y0
local dx=(x1-x0)/(y1-y0)
local cy0=y0\1+1
-- sub-pix shift
x0+=(cy0-y0)*dx
2023-01-03 03:59:34 +00:00
for y=cy0,min(y1\1,127) do
-- open span?
local span=spans[y]
2022-12-23 02:30:05 +00:00
if (span) rectfill(x0,y,span,y)
spans[y]=x0
x0+=dx
2022-12-17 20:16:26 +00:00
end
x0,y0=_x1,_y1
end
2022-12-17 20:16:26 +00:00
end
function _apply(x,ts,a)
local t=deli(ts,1)
for k,v in pairs(t) do
2022-12-23 02:33:48 +00:00
if (k!="update") x[k]=v
2022-12-17 20:16:26 +00:00
end
if (t and t.update and not t.update(x,a)) add(ts,t,1)
2022-12-17 20:16:26 +00:00
end
function sgn0(x)
2022-12-23 02:35:24 +00:00
return x!=0 and sgn(x) or 0
2022-12-17 20:16:26 +00:00
end
function _mnmx(x,y)
if (x>y)return y,x
return x,y
2022-12-17 20:16:26 +00:00
end
2022-12-18 04:38:49 +00:00
2022-12-20 05:36:11 +00:00
function _rast(
2023-01-03 04:43:59 +00:00
xys,x0,y0,x1,y1
2022-12-20 05:36:11 +00:00
)
2022-12-23 02:42:44 +00:00
local function _add()
2023-01-03 04:43:59 +00:00
local n=#xys
local xy0={x0,y0}
if (n==0 or not _anch_eq(xys[n],xy0)) add(xys,xy0)
2022-12-23 02:42:44 +00:00
end
2022-12-20 05:36:11 +00:00
2022-12-23 02:42:44 +00:00
local dx,dy=abs(x1-x0),abs(y1-y0)
2023-01-03 04:04:29 +00:00
local sx,sy=sgn(x1-x0),sgn(y1-y0)
2022-12-20 05:36:11 +00:00
2022-12-31 07:30:05 +00:00
local done,err
2022-12-20 05:36:11 +00:00
if dx>dy then
err=dx/2.0
2022-12-23 02:42:44 +00:00
while x0!=x1 do
_add()
2022-12-20 05:36:11 +00:00
err-=dy
2022-12-23 02:42:44 +00:00
if (err<0) y0+=sy err+=dx
x0+=sx
2022-12-20 05:36:11 +00:00
end
else
err=dy/2.0
2022-12-23 02:42:44 +00:00
while y0!=y1 do
_add()
2022-12-20 05:36:11 +00:00
err-=dx
2022-12-23 02:42:44 +00:00
if (err<0) x0+=sx err+=dy
y0+=sy
2022-12-20 05:36:11 +00:00
end
end
2022-12-23 02:42:44 +00:00
_add()
2022-12-20 05:36:11 +00:00
end
2023-01-01 03:02:33 +00:00
-->8
-- anchor operations (for the rope code)
function _anch_eq(a0,a1)
if (a0 and a1) return a0[1]==a1[1] and a0[2]==a1[2]
return a0==a1
end
--[[
function _anch_unpack(anch)
assert(anch[1])
assert(anch[2])
return anch[1],anch[2]
end
]]--
_anch_unpack=unpack
function _anch_new(prev,next,xy)
local out={prev=prev,next=next,_anch_unpack(xy)}
if (prev) prev.next=out
if (next) next.prev=out
return out
end
function _anch_del(n1,xy)
local n0,n2=n1.prev,n1.next
if (n0) n0.next=n2
if (n2) n2.prev=n0
end
function _anch_update(a0,a1)
a0[1]=a1[1]
a0[2]=a1[2]
end
2022-12-18 04:38:49 +00:00
-->8
-- input
2022-12-18 04:38:49 +00:00
kbd={}
add(real_modules,kbd)
function kbd:init()
2022-12-20 00:25:38 +00:00
self.real=btn()
2022-12-23 02:49:03 +00:00
self.state={btn=0}
2022-12-18 04:38:49 +00:00
end
function kbd:update()
2022-12-20 00:25:38 +00:00
-- figure out what keys are _really_ pressed
2022-12-23 02:49:03 +00:00
local now_real,was_real=btn(),self.real
2022-12-20 00:25:38 +00:00
self.real=now_real
-- add keys that are really pressed
-- if they weren't really pressed before
-- (they may have been force-
-- released by :release())
2022-12-23 02:49:03 +00:00
local real_pressed=~was_real&now_real
2022-12-20 00:25:38 +00:00
2022-12-23 02:49:03 +00:00
local state=self.state
local now_down=state.btn&now_real|real_pressed
local was_down=state.btn
2022-12-20 00:25:38 +00:00
-- deduce pressed/released by changes in down
2022-12-23 02:49:03 +00:00
state.btn,state.btnp,state.btnr=
now_down,
~was_down&now_down,
~now_down&was_down
2022-12-20 00:25:38 +00:00
end
2022-12-23 02:49:03 +00:00
for _kbdi in all(split"btn,btnp,btnr") do
kbd[_kbdi]=function(self,i,t) return 1<<i&self.state[_kbdi]!=0 end
2022-12-20 00:25:38 +00:00
end
2022-12-18 04:38:49 +00:00
function kbd:release(i)
2022-12-23 02:49:03 +00:00
self.state.btn&=~(1<<i)
2022-12-18 04:38:49 +00:00
end
function tostring(any)
if type(any)=="table" then
2022-12-23 02:51:05 +00:00
local str = "{ "
for k,v in pairs(any) do
str=str..tostring(k).."->"..tostring(v).." "
end
return str.."}"
end
2022-12-23 02:51:05 +00:00
return tostr(any)
end
2022-12-18 04:38:49 +00:00
-->8
-- title screen
2022-12-18 04:38:49 +00:00
title={}
add(modules,title)
lvlshimmer = {4,9,10,10,9}
2022-12-18 04:38:49 +00:00
function title:draw()
cls(0)
-- this is right for 72x32
spr(96,28,56,9,2)
2022-12-18 05:36:25 +00:00
print("pyrex",32,73,7)
print("[nyeogmi]",62,73,7)
print("kistaro",32,79,7)
local lvlstr = "⬅️ "..start_level.." ➡️"
local lx, ly = 51+wrongbleep:vibrate(), 90+wrongbleep:vibrate()
print(lvlstr,lx-1,ly+1,1)
print(lvlstr,lx,ly,cycle(lvlshimmer))
2022-12-18 04:38:49 +00:00
end
function title:init()
start_level=persist.recent_level
-- max_level=persist.max_level
max_level = 31 --debugging/coding
wiped = false
end
2022-12-18 04:38:49 +00:00
function title:update()
2022-12-23 02:52:54 +00:00
if (btnp"0") start_level-=1
if (btnp"1") start_level+=1
start_level%=(max_level+1)
if btn"3" and not wiped then
wrongbleep:bleep()
if (wrongbleep:adequately_warned()) then
persist:wipe()
max_level = 0
start_level = 0
wiped=true
-- todo: sfx(kaboom!)
end
end
if (btnp"4" or btnp"5") modules=real_modules _init()
2022-12-18 04:38:49 +00:00
end
2022-12-20 00:38:21 +00:00
2022-12-17 20:16:26 +00:00
-->8
--level behaviors
2022-12-17 20:16:26 +00:00
level={}
2022-12-18 04:38:49 +00:00
add(real_modules,level)
2022-12-17 20:16:26 +00:00
function level:init()
level:reinit(start_level)
2022-12-17 20:16:26 +00:00
end
function level:reinit(n)
2023-01-02 04:18:38 +00:00
self.hintlevel=0
2022-12-17 20:16:26 +00:00
self.ix=n
self.todo={}
2022-12-23 03:07:43 +00:00
self.bigx,self.bigy=n%8,n\8
2022-12-31 23:07:23 +00:00
self.dirty=false
2022-12-17 20:16:26 +00:00
2023-01-02 00:31:44 +00:00
player.rope=nil -- reanchor will touch the rope otherwise
2022-12-17 20:16:26 +00:00
self:load_dynobjs()
2022-12-31 23:07:23 +00:00
self:recollide_reanchor()
2022-12-17 23:08:54 +00:00
self:spawn_exit()
persist:lvlstart()
2022-12-17 23:08:54 +00:00
end
2022-12-18 00:25:20 +00:00
function level:restart()
self:reinit(self.ix)
end
2022-12-17 23:08:54 +00:00
function level:advance()
self:reinit(self.ix+1)
2022-12-17 20:16:26 +00:00
end
normpal = {[1]=0,[8]=0,[14]=0}
2022-12-17 20:16:26 +00:00
function level:draw()
2022-12-31 07:30:05 +00:00
cls(5)
fillp()
pal(normpal)
2022-12-17 20:16:26 +00:00
map(
2022-12-17 23:08:54 +00:00
self.bigx*16,self.bigy*16,
2022-12-17 20:16:26 +00:00
0,0,16,16,
64 -- flag 6: visible
)
2022-12-17 23:48:52 +00:00
for _,pit in pairs(self._pits) do
local px,py=pit.px,pit.py
2023-01-02 21:05:58 +00:00
local pr=self._pits[_mix{px+1,py}]
spr(pit.s,px,py)
2023-01-02 00:26:21 +00:00
if pit.full then
2023-01-02 20:18:30 +00:00
spr(15,pit.px,pit.py)
end
palt(8,true)
spr(pit.s,px,py)
palt()
2022-12-17 23:48:52 +00:00
end
2022-12-17 20:16:26 +00:00
for _,crate in pairs(self._crates) do
spr(crate.s,crate.px,crate.py)
end
2022-12-17 23:48:52 +00:00
pal()
2022-12-17 20:16:26 +00:00
end
function level:busy()
for _,crate in pairs(self._crates) do
2022-12-17 20:16:26 +00:00
if (#crate.todo>0) return true
end
2022-12-31 07:30:05 +00:00
return
2022-12-17 20:16:26 +00:00
end
function level:update()
_apply(self, self.todo)
2022-12-17 23:48:52 +00:00
local remove={}
for cix,crate in pairs(self._crates) do
2022-12-17 20:16:26 +00:00
_apply(crate, crate.todo)
2022-12-17 23:48:52 +00:00
if #crate.todo==0 then
2023-01-02 21:05:58 +00:00
local pit=self._pits[_mix{crate.mx,crate.my}]
2023-01-02 00:26:21 +00:00
if pit and not pit.full then
2022-12-17 23:48:52 +00:00
add(remove,cix)
crate.dead=true
2023-01-02 00:26:21 +00:00
pit.full=true
2022-12-17 23:48:52 +00:00
end
end
end
for cix in all(remove) do
self._crates[cix]=nil
2022-12-31 23:07:23 +00:00
self.dirty=true
2022-12-17 23:48:52 +00:00
end
2022-12-31 23:07:23 +00:00
if self.dirty then
self:recollide_reanchor()
self.dirty=false
2022-12-17 20:16:26 +00:00
end
end
function level:load_dynobjs()
self._crates={}
2022-12-17 23:48:52 +00:00
self._pits={}
2022-12-23 03:07:43 +00:00
local crate_id=1
2022-12-17 20:16:26 +00:00
for mx=0,15,1 do
for my=0,15,1 do
2023-01-02 21:05:58 +00:00
local mxy=_mix{mx,my}
2022-12-17 23:48:52 +00:00
local px,py=mx*8,my*8
2022-12-17 20:16:26 +00:00
local s=self:_mget(mx,my)
local def=self:_get_cratedef(s)
if def then
2022-12-17 20:16:26 +00:00
self._crates[mxy]={
s=s,def=def,
2022-12-23 03:07:43 +00:00
id=crate_id,
2022-12-17 20:16:26 +00:00
mx=mx,my=my,
2022-12-17 23:48:52 +00:00
px=px,py=py,
2022-12-17 20:16:26 +00:00
todo={}
}
2022-12-23 03:07:43 +00:00
crate_id+=1
2022-12-17 20:16:26 +00:00
end
2022-12-17 23:48:52 +00:00
2022-12-23 03:07:43 +00:00
-- pit
if (fget(s,5)) self._pits[mxy]={s=s,mx=mx,my=my,px=px,py=py}
2022-12-17 20:16:26 +00:00
end
end
end
2022-12-31 23:07:23 +00:00
function level:recollide_reanchor()
2022-12-17 20:16:26 +00:00
self._coll={}
for mx=0,15 do
for my=0,15 do
2023-01-02 21:05:58 +00:00
local mxy=_mix{mx,my}
2022-12-17 20:16:26 +00:00
self._coll[mxy]=
fget(self:_mget(mx,my),7) or
2022-12-31 07:30:05 +00:00
self._crates[mxy]
2022-12-17 20:16:26 +00:00
end
end
local anch_new={}
for dxy in all{{-1,-1},{1,-1},{-1,1},{1,1}} do
local dx,dy=unpack(dxy)
assert(dx!=0 and dy!=0)
for mx0=0,15 do
for my0=0,15 do
local mx1,my1=mx0+dx,my0+dy
if (
2023-01-03 04:43:59 +00:00
self:mcoll{mx0,my0} and not self:get_crate(mx0,my0) and
not self:mcoll{mx0,my1} and
not self:mcoll{mx1,my0} and
not self:mcoll{mx1,my1}
) then
2023-01-02 21:05:58 +00:00
local key=_mix{"GEOM",mx0,my0,dx,dy}
anch_new[key]= {
2023-01-01 03:02:33 +00:00
max(mx0,mx1),max(my0,my1),adx=-dx,ady=-dy
}
end
end
2022-12-20 02:01:02 +00:00
end
for _,cr in pairs(self._crates) do
2023-01-02 21:05:58 +00:00
local key=_mix{"CRATE",cr.id,dx,dy}
local mx0,my0=cr.mx,cr.my
local mx1,my1=mx0+dx,my0+dy
anch_new[key]={
2023-01-01 03:02:33 +00:00
max(mx0,mx1),max(my0,my1),adx=-dx,ady=-dy
}
end
2022-12-17 20:16:26 +00:00
end
2022-12-31 22:05:22 +00:00
local moves={}
for k,new in pairs(anch_new) do
2022-12-31 22:44:24 +00:00
local old=(self._anch or {})[k]
if old then
2022-12-31 22:44:24 +00:00
anch_new[k]=new
2023-01-01 01:27:00 +00:00
if (not _anch_eq(old,new)) add(moves,{old,new,key=k})
2022-12-17 20:16:26 +00:00
end
end
self._anch=anch_new
self._anch_keys={}
2023-01-02 21:05:58 +00:00
self._anch_by={}
2023-01-01 03:02:33 +00:00
for k,v in pairs(self._anch) do
2023-01-02 21:05:58 +00:00
local ax,ay=_anch_unpack(v)
add(self._anch_keys,{key=k})
2023-01-02 21:05:58 +00:00
local pkey=_mix{ax,ay}
self._anch_by[pkey]=self._anch_by[pkey] or v
self._anch_by[_mix{ax,ay,v.adx,v.ady}]=v
2022-12-19 01:37:00 +00:00
end
shellsort(self._anch_keys)
2022-12-31 22:05:22 +00:00
shellsort(moves)
if player.rope then
player.rope:experience_anchor_moves(moves)
end
2022-12-19 01:37:00 +00:00
2022-12-31 22:05:22 +00:00
for point in self:anchor_points() do
point.moved=nil
end
2022-12-17 20:16:26 +00:00
end
2022-12-17 23:08:54 +00:00
function level:win_at(mx,my)
2023-01-02 21:05:58 +00:00
return self._wins[_mix{mx,my}]
2022-12-17 23:08:54 +00:00
end
2022-12-17 20:16:26 +00:00
function level:anchor_points()
2022-12-31 22:44:24 +00:00
-- TODO: Return this to using all()
local keys=all(self._anch_keys)
return function()
2022-12-31 22:44:24 +00:00
local k=keys()
2022-12-31 07:30:05 +00:00
if (k) return self._anch[k.key]
end
end
2023-01-01 01:27:00 +00:00
function level:anchor_at(point)
2023-01-02 21:05:58 +00:00
return self._anch_by[_mix{_anch_unpack(point)}]
end
function level:anchor_at_tension(point,tension)
local ax,ay=_anch_unpack(point)
local adx,ady=_anch_unpack(tension)
return self._anch_by[_mix{ax,ay,adx,ady}]
2022-12-31 22:44:24 +00:00
end
2022-12-17 23:48:52 +00:00
function level:get_open_pit(mx,my)
2023-01-02 21:05:58 +00:00
local pit=self._pits[_mix{mx,my}]
2023-01-02 00:26:21 +00:00
if (pit and not pit.full) return pit
2022-12-17 23:48:52 +00:00
end
2022-12-17 23:08:54 +00:00
function level:spawn_exit()
self._wins={}
2022-12-31 07:30:05 +00:00
local spawned
2022-12-17 23:08:54 +00:00
local spawn_at=function(x,y)
if (self:_mget(x,y)!=1) return
assert(not spawned,x..","..y)
spawned=true
player:reinit(x,y)
2022-12-17 23:15:56 +00:00
player.orientx=-1
if (x<8) player.orientx=1
2022-12-17 23:08:54 +00:00
end
local win_at=function(x,y)
2022-12-18 04:39:58 +00:00
if (self:_mget(x,y)!=18) return
for nx=x-1,x+1 do
for ny=y-1,y+1 do
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
-- next check: is at least one of
-- nx or ny out of range [0, 15]?
if (nx | ny) & 0xFFF0 ~= 0 then
2023-01-02 21:05:58 +00:00
self._wins[_mix{nx,ny}]=true
end
2022-12-17 23:08:54 +00:00
end
end
end
for f in all{spawn_at,win_at} do
for x=1,14 do f(x,0) f(x,15) end
for y=0,15 do f(0,y) f(15,y) end
end
assert(spawned)
end
2023-01-03 04:43:59 +00:00
function level:mcoll(mxy)
local mx,my=unpack(mxy)
2022-12-31 22:44:24 +00:00
if ((mx | my) & 0xFFF0!=0) return true
2023-01-02 21:05:58 +00:00
return self._coll[_mix{mx,my}]
2022-12-17 20:16:26 +00:00
end
function level:get_crate(mx,my)
2023-01-02 21:05:58 +00:00
return self._crates[_mix{mx,my}]
2022-12-17 20:16:26 +00:00
end
function level:_mget(mx,my)
return mget(
self.bigx*16+mx,
self.bigy*16+my
)
end
2023-01-02 21:05:58 +00:00
function _mix(arg)
local out=arg[1]
for i=2,#arg do out..=","..arg[i] end
return out
2022-12-17 20:16:26 +00:00
end
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
-- crate spec:
-- "up" == 1
-- "right" == 2
-- "down" == 4
-- "left" == 8
--
-- +1+
-- 8 2
-- +4+
2022-12-17 20:16:26 +00:00
function level:_get_cratedef(s)
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
if (s<64 or s>=80) return
return s & 0x000F
2022-12-17 20:16:26 +00:00
end
function level:get_latch(dx,dy,px,py)
local mx,my=px\8,py\8
2023-01-02 21:05:58 +00:00
local mxy=_mix{mx,my}
2022-12-17 20:16:26 +00:00
local crate=self._crates[mxy]
2022-12-19 00:46:46 +00:00
local dx1,dy1=-sgn0(dx),-sgn0(dy)
2022-12-17 20:16:26 +00:00
if crate then
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
if crate.def & dy1*dy1*(2.5+1.5*dy1)+dx1*dx1*(5-3*dx1) ~= 0 then
2022-12-17 20:16:26 +00:00
return {
el="crate",
2022-12-19 00:46:46 +00:00
dx=dx1,dy=dy1,
ax_offset=dx1*0.5,
ay_offset=dy1*0.5,
2022-12-17 20:16:26 +00:00
rec=crate
}
end
end
local m=self:_mget(mx,my)
if
2022-12-19 00:46:46 +00:00
(m==60 and dy1<0) or
(m==61 and dx1>0) or
(m==62 and dy1>0) or
(m==63 and dx1<0)
2022-12-17 20:16:26 +00:00
then
return {
el="eyehook",
2022-12-19 00:46:46 +00:00
dx=dx1,dy=dy1,
ax_offset=dx1*0.5,
ay_offset=dy1*0.5,
rec={mx=mx,my=my,px=mx*8,py=my*8},
2022-12-17 20:16:26 +00:00
}
end
end
ropecheck=split"-0.6,0.4,0.4"
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
-- argument "o" is a rope operation:
-- array of [mx0,my0,dmx,dmy]
2022-12-17 20:16:26 +00:00
function level:can_move(
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
is_player,o,exclude_src,exclude_dst
2022-12-17 20:16:26 +00:00
)
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
local mx0,my0,dmx,dmy=unpack(o)
2022-12-23 03:07:43 +00:00
local mx1,my1=mx0+dmx,my0+dmy
if (is_player and self:win_at(mx1,my1)) return true
if (is_player and self:get_open_pit(mx1,my1)) return wrongbleep:adequately_warned()
2022-12-17 23:08:54 +00:00
2023-01-03 04:43:59 +00:00
if (self:mcoll{mx1,my1} or player.x==mx1 and player.y==my1) return
2022-12-18 00:57:47 +00:00
2022-12-17 20:16:26 +00:00
if player.rope then
local w,h=1.2,0.2
if (dmx==0) w,h=0.2,1.2
2022-12-31 07:30:05 +00:00
if (player.rope:collide_mrect(mx0+ropecheck[dmx+2],my0+ropecheck[dmy+2],w,h,exclude_src,exclude_dst)) return
2022-12-17 20:16:26 +00:00
end
return true
end
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
-- argument is a rope operation:
-- array of [mx0,my0,dmx,dmy]
-- must be a free function
-- to use as a foreach target
function level_tug_crate(t)
local self,mx0,my0,dmx,dmy=level,unpack(t)
2023-01-02 21:05:58 +00:00
local mxy0=_mix{mx0,my0}
2022-12-17 20:16:26 +00:00
local existing=self._crates[mxy0]
2022-12-23 03:07:43 +00:00
if (not existing) return
2022-12-17 20:16:26 +00:00
self._crates[mxy0]=nil
local mx1,my1=mx0+dmx,my0+dmy
2022-12-23 03:07:43 +00:00
local px1,py1=mx1*8,my1*8
2022-12-17 20:16:26 +00:00
existing.todo={
2022-12-23 03:07:43 +00:00
{px=px1+dmx,py=py1+dmy,mx=mx1,my=my1,update=function()
2022-12-31 23:07:23 +00:00
self.dirty=true
2022-12-17 20:16:26 +00:00
return true
end},
2022-12-23 03:07:43 +00:00
{px=px1,py=py1}
2022-12-17 20:16:26 +00:00
}
2023-01-02 21:05:58 +00:00
self._crates[_mix{mx1,my1}]=existing
2022-12-20 05:36:11 +00:00
end
2022-12-17 20:16:26 +00:00
-->8
--player handling
2022-12-17 20:16:26 +00:00
player={}
2022-12-18 04:38:49 +00:00
add(real_modules,player)
2022-12-17 20:16:26 +00:00
function player:init()
2022-12-18 00:25:20 +00:00
-- don't change this on reinit:
-- it stays the same when the level is changed or reloaded
self.vanish_frame=0
2022-12-17 20:16:26 +00:00
end
function player:reinit(x,y)
2022-12-23 03:22:23 +00:00
self.x,self.y=x,y
self.px,self.py=0,0
2022-12-17 20:16:26 +00:00
self.todo={}
2022-12-31 06:39:15 +00:00
self.cooldown=4
2022-12-31 07:30:05 +00:00
self.rope=nil -- don't elide, needs to be cleared if present
2022-12-17 23:48:52 +00:00
self.fall_frame=0
2022-12-17 20:16:26 +00:00
2022-12-23 03:22:23 +00:00
self.orientx,self.orienty=-1,0
2022-12-17 20:16:26 +00:00
end
function player:update()
2022-12-18 00:25:20 +00:00
-- this is a non-gameplay action that takes precedence over
-- all gameplay actions
self:_vanish_if_requested()
2022-12-23 03:22:23 +00:00
if not (#self.todo>0 or level:busy()) then
2022-12-17 23:08:54 +00:00
if level:win_at(self.x,self.y) then
level:advance()
return
end
2022-12-17 23:48:52 +00:00
if level:get_open_pit(self.x,self.y) then
self.todo={{update=self._fall}}
return
end
2022-12-18 04:38:49 +00:00
if kbd:btn(0) then
2022-12-20 00:25:38 +00:00
self.orientx=-1
self.orienty=0
2022-12-18 04:38:49 +00:00
elseif kbd:btn(1) then
2022-12-20 00:25:38 +00:00
self.orientx=1
self.orienty=0
2022-12-18 04:38:49 +00:00
elseif kbd:btn(2) then
2022-12-20 00:25:38 +00:00
self.orienty=-1
2022-12-18 04:38:49 +00:00
elseif kbd:btn(3) then
2022-12-20 00:25:38 +00:00
self.orienty=1
end
2022-12-31 06:39:15 +00:00
function btncd(x)
return (kbd:btn(x) and self.cooldown==0) or kbd:btnp(x)
end
2022-12-20 00:25:38 +00:00
if kbd:btn(4) then
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
if kbd:btnp(4) and self.rope then
2022-12-20 00:25:38 +00:00
self.rope:destroy()
kbd:release(4)
2022-12-17 20:16:26 +00:00
end
2022-12-20 00:25:38 +00:00
-- wait for user to release it
else
2022-12-31 06:39:15 +00:00
local x,y=self.x,self.y
2022-12-23 03:22:23 +00:00
local function try_move(dx,dy,f)
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
if level:can_move(true,{x,y,dx,dy},0,2) then
2022-12-31 06:39:15 +00:00
self.todo=f
self.cooldown=3
local t=f[#f]
t.x=x+dx
t.y=y+dy
return
end
2022-12-23 03:22:23 +00:00
wrongbleep:bleep()
end
2022-12-31 06:39:15 +00:00
if btncd(0) then
2022-12-31 06:41:08 +00:00
try_move(-1,0,{{orientx=-1,orienty=0,px=-2,py=0},{px=1}})
2022-12-31 06:39:15 +00:00
elseif btncd(1) then
2022-12-31 06:41:08 +00:00
try_move(1,0,{{orientx=1,orienty=0,px=2,py=0},{px=-1}})
2022-12-31 06:39:15 +00:00
elseif btncd(2) then
2022-12-31 06:41:08 +00:00
try_move(0,-1,{{orienty=-1,px=0,py=-2},{py=1}})
2022-12-31 06:39:15 +00:00
elseif btncd(3) then
2022-12-31 06:41:08 +00:00
try_move(0,1,{{orienty=1,px=0,py=2},{py=-1}})
2022-12-23 03:22:23 +00:00
elseif not self.rope and kbd:btnr(4) then
local dx,dy=self.orientx,self.orienty
2022-12-17 20:16:26 +00:00
if (dy!=0) dx=0
2023-01-03 04:43:59 +00:00
while not level:mcoll{x,y} do x+=dx y+=dy end
self.rope=rope:new(
2023-01-01 03:02:33 +00:00
{x+0.5-dx*0.5,y+0.5-dy*0.5},
{self.x+0.5,self.y+0.5},
level:get_latch(dx,dy,x*8,y*8)
)
2022-12-17 20:16:26 +00:00
self.todo={{
update=function()
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
return not self.rope or self.rope:latched()
2022-12-17 20:16:26 +00:00
end
2022-12-20 00:25:38 +00:00
}}
elseif kbd:btnp(5) then
2022-12-23 03:22:23 +00:00
if (self.rope and not self.rope:tug()) wrongbleep:bleep(9)
2022-12-17 20:16:26 +00:00
end
end
end
2022-12-31 06:39:15 +00:00
if (#self.todo==0) self.px=0 self.py=0
2022-12-17 20:16:26 +00:00
_apply(self,self.todo)
2022-12-31 06:39:15 +00:00
if (self.cooldown>0) self.cooldown-=1
2022-12-17 20:16:26 +00:00
if self.rope then
self.rope:update()
2022-12-22 03:54:09 +00:00
if self.rope:done_reeling() then
2022-12-23 03:22:23 +00:00
local latch=self.rope.latch
self.x=latch.rec.mx+latch.dx
self.y=latch.rec.my+latch.dy
2022-12-22 03:54:09 +00:00
end
2023-01-01 03:02:33 +00:00
self.rope:drag_dst{
2022-12-23 03:22:23 +00:00
self.x+self.px/8+0.5,
self.y+self.py/8+0.5
2023-01-01 03:02:33 +00:00
}
2022-12-17 20:16:26 +00:00
2022-12-18 00:57:47 +00:00
local tdx,tdy=self.rope:tug_orientxy()
2022-12-23 03:22:23 +00:00
if (tdx) self.orientx=tdx
if (tdy) self.orienty=tdy
2022-12-18 00:57:47 +00:00
2022-12-23 03:22:23 +00:00
if (self.rope:done()) self.rope=nil
2022-12-17 20:16:26 +00:00
end
end
2022-12-18 00:25:20 +00:00
function player:_vanish_if_requested()
2022-12-18 04:38:49 +00:00
if kbd:btn(5) then
2022-12-18 00:25:20 +00:00
self.vanish_frame+=1
2022-12-18 00:26:30 +00:00
if (self.fall_frame>0 or self.vanish_frame>20) then
self.rope=nil
2022-12-18 00:25:20 +00:00
level:restart()
2022-12-18 04:38:49 +00:00
kbd:release(5)
2022-12-18 00:26:30 +00:00
self.vanish_frame=20
2022-12-18 00:25:20 +00:00
end
else
self.vanish_frame-=1
2022-12-17 23:48:52 +00:00
end
2022-12-18 00:25:20 +00:00
self.vanish_frame=max(self.vanish_frame,0)
end
function player:_fall()
if (self.fall_frame<10) self.fall_frame+=1
2022-12-17 23:48:52 +00:00
end
2022-12-17 20:16:26 +00:00
function player:draw()
local px=self.x*8+self.px+wrongbleep:vibrate()
local py=self.y*8+self.py+wrongbleep:vibrate()
2022-12-18 04:38:49 +00:00
local head=1-self.orienty
2022-12-17 23:48:52 +00:00
local vanish_level=max((self.vanish_frame-4)/16,0)
2022-12-18 00:25:20 +00:00
local invis_level=max(self.fall_frame/10,4*(vanish_level-0.75))
if (invis_level>=1.0) return
2022-12-23 03:22:23 +00:00
--[[
local HEAD=14--3
local BODY=12--12
local TAIL=14--14
local IRIS=7--9
local PUPIL=0--0
2022-12-23 03:22:23 +00:00
]]
-- in order: head,body,iris,pupil,body again,tail
local palette=split"-1,14,14,12,12,-1,-1,-1,7,0,-1,12,14,14,14"
local function setpal()
--[[
-- head
nil,14,14,
--body
[2]=HEAD,
[3]=HEAD,
[4]=BODY,
[5]=BODY,
[9]=IRIS,
[10]=PUPIL,
[12]=BODY,
[13]=TAIL,
[14]=TAIL,
[15]=TAIL,
2022-12-23 03:22:23 +00:00
]]
pal(palette)
-- vanish colors
local vanish=split"13,15,14,5,4,12,2,3,9,10"
for i,ilc in ipairs(vanish) do
2022-12-31 06:45:34 +00:00
if (vanish_level>i/#vanish) pal(ilc,5)
end
2022-12-18 00:25:20 +00:00
2023-01-02 02:06:11 +00:00
if (self.fall_frame>3) local zc=@0x5f00&0xf0 for i=0x5f00,0x5f0c,4 do poke4(i,0x0505.0505) end poke(0x5f00,zc|0x01)
2022-12-17 23:48:52 +00:00
end
2022-12-22 03:54:09 +00:00
local rx,ry=self.x*8+self.px+1,self.y*8+self.py+2
if (self.orientx==1) rx+=6
if self.rope then
local rx_adj,ry_adj=self.rope:affected_src_xy{rx,ry}
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
if rx_adj then
2022-12-22 03:54:09 +00:00
local drx,dry=rx_adj-rx,ry_adj-ry
rx,ry=rx+drx,ry+dry
px,py=px+drx,py+dry
end
end
2023-01-03 04:11:25 +00:00
setpal()
2022-12-17 20:16:26 +00:00
if self.orientx==-1 then
spr(16,px+6,py-2,1,1)
spr(17,px+1,py,1,1)
if (self.rope and invis_level<=0.25) pal() self.rope:draw{self.x*8+self.px+1,self.y*8+self.py+2} setpal()
2022-12-17 20:16:26 +00:00
spr(head,px-3,py-3,1,1)
else
spr(16,px-6,py-2,1,1,true)
spr(17,px-1,py,1,1,true)
if (self.rope and invis_level<=0.25) pal() self.rope:draw{self.x*8+self.px+7,self.y*8+self.py+2} setpal()
2022-12-17 20:16:26 +00:00
spr(head,px+3,py-3,1,1,true)
end
2022-12-17 23:48:52 +00:00
pal()
2022-12-17 20:16:26 +00:00
end
-->8
-- rope physics
2022-12-17 20:16:26 +00:00
rope={}
rope.__index=rope
function rope:new(
2023-01-01 01:27:00 +00:00
src,dst,latch
2022-12-17 20:16:26 +00:00
)
local r={
id=0,
state={name="cast",frame=0},
latch=latch,
2023-01-02 20:18:30 +00:00
flicker_t=t(),
2022-12-17 20:16:26 +00:00
}
2023-01-01 01:27:00 +00:00
r.src=src
r.dst=dst
r.src.next=r.dst
r.dst.prev=r.src
2022-12-17 20:16:26 +00:00
setmetatable(r,rope)
return r
end
2022-12-18 04:10:01 +00:00
function rope:latched()
return self.state.name=="latched"
2022-12-17 20:16:26 +00:00
end
function rope:done()
2022-12-18 04:10:01 +00:00
return self.state.name=="done"
2022-12-17 20:16:26 +00:00
end
2022-12-22 03:54:09 +00:00
function rope:done_reeling()
return self.state.name=="done" and self.state.reelin
end
2022-12-17 20:16:26 +00:00
function rope:update()
2022-12-18 04:10:01 +00:00
if self.state.name=="cast" then
self.state.frame+=1
if (self.state.frame>=3) self.state={name="latched"}
2022-12-18 04:10:01 +00:00
elseif self.state.name=="latched" then
2022-12-31 07:30:05 +00:00
if (not self.latch) wrongbleep:bleep(5) self:destroy() return
2023-01-03 02:27:36 +00:00
if (self.latch.rec and self.latch.rec.dead) self:destroy()
2023-01-01 23:36:55 +00:00
if (not self:_check_pinch()) self:destroy()
2022-12-18 04:10:01 +00:00
elseif self.state.name=="destroy" then -- destroy
self.state.frame+=1
2022-12-31 06:45:12 +00:00
if (self.state.frame>=4) self.state={name="done",reelin=self.state.reelin}
2022-12-18 22:53:58 +00:00
else
-- done state
2022-12-17 20:16:26 +00:00
end
2022-12-18 04:10:01 +00:00
end
2022-12-17 20:16:26 +00:00
2022-12-22 03:54:09 +00:00
function rope:destroy(reelin)
2022-12-18 04:10:01 +00:00
if (self.state.name=="destroy" or self.state.name=="done") return
2022-12-22 03:54:09 +00:00
self.state={name="destroy",frame=0,reelin=reelin}
end
function rope:_resegment(points,artificial_pxy,cb)
local n,perc_to_show,from_end=self.state.name,1.0
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
if (n=="done") return
if (n=="cast") perc_to_show=self.state.frame/2
2022-12-31 06:45:12 +00:00
if (n=="destroy") perc_to_show=(1.0-self.state.frame/4)^2
2022-12-22 03:54:09 +00:00
if (self.state.reelin) from_end=true
local artificial_px,artificial_py=unpack(artificial_pxy)
2022-12-22 02:11:19 +00:00
points[#points]={x=artificial_px,y=artificial_py}
2022-12-19 02:14:15 +00:00
2022-12-18 04:10:01 +00:00
local len=0
for i=1,#points-1 do
len+=distance(points[i],points[i+1])
end
2023-01-03 02:27:36 +00:00
local len_to_show,ia,iz,istep=perc_to_show*len,#points-1,1,-1
if (from_end) ia,iz,istep=iz,ia,1
2022-12-18 04:10:01 +00:00
2022-12-22 03:54:09 +00:00
for i=ia,iz,istep do
2023-01-03 02:27:36 +00:00
local src,dst=points[i],points[i+1]
2022-12-18 04:10:01 +00:00
local x,y=dst.x,dst.y
local dx,dy=src.x-x,src.y-y
2023-01-03 02:27:36 +00:00
local dist_base=sqrt(dx*dx+dy*dy)
2022-12-18 04:10:01 +00:00
local coef=min(len_to_show/dist_base,1.0)
len_to_show-=dist_base
dx,dy=dx*coef,dy*coef
2022-12-22 03:54:09 +00:00
if (from_end) x,y=src.x-dx,src.y-dy
2022-12-17 20:16:26 +00:00
local v0,v1=cb(x,y,dx,dy,i)
if (coef<1) return v0,v1
end
end
function rope:affected_src_xy(artificial_pxy)
if (not self.state.reelin) return
return self:_resegment(
self:_anchors_simplified(),artificial_pxy,
function(x,y) return x,y end
)
end
2023-01-03 02:27:36 +00:00
TONGUE_SEGS=gsv[[0`0.25`1
0.25`0.9`0.5
0.9`1`1]]
function rope:draw(artificial_pxy)
local points,highlight,hypo_ops,hypo_blocks=self:_tug(true)
local function colorh(ix)
color(8)
if (highlight==ix) color(12)
end
2022-12-18 22:53:58 +00:00
self:_resegment(points,artificial_pxy,
function(x,y,dx,dy,i)
colorh(i)
2023-01-03 02:27:36 +00:00
foreach(TONGUE_SEGS,function(row)
local d0,d1,w=unpack(row)
2022-12-31 07:09:38 +00:00
linefill(x+d0*dx,y+d0*dy,x+d1*dx,y+d1*dy,w)
2023-01-03 02:27:36 +00:00
end)
circfill(x+dx,y+dy,1)
2022-12-18 04:10:01 +00:00
end
)
2022-12-19 00:46:46 +00:00
-- draw latch
2022-12-31 07:04:27 +00:00
local l=self.latch
if l and l.rec and (self.state.reelin or self:latched()) then
2022-12-31 07:04:27 +00:00
local function rfsplit(x) rectfill(unpack(split(x))) end
colorh(0)
camera(-l.rec.px,-l.rec.py)
2023-01-03 02:27:36 +00:00
if (l.dx==-1) rfsplit"0,3,2,4"
if (l.dx==1) rfsplit"5,3,7,4"
if (l.dy==-1) rfsplit"3,0,4,2"
if (l.dy==1) rfsplit"3,5,4,7"
2022-12-31 07:04:27 +00:00
camera()
color()
2022-12-19 00:46:46 +00:00
end
2023-01-02 20:18:30 +00:00
-- hypothetical
local time=t()-self.flicker_t
2023-01-03 02:27:36 +00:00
local flicker_on=time%0.5>0.25
if self:latched() and time>0 and not level:busy() then
2023-01-03 02:27:36 +00:00
if flicker_on then
foreach(hypo_ops, function(o)
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
local mx0,my0,dmx,dmy=unpack(o)
2023-01-03 02:27:36 +00:00
spr(14,(mx0+dmx)*8,(my0+dmy)*8)
end)
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
end
2023-01-03 02:27:36 +00:00
foreach(hypo_blocks, function(o)
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
local x,y,dx,dy=unpack(o)
spr(34,8*x+4*dx,8*y+4*dy,1,1,flicker_on)
2023-01-03 02:27:36 +00:00
end)
2023-01-02 20:18:30 +00:00
end
-- debug
2022-12-31 22:44:24 +00:00
--[[
local n1=self.src
local sy=0
while true do
if (n1==nil) break
2023-01-01 01:27:00 +00:00
local anch=level:anchor_at(n1)
2023-01-01 23:36:55 +00:00
local ax,ay=_anch_unpack(n1)
local x=ax*8
local y=ay*8
2022-12-31 22:44:24 +00:00
if anch then
if (anch.adx>0) x-=1
if (anch.ady>0) y-=1
end
rectfill(x-1,y-1,x+1,y+1,12)
2023-01-01 23:36:55 +00:00
print("ax="..ax..",ay="..ay,72,sy)
2022-12-31 22:44:24 +00:00
sy+=7
local n0=n1.prev
local n2=n1.next
if n0!=nil and n2!=nil then
2022-12-31 22:44:24 +00:00
if anch then
2023-01-01 23:36:55 +00:00
rectfill(x+2,y+2,x+4,y+4,3)
else
2023-01-01 23:36:55 +00:00
rectfill(x+2,y+2,x+4,y+4,2)
end
else
rectfill(x+2,y+2,x+4,y+4,4)
end
n1=n1.next
end
2022-12-17 20:16:26 +00:00
for _,p in pairs(level._anch) do
2023-01-01 23:36:55 +00:00
local ax,ay=_anch_unpack(p)
local x,y=ax*8,ay*8
if (p.adx>0) x-=1
if (p.ady>0) y-=1
pset(x,y,11)
pset(x+p.adx,y,11)
pset(x,y+p.ady,11)
2022-12-17 20:16:26 +00:00
end
2023-01-02 21:05:58 +00:00
]]--
2022-12-17 20:16:26 +00:00
end
2023-01-01 03:02:33 +00:00
function rope:drag_dst(xy)
self:drag(self.dst,xy)
2022-12-17 20:16:26 +00:00
end
2023-01-01 03:02:33 +00:00
function rope:drag(n1,axy)
self:relax()
2023-01-01 03:02:33 +00:00
self:_drag(n1,{axy[1],n1[2]})
self:_drag(n1,axy)
self:relax()
2022-12-20 02:01:02 +00:00
end
function rope:relax()
local n0=self.src
while true do
local n1=n0.next
2022-12-31 07:30:05 +00:00
if (not n1) break
local n2=n1.next
2023-01-01 01:27:00 +00:00
if _anch_eq(n0,n1) then
2023-01-01 03:02:33 +00:00
_anch_del(n1)
else
n0=n0.next
end
end
local n0=self.src
2022-12-31 07:30:05 +00:00
while n0 do
local n1=n0.next
2022-12-31 07:30:05 +00:00
if (not n1) return
local n2=n1.next
2022-12-31 07:30:05 +00:00
if (not n2) return
2023-01-02 21:05:58 +00:00
local adxy,position_new=calc_tension(n0,n1,n2)
local anch=level:anchor_at_tension(n1,adxy)
if not anch or _anch_eq(n1,position_new) then
2023-01-01 03:02:33 +00:00
self:_drag(n1,position_new,{_anch_unpack(n1)})
_anch_del(n1)
else n0=n0.next end
end
end
2023-01-01 23:36:55 +00:00
function rope:_check_pinch()
2022-12-22 03:54:09 +00:00
if (not self:latched()) return true
if (level:busy()) return true
local n0=self.src
2023-01-03 04:43:59 +00:00
local qxys={}
while true do
local n1=n0.next
2022-12-31 07:30:05 +00:00
if (not n1) break
2023-01-01 01:27:00 +00:00
local n0ax,n0ay=_anch_unpack(n0)
local n1ax,n1ay=_anch_unpack(n1)
2023-01-03 04:43:59 +00:00
_rast(qxys,n0ax\0.5,n0ay\0.5,n1ax\0.5,n1ay\0.5)
n0=n1
end
2022-12-17 21:52:37 +00:00
2023-01-03 04:43:59 +00:00
local function _possible_tiles(t)
local qx,qy=unpack(qxys[t])
local poss={}
2023-01-03 04:43:59 +00:00
for mx=(qx-1)\2,qx\2 do
for my=(qy-1)\2,qy\2 do
if (not level:mcoll{mx,my}) add(poss,{mx,my})
end
2022-12-19 00:07:15 +00:00
end
2023-01-03 04:43:59 +00:00
return all(poss)
end
-- find cases where i move through an impassable zone
2023-01-03 04:43:59 +00:00
for i=1,#qxys do
if (not _possible_tiles(i)()) return
end
-- find cases where i am cut off diagonally
2023-01-03 04:43:59 +00:00
for i=3,#qxys do
local qx1,qy1=unpack(qxys[i-1])
if (qx1|qy1)&1==0 then
2022-12-31 07:30:05 +00:00
local ok
2023-01-03 04:43:59 +00:00
for m0 in _possible_tiles(i-2) do
for m2 in _possible_tiles(i) do
local mx0,my0=unpack(m0)
local mx2,my2=unpack(m2)
if (mx0==mx2 or my0==my2 or not level:mcoll{mx0,my2} or not level:mcoll{mx2,my0}) ok=true
end
end
2022-12-19 00:07:15 +00:00
2022-12-31 07:30:05 +00:00
if (not ok) return
end
end
return true
2022-12-17 20:16:26 +00:00
end
2023-01-02 21:05:58 +00:00
function calc_tension(xy0,xy1,xy2)
2023-01-01 01:27:00 +00:00
local x0,y0=_anch_unpack(xy0)
2023-01-02 21:05:58 +00:00
local x1,y1=_anch_unpack(xy1)
2023-01-01 01:27:00 +00:00
local x2,y2=_anch_unpack(xy2)
2022-12-17 20:16:26 +00:00
2022-12-31 23:07:23 +00:00
local dx,dy=x2-x0,y2-y0
2022-12-22 05:37:26 +00:00
2022-12-31 23:07:23 +00:00
local function switch_ends()
dx,dy,x0,y0,x2,y2=-dx,-dy,x2,y2,x0,y0
end
local function signs(douter,dinner)
local adb=sgn0(dinner)
return -sgn0(douter)*adb,adb
end
local adx,ady,x1_new,y1_new
if abs(dx)>abs(dy) then
2022-12-31 23:07:23 +00:00
if (x0>x2) switch_ends()
x1_new,y1_new=x1,y0+(x1-x0)/dx*dy
adx,ady=signs(dy,y1_new-y1)
else
2022-12-31 23:07:23 +00:00
if (y0>y2) switch_ends()
x1_new,y1_new=x0+(y1-y0)/dy*dx,y1
ady,adx=signs(dx,x1_new-x1)
2022-12-17 20:16:26 +00:00
end
2023-01-02 21:05:58 +00:00
return {adx,ady},{x1_new,y1_new}
end
2022-12-17 20:16:26 +00:00
2023-01-02 21:05:58 +00:00
function would_stick(anch,tens)
adx,ady=unpack(tens)
return anch.adx==adx and anch.ady==ady
2022-12-17 20:16:26 +00:00
end
2022-12-31 22:05:22 +00:00
function rope:experience_anchor_moves(moves)
2023-01-01 23:36:55 +00:00
local latch=self.latch
2022-12-31 22:05:22 +00:00
self:_be_dragged_by(moves)
self:_be_pushed_by(moves)
2023-01-01 23:36:55 +00:00
if latch.rec then
self:_drag(self.src,{
latch.rec.mx+0.5+latch.ax_offset,
latch.rec.my+0.5+latch.ay_offset
})
end
2022-12-31 22:05:22 +00:00
self:relax()
end
function rope:_be_dragged_by(moves)
local n=self.src
while n do
for t in all(moves) do
2023-01-01 03:02:33 +00:00
local xy_old,xy_new=unpack(t)
if (_anch_eq(xy_old,n)) n.dest=xy_new break
2022-12-31 22:05:22 +00:00
end
n=n.next
end
n=self.src
while n do
2023-01-01 01:27:00 +00:00
if (n.dest) self:_drag(n,n.dest) n.dest=nil
2022-12-31 22:05:22 +00:00
n=n.next
end
end
function rope:_be_pushed_by(moves)
for i in all(moves) do
self:_be_pushed_by1(unpack(i))
end
end
2023-01-01 01:27:00 +00:00
function rope:_be_pushed_by1(anch_old,anch_new)
local n0=self.src
2023-01-01 01:27:00 +00:00
local ax_old,ay_old=_anch_unpack(anch_old)
local ax_new,ay_new=_anch_unpack(anch_new)
while n0 do
n1=n0.next
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
if (not n1) return
2023-01-01 01:27:00 +00:00
local nx0,ny0=_anch_unpack(n0)
local nx1,ny1=_anch_unpack(n1)
2022-12-29 22:54:08 +00:00
local nxmn,nxmx = _mnmx(nx0,nx1)
local nymn,nymx = _mnmx(ny0,ny1)
if
2022-12-31 22:44:24 +00:00
(ax_new!=ax_old or (nxmn<ax_new and ax_new<nxmx)) and
(ay_new!=ay_old or (nymn<ay_new and ay_new<nymx)) and
2022-12-22 05:55:21 +00:00
2023-01-01 01:27:00 +00:00
(_which_side(anch_old,n0,n1)!=
_which_side(anch_new,n0,n1)
2023-01-02 21:05:58 +00:00
) and would_stick(anch_new,calc_tension(n0,anch_new,n1))
then
local nx05,ny05
if ax_new==ax_old then
2022-12-31 22:44:24 +00:00
nx05=ax_new
ny05=ny0+(nx05-nx0)/(nx1-nx0) * (ny1-ny0)
elseif ay_new==ay_old then
2022-12-31 22:44:24 +00:00
ny05=ay_new
nx05=nx0+(ny05-ny0)/(ny1-ny0) * (nx1-nx0)
end
2023-01-01 03:02:33 +00:00
local n05=_anch_new(n0,n1,{nx05,ny05})
self:_drag(n05,{ax_new,ay_new})
else
n0=n0.next
end
end
end
2023-01-01 01:27:00 +00:00
function rope:_drag(n1,new,removing)
local function _sweep_radar(lhs,rhs,pivot,src,dst)
if (_anch_eq(src,dst)) return
2023-01-01 00:18:24 +00:00
2022-12-29 22:54:08 +00:00
local function _uncreatable(anchor)
2023-01-01 01:27:00 +00:00
return _anch_eq(anchor,lhs) or _anch_eq(anchor,lhs) or _anch_eq(anchor,removing)
2022-12-29 22:54:08 +00:00
end
2023-01-01 03:02:33 +00:00
local function _sweep(extent_orig,extent_final,cb_in_bounds,cb_make_point)
local eligible={}
local point_orig=cb_make_point(extent_orig)
local point_final=cb_make_point(extent_final)
for anchor in level:anchor_points() do
-- figure out which anchors we even can stick to
if cb_in_bounds(anchor) and not _uncreatable(anchor) then
local side_orig=_which_side(anchor,pivot,point_orig)
local side_final=_which_side(anchor,pivot,point_final)
2023-01-02 21:05:58 +00:00
if (side_orig!=side_final and would_stick(anchor,calc_tension(pivot,anchor,point_final))) add(eligible,{anchor,side_final})
2023-01-01 03:02:33 +00:00
end
end
-- if no one's in the race, don't raycast
if (#eligible==0) return
if (#eligible==1) return eligible[1][1]
-- see who wins the race
for extent in _stepfrom(extent_orig,extent_final) do
local point = cb_make_point(extent)
for anchor_final in all(eligible) do
if (_which_side(anchor_final[1],pivot,point)==anchor_final[2]) return anchor_final[1]
end
end
2023-01-01 00:18:24 +00:00
end
2023-01-01 03:02:33 +00:00
local ax_pivot,ay_pivot=_anch_unpack(pivot)
local ax_src,ay_src=_anch_unpack(src)
local ax_dst,ay_dst=_anch_unpack(dst)
if ax_src==ax_dst then
2023-01-01 00:18:24 +00:00
return _sweep(
2023-01-01 03:02:33 +00:00
ay_src,ay_dst,
function(anchor) return mid(ax_pivot,anchor[1],ax_dst)==anchor[1] end,
function(ay) return {ax_dst,ay} end
2023-01-01 00:18:24 +00:00
)
else
return _sweep(
2023-01-01 03:02:33 +00:00
ax_src,ax_dst,
function(anchor) return mid(ay_pivot,anchor[2],ay_dst)==anchor[2] end,
function(ax) return {ax,ay_dst} end
2023-01-01 00:18:24 +00:00
)
2022-12-17 20:16:26 +00:00
end
end
2023-01-01 03:02:33 +00:00
local old={_anch_unpack(n1)}
_anch_update(n1,new)
2022-12-17 20:16:26 +00:00
local n0=n1.prev
2022-12-31 07:30:05 +00:00
while n0 do
2023-01-01 01:27:00 +00:00
local anch=_sweep_radar(n0,n1,n0,old,new)
2022-12-31 07:30:05 +00:00
if (not anch) break
2023-01-01 03:02:33 +00:00
n0=_anch_new(n0,n1,anch)
end
2022-12-17 20:16:26 +00:00
local n2=n1.next
2022-12-31 07:30:05 +00:00
while n2 do
2023-01-01 01:27:00 +00:00
local anch=_sweep_radar(n1,n2,n2,old,new)
2022-12-31 07:30:05 +00:00
if (not anch) break
2023-01-01 03:02:33 +00:00
n2=_anch_new(n1,n2,anch)
2022-12-17 20:16:26 +00:00
end
end
function _stepfrom(x0,x1)
2022-12-31 07:30:05 +00:00
local done
if x0==x1 then
return function()
Save some tokens in horrible, horrible ways. (#13) replace comparisons with bit math bullshit integers in the range [0, 15] fit entirely in the bit mask 0x000F. integers out of that range will have at least one bit 0x0010 or higher, or will have the sign bit 0x8000 set. so to find out if one of two numbers is out of range [0, 15], we can check the bit mask of their bitwise or. this saves tokens and cycles. it is also completely illegible. very in the spirit of Pico-8, I love it. comment the bullshit it needs it packed crate representation don't bother exploding crates into four bools, and then comparing them all individually to a bunch of conditions. absurd bit manipulation bullshit saves cycles and tokens. leaving a crate's movement rule represented as four bits means we can exploit our previous calculation of dx1 and dy1, which must each either be 0x0001 or 0x8FFF, and violently hammer them down to align with this bit-packed representation, giving this glorious little atrocity. Fix crate math. I forgot that -1 & 1 = 1 rather than 0 so all the bit math didn't work. But I can fix it with polynomial algebra! this is much better. Save tokens on movemebnt checks I promise this is mathematically equivalent-ish to the original. (0.2 and its multiples are nonterminating decimals in base 2, so there's a little jank when the negative shift right is a shift left.) Trimming Trim up redundant nil checks, sequential assignments that could be on a shared line, and repeated references to a deeply nested variable. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/13 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2022-12-24 00:08:10 +00:00
if (done) return
done=true return x0
2022-12-17 20:16:26 +00:00
end
end
2023-01-01 03:02:33 +00:00
local mul=1
if (x0>x1) x0,x1,mul=-x0,-x1,-mul
local i=flr(x0)
local top=flr(x1)
return function()
2022-12-31 07:30:05 +00:00
if (done) return
i+=1
if i>top then
done = true
if (x1!=flr(x1)) return mul*x1
2022-12-31 07:30:05 +00:00
return
end
return mul*i
end
2022-12-17 20:16:26 +00:00
end
2023-01-01 01:27:00 +00:00
function _which_side(xy,x0y0,x1y1)
local x,y=_anch_unpack(xy)
local x0,y0=_anch_unpack(x0y0)
local x1,y1=_anch_unpack(x1y1)
return sgn0((x1-x0)*(y-y0) - (y1-y0)*(x-x0))
2022-12-17 20:16:26 +00:00
end
function distance(p1,p2)
local dx=p2.x-p1.x
local dy=p2.y-p1.y
return sqrt(dx*dx+dy*dy)
end
function rope:collide_mrect(mx0,my0,mw,mh,exclude_src,exclude_dst)
local mx1,my1=mx0+mw,my0+mh
local n0=self.src
while true do
local n1=n0.next
2022-12-31 07:30:05 +00:00
if (not n1) return
local nd=n0
for i=1,exclude_dst do
nd=nd.next
2022-12-31 07:30:05 +00:00
if (not nd) return
end
2023-01-01 03:02:33 +00:00
local x1,y1=_anch_unpack(n0)
local x2,y2=_anch_unpack(n1)
2022-12-22 19:25:31 +00:00
local function _line_line(x3,y3,x4,y4)
2022-12-31 07:30:05 +00:00
local denom=(y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)
2022-12-22 19:25:31 +00:00
local ua=
((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/denom
2022-12-31 07:30:05 +00:00
if (ua<0 or ua>1) return
2022-12-22 19:25:31 +00:00
local ub=
((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/denom
2022-12-31 07:30:05 +00:00
if (ub<0 or ub>1) return
2022-12-22 19:25:31 +00:00
return true
end
if exclude_src<=0 then
2022-12-22 19:25:31 +00:00
if (_line_line(mx0,my0,mx1,my0) or _line_line(mx0,my0,mx0,my1) or _line_line(mx0,my1,mx1,my1) or _line_line(mx1,my0,mx1,my1)) return true
end
exclude_src-=1
n0=n1
2022-12-17 20:16:26 +00:00
end
end
-->8
-- moved here because it's complicated
2022-12-18 00:57:47 +00:00
function rope:tug_orientxy()
local a1=self.dst
local a0=self.dst.prev
2023-01-01 03:02:33 +00:00
local ax0,ay0=_anch_unpack(a0)
local ax1,ay1=_anch_unpack(a1)
local dx=ax0-ax1
2022-12-31 07:30:05 +00:00
local tdx
if (dx>3/8) tdx=1
if (dx<-3/8) tdx=-1
2022-12-18 00:57:47 +00:00
2023-01-01 03:02:33 +00:00
local dy=ay0-ay1
2022-12-31 07:30:05 +00:00
local tdy
2022-12-18 00:57:47 +00:00
if abs(dy)>abs(dx)/2 then
if (dy>3/8) tdy=1
if (dy<-3/8) tdy=-1
2022-12-18 00:57:47 +00:00
end
return tdx,tdy
end
2022-12-17 20:16:26 +00:00
function rope:tug()
2022-12-18 04:10:01 +00:00
if (not self:latched()) return
2023-01-02 20:18:30 +00:00
local success=self:_tug()
if (success) self.flicker_t=t()
return success
2022-12-17 20:16:26 +00:00
end
2022-12-18 22:53:58 +00:00
function rope:_tug(hypothetically)
2022-12-17 20:16:26 +00:00
local ancs=self:_anchors_simplified()
local touched={}
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
local blocks = {}
2022-12-17 20:16:26 +00:00
for i=#ancs-1,2,-1 do
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
local ops_before_trash,blocks_before_trash=self:_calc_push(ancs[i+1],ancs[i],ancs[i-1],ancs[i-2])
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
local ops = {}
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
for b in all(blocks_before_trash) do add(blocks, b) end
2022-12-19 00:07:15 +00:00
if #ops_before_trash>0 then
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
ops=ops_before_trash
2022-12-19 00:07:15 +00:00
else
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
local ops_after_trash,blocks_after_trash=self:_calc_push(ancs[i-2],ancs[i-1],ancs[i],ancs[i+1])
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
ops=ops_after_trash
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
for b in all(blocks_after_trash) do add(blocks,b) end
2022-12-19 00:46:46 +00:00
end
2022-12-18 22:53:58 +00:00
if #ops>0 then
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
if (hypothetically) return ancs,i-1,ops,blocks
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
foreach(ops, level_tug_crate)
2022-12-20 00:38:21 +00:00
return true
2022-12-17 20:16:26 +00:00
end
end
local latch=self.latch
2022-12-31 07:30:05 +00:00
if latch and latch.el=="eyehook" then
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
if (hypothetically) return ancs,0,{},blocks
2022-12-22 03:54:09 +00:00
player.todo={{
update=function(s)
2022-12-31 07:30:05 +00:00
if not s.rope or s.rope:done() then
2022-12-22 03:54:09 +00:00
return true
end
end
}}
self:destroy(true)
return true
end
2022-12-31 07:30:05 +00:00
if latch and latch.el=="crate" then
2022-12-17 20:16:26 +00:00
local dmx,dmy=
sgn0(latch.dx),
sgn0(latch.dy)
2022-12-19 00:07:15 +00:00
local obj_anc=ancs[1]
local pull_anc=ancs[2]
2022-12-19 00:07:15 +00:00
local pull_dx=pull_anc.x-obj_anc.x
local pull_dy=pull_anc.y-obj_anc.y
2022-12-17 20:16:26 +00:00
local mx0=latch.rec.mx
local my0=latch.rec.my
2022-12-19 00:07:15 +00:00
local mxa=(pull_anc.x+dmx)\8
local mya=(pull_anc.y+dmy)\8
2022-12-17 20:16:26 +00:00
2022-12-31 07:30:05 +00:00
local invalid_move
2022-12-17 20:16:26 +00:00
if
2022-12-19 00:07:15 +00:00
(dmx!=0 and sgn0(pull_dx)!=dmx) or
(dmy!=0 and sgn0(pull_dy)!=dmy) or
2022-12-17 20:16:26 +00:00
sgn0(mx0-mxa)!=
sgn0(mx0+dmx-mxa) or
sgn0(my0-mya)!=
sgn0(my0+dmy-mya)
then
invalid_move=true
2022-12-17 20:16:26 +00:00
end
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
if not invalid_move then
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
local mv = {mx0,my0,dmx,dmy}
if level:can_move(false,mv,1,0) then
if (hypothetically) return ancs,0,{mv},blocks
2022-12-18 22:53:58 +00:00
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
level_tug_crate(mv)
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
return true
else
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
add(blocks, mv)
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
end
2022-12-17 20:16:26 +00:00
end
end
2022-12-18 22:53:58 +00:00
if (hypothetically) return ancs,32767,{},blocks -- invalid
2022-12-31 07:30:05 +00:00
return
2022-12-17 20:16:26 +00:00
end
function rope:_calc_push(
2022-12-19 01:20:59 +00:00
an,a0,a1,af
2022-12-17 20:16:26 +00:00
)
local ops={}
2022-12-31 07:30:05 +00:00
if (not an) return ops
2022-12-19 01:20:59 +00:00
2023-01-02 03:17:20 +00:00
local ax0,ay0=_anch_unpack(a0)
local ax1,ay1=_anch_unpack(a1)
local anch=level:anchor_at(a0)
2023-01-02 04:18:38 +00:00
if (not anch) return ops
2023-01-02 03:17:20 +00:00
if ax0==ax1 then
2022-12-19 01:20:59 +00:00
-- no far side applying pressure?
2022-12-17 20:16:26 +00:00
local y0,y1=_mnmx(a0.y,a1.y)
2022-12-18 22:53:58 +00:00
local my0,my1,smy=(y0+1)\8,(y1-1)\8,1
if a0.y>a1.y then
my0,my1=my1,my0
smy=-smy
end
2022-12-17 20:16:26 +00:00
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
local dmx=1 -- maybe push right?
2023-01-02 03:17:20 +00:00
if anch.adx==-1 and a0.x>an.x+7 then
2022-12-17 20:16:26 +00:00
-- push left
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
ax0, dmx=ax0-1,-1
elseif anch.adx!=1 or a0.x>=an.x-7 then
2022-12-17 20:16:26 +00:00
return {}
end
2022-12-18 22:53:58 +00:00
for my=my0,my1,smy do
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
add(ops,{ax0,my,dmx,0})
2022-12-17 20:16:26 +00:00
end
end
2023-01-02 03:17:20 +00:00
if ay0==ay1 then
2022-12-17 20:16:26 +00:00
local x0,x1=_mnmx(a0.x,a1.x)
2022-12-18 22:53:58 +00:00
local mx0,mx1,smx=(x0+1)\8,(x1-1)\8,1
if a0.x>a1.x then
mx0,mx1=mx1,mx0
smx=-smx
end
2022-12-17 20:16:26 +00:00
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
local dmy=1 -- maybe push down?
2023-01-02 03:17:20 +00:00
if anch.ady==-1 and a0.y>an.y+6 then
2022-12-17 20:16:26 +00:00
-- push up
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
ay0,dmy=ay0-1,-1
elseif anch.ady!=1 or a0.y>=an.y-6 then
2022-12-17 20:16:26 +00:00
return {}
end
2022-12-18 22:53:58 +00:00
for mx=mx0,mx1,smx do
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
add(ops,{mx,ay0,0,dmy})
2022-12-17 20:16:26 +00:00
end
end
2022-12-19 00:46:46 +00:00
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
local ops2,blocked={},{}
2022-12-19 00:46:46 +00:00
for o in all(ops) do
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
local mx,my=unpack(o)
2023-01-03 04:43:59 +00:00
if level:mcoll{mx,my} then
Assorted token golf in rope logic (#25) Remove unused vars, convert tug_crate arg to table The tug_crate conversion is for performance. `foreach(tbl, predefined_func)` is substantially faster than a standard `for` loop using the `all` iterator. However, if the function inside the foreach is defined inline, it's much slower due to closure-construction overhead (even though nothing is being closed over). Converting `tug_crate` to take a table as an argument allows foreach to feed right into it, and it also naturally suggests a rewrite a few lines down to get rid of duplicative listing of `mx0,my0,dmx,dmy`, saving several tokens. I'm going to take a look at can_move to see if it's worth making iits mx0,my0,dmx,dmy arguments into a table as well. can_move also takes a rope operation table this is approximately token-neutral but performance-saving. each function parameter makes its call cost worse. When can_move is called inside a loop, we already have a table and we unpack to call can_move; moving the unpack into can_move saves us marshalling cost. It requires us to construct a table in a different spot (where we were not previously doing so) but that spot is not in a loop. calc_push op loop golf Reorganizing conditionals saves tokens here. Fix syntax errors. This also saves a few tokens and cycles by turning level:tug_crate into a free function. It's not _pretty_ but it's the least bad option. _calc_push golf redux Removed unnecessary variable declarations and conditional cases by using an "assume, alternate, verify assumption" pattern and reusing ax0/ay0 when they would never be referenced again. Fix syntax errors. Slightly more efficient fix to level_tug_crate. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/25 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-03 01:06:57 +00:00
if (not level:get_crate(mx, my)) break
if not level:can_move(false,o,0,0) then
add(blocked,o)
2022-12-31 07:30:05 +00:00
break
2022-12-19 00:46:46 +00:00
end
add(ops2,o)
end
end
Show blocked crate moves (#24) Save/load system. Not golfed. Saves the music flag, the last level the player played, and the furthest level reached. Loads music flag on launch. Title screen starts on most recent level played; when in "release configuration" the title screen will only let the player pick levels up to the maximum reached through gameplay, but right now this is replaced with the 31. Save file can be wiped by holding the down arrow at the title screen. block writes while reading Disabling writes during "wipe" and "first load" is not quite semantically what we want, it's writes during read we want to block. This happens because turning the music on or off tries to save the state, and it's easier to just ignore that persistence request than to rework the music code so it doesn't. "wipe" and "first load" are when we're actually reading (and enacting) state, but it's the act of reading rather than those two acts that should block writes. It is also unwilling to write until it's done its first read, which I think is a feature; it makes it harder to accidentally blank out the player's data. Show blocked moves as an animated X. I am not convinced the sprite is very good. This could help the player learn what pulls were considered before proposing the ones that would occur if the player pulled the tongue. Or it's just visual noise that sucks. Anyway, this correctly captures what the blocked considered moves were, and we can decide whether to use it or not. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/24 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 23:08:10 +00:00
return ops2,blocked
2022-12-17 20:16:26 +00:00
end
function rope:_anchors_simplified()
-- todo: cache this
local points={}
local _slope = function(p0,p1)
return atan2(p1.y-p0.y,p1.x-p0.x)
end
a=self.src
2022-12-31 07:30:05 +00:00
while a do
2023-01-01 03:02:33 +00:00
local ax,ay=_anch_unpack(a)
local point={
2023-01-01 03:02:33 +00:00
ax,ay,
x=flr(ax*8+0.5),y=flr(ay*8+0.5),
}
2023-01-01 01:27:00 +00:00
local aw=level:anchor_at(a)
2022-12-22 19:25:31 +00:00
local l=self.latch
if aw then
if (aw.adx==1) point.x-=1
if (aw.ady==1) point.y-=1
2022-12-31 07:30:05 +00:00
elseif not a.prev and l then
2022-12-22 19:25:31 +00:00
if (l.ax_offset<0) point.x-=1
if (l.ay_offset<0) point.y-=1
end
2022-12-22 19:25:31 +00:00
local p0,p1=points[#points-1],points[#points]
2022-12-31 07:30:05 +00:00
if not p0 then
add(points,point)
2022-12-22 19:25:31 +00:00
elseif _slope(p0,p1)==_slope(p1,point) then -- epsilon?
points[#points]=point
2022-12-17 20:16:26 +00:00
else
add(points,point)
2022-12-17 20:16:26 +00:00
end
a=a.next
2022-12-17 20:16:26 +00:00
end
return points
end
2022-12-20 00:38:21 +00:00
-->8
--wrongbleeps
wrongbleep={}
add(modules,wrongbleep)
2022-12-20 00:38:21 +00:00
add(real_modules,wrongbleep)
function wrongbleep:init()
self.duration=0
self.continuous=0
2022-12-20 00:38:21 +00:00
end
function wrongbleep:update()
if (self.duration>5) self.duration=5
if self.duration>0 then
sfx(63,3)
self.continuous+=1
else
self.continuous=0
end
self.duration=max(self.duration-1,-4)
2022-12-20 00:38:21 +00:00
end
function wrongbleep:bleep(duration)
self.duration+=duration or 2
end
function wrongbleep:vibrate(duration)
if (self.continuous<10) return 0
return (rnd()*2-1)*min(self.continuous/10,2)
end
function wrongbleep:adequately_warned(duration)
return self.continuous>45
end
2022-12-20 00:38:21 +00:00
2022-12-17 20:16:26 +00:00
2022-12-22 02:11:19 +00:00
-->8
-- text
level_text={by_lvl={}}
add(real_modules,level_text)
2023-01-02 00:14:23 +00:00
level_text_raw=gsv[[
0`9`11`press 🅾️ to mlem & unmlem,
0`33`17`❎ to yoink]]
2022-12-22 02:11:19 +00:00
function level_text:init()
2023-01-02 00:14:23 +00:00
for i=0,31 do self.by_lvl[i]={} end
2022-12-22 02:11:19 +00:00
for row in all(level_text_raw) do
2023-01-02 00:14:23 +00:00
if (row) add(self.by_lvl[row[1]],row)
2022-12-22 02:11:19 +00:00
end
end
2023-01-02 00:14:23 +00:00
function level_text:draw2()
for xys in all(self.by_lvl[level.ix]) do
print(xys[4],xys[2],xys[3],7)
2022-12-22 02:11:19 +00:00
end
end
-->8
--hint system
--hint file format:
-- each row is one hint.
-- 4 or 5 columns
-- separated with a
-- grave (`) character
-- [1] room#
-- [2] x coord
-- [3] y coord
-- [4] message line 1 (rot13)
-- [5] message llne 2 (rot13)
2023-01-01 22:55:02 +00:00
-- [6] arrow (semicolon separated list: each element is two comma-separated integers)
-- row 5 can be omitted
-- for a 1-line hint
2023-01-01 22:55:02 +00:00
-- row 6 can be omitted if there is no arrow
--
-- multiple hints for the same
-- room are revealed in order
hints = {}
add(real_modules,hints)
function hints:init()
2023-01-02 00:11:20 +00:00
local h = gsv[[0`42`57`🅾️ pULL` ■
0`42`73`❎, ❎ pULL``69,67;55,67
1`35`33`⁘` pULL`62,35;41,35
1`79`82`pULL ■``100,94;100,88
1`42`98`⁘`IGNORE`66,99;52,99;52,75;28,75;28,120
2023-01-01 22:55:02 +00:00
2`75`65` `⁘`86,67;76,67;76,71
2023-01-02 00:11:20 +00:00
2`104`73` ■`pULL`81,75;86,75
2023-01-01 22:55:02 +00:00
2`27`42`⁘``36,16;36,44;31,44
3`51`106`■``52,97;52,104
3`-1`-1```28,78;28,45
3`-1`-1```65,35;83,35
2023-01-02 04:18:38 +00:00
3`-1`-1```97,35;105,35
24`-1`-1```41,51;47,51
24`59`49`■
24`-1`-1```75,62;75,51
24`-1`-1```78,49;67,49
24`-1`-1```36,62;36,51
24`-1`-1```56,59;56,51
24`67`17`■
24`-1`-1```62,83;58,83
]]
for rec in all(h) do
2023-01-01 22:55:02 +00:00
if(rec[6]) rec[6]=gsv(rec[6],";",",")
local lh = self[rec[1]]
if lh then
add(lh,rec)
else
self[rec[1]] = {rec}
end
end
menuitem(1,"get hint",function() level.hintlevel+=1 end)
menuitem(2,"hide hints",function() level.hintlevel=0 end)
end
Better debug mouse (#20) Debug mouse is now its own module, so it can be separated from the hint system, since it is useful for more than just positioning hints. It now has the following enhancements: 1. Clock-based table cyclng now has a helper function (cycle) 2. Debug mouse color cycling is distinct from hint color cycling, so debug position readout remains legible 3. Debug position readout now stays on screen even when the cursor is near or past the edges 4. Debug cursor cycles between a mouse sprite specifically marking the exact pixel that is being sampled, an "X" for text character sizing, and a "□" for positioning the centered 3x3 characters often used as hint target markers 5. Map cell coordinates (in square brackets) are displayed in addition to pixel coordnates (in parentheses) Sprite 50 is now the mouse cursor. Color 15 is color cycling for debug readouts. Debug mouse features can be disabled by commenting out `add(real_modules, debugmouse)`. I've done a little bit of golfing but this is stiill a token expense. I'm going to write a crappy sprintf function to save tokens everywhere we're assembling strings from their component parts. Simplify debug info display. Save tokens by omitting parentheses and map coordinates. Adjust location to match. Instead of cycling between symbols, the cursor shape can be chosen by using left, right, or both mouse buttons. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/20 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 00:31:34 +00:00
hintflicker=split"7,10,9,8,8,9,10,7"
function hints:draw2()
pal()
Better debug mouse (#20) Debug mouse is now its own module, so it can be separated from the hint system, since it is useful for more than just positioning hints. It now has the following enhancements: 1. Clock-based table cyclng now has a helper function (cycle) 2. Debug mouse color cycling is distinct from hint color cycling, so debug position readout remains legible 3. Debug position readout now stays on screen even when the cursor is near or past the edges 4. Debug cursor cycles between a mouse sprite specifically marking the exact pixel that is being sampled, an "X" for text character sizing, and a "□" for positioning the centered 3x3 characters often used as hint target markers 5. Map cell coordinates (in square brackets) are displayed in addition to pixel coordnates (in parentheses) Sprite 50 is now the mouse cursor. Color 15 is color cycling for debug readouts. Debug mouse features can be disabled by commenting out `add(real_modules, debugmouse)`. I've done a little bit of golfing but this is stiill a token expense. I'm going to write a crappy sprintf function to save tokens everywhere we're assembling strings from their component parts. Simplify debug info display. Save tokens by omitting parentheses and map coordinates. Adjust location to match. Instead of cycling between symbols, the cursor shape can be chosen by using left, right, or both mouse buttons. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/20 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 00:31:34 +00:00
local c=cycle(hintflicker)
2023-01-01 22:55:02 +00:00
local function body()
for i,h in ipairs(self[level.ix]) do
if (i > level.hintlevel) return
local _,x,y,txt,txt2,arrow=unpack(h)
print(txt,x,y)
if (txt2) print(txt2,x,y+8)
if arrow then
line()
local x0,y0,x1,y1
for i=1,#arrow do
x0,y0,x1,y1=x1,y1,unpack(arrow[i])
line(x1,y1)
end
local dir=atan2(x1-x0,y1-y0)
local function _ahead(d,r)
line(x1+r*sgn0(cos(dir+d)),y1+r*sgn0(sin(dir+d)))
end
_ahead(0.375,2) _ahead(0.625,2) _ahead(0,0)
end
end
end
2023-01-01 22:55:02 +00:00
color(7)
camera(1,-1) pal(7,1) body()
camera() pal(7,c) body()
pal()
end
Better debug mouse (#20) Debug mouse is now its own module, so it can be separated from the hint system, since it is useful for more than just positioning hints. It now has the following enhancements: 1. Clock-based table cyclng now has a helper function (cycle) 2. Debug mouse color cycling is distinct from hint color cycling, so debug position readout remains legible 3. Debug position readout now stays on screen even when the cursor is near or past the edges 4. Debug cursor cycles between a mouse sprite specifically marking the exact pixel that is being sampled, an "X" for text character sizing, and a "□" for positioning the centered 3x3 characters often used as hint target markers 5. Map cell coordinates (in square brackets) are displayed in addition to pixel coordnates (in parentheses) Sprite 50 is now the mouse cursor. Color 15 is color cycling for debug readouts. Debug mouse features can be disabled by commenting out `add(real_modules, debugmouse)`. I've done a little bit of golfing but this is stiill a token expense. I'm going to write a crappy sprintf function to save tokens everywhere we're assembling strings from their component parts. Simplify debug info display. Save tokens by omitting parentheses and map coordinates. Adjust location to match. Instead of cycling between symbols, the cursor shape can be chosen by using left, right, or both mouse buttons. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/20 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 00:31:34 +00:00
-->8
-- debug mouse support
debugmouse = {}
-- comment this out to disable debug mode
add(real_modules, debugmouse)
function debugmouse:init()
poke(0x5f2d,1)
end
debugflicker=split"5,6,7,15,14,8,2,4,9,10,11,3,12,13"
debugchs = split" ,□,x"
function debugmouse:draw3()
if (stat(34) == 0) return
pal(15,cycle(debugflicker,1.5))
local x, y, c = stat(32), stat(33), debugchs[stat(34) & 0x3]
if not c or c == " " then
spr(50,x,y)
else
print(c,x,y,15)
end
print(x..", "..y,
mid(0,x,97),
mid(0, y > 117 and y - 6 or y + 6, 117),
15)
pal()
end
-->8
-- save/load
persist={}
add(modules, persist)
add(real_modules, persist)
function persist:init0()
cartdata("ulimate_lizard_total_destruction_0_1")
self.init0 = self.read
self:read()
end
function persist:read()
self.ready=false
local m = dget(0) == 0
self.music = m
if m then music_on() else music_off() end
self.max_level = dget(1)
self.recent_level = dget(2)
self.ready=true
end
function persist:wipe()
for i=0,64 do
dset(i,0)
end
self:read()
end
function persist:lvlstart()
self.recent_level = level.ix
self.max_level = max(self.max_level, level.ix)
self:write()
end
function persist:write()
if (not self.ready) return
dset(0, self.music and 0 or -1)
dset(1, self.max_level)
dset(2, self.recent_level)
end
2022-12-17 20:16:26 +00:00
__gfx__
2023-01-02 20:18:30 +00:00
000030000000002200003000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeff1ff1ff1fffffff1ffffff1fffffff1dddddddd111111110000000033300333
003333300000332200333330eeffffffffffffffffffffeee5e555e55e555e5eff1ff1ffffffffffffffffffffffffffdddddddd111111110cc00cc033300333
099333990039932009333339effeeeeeeeeeeeeeeeeeeffee5eeeeeeeeeeee5eff1ff1ffff111111ff1111ff111111ffdddddddd111111110cccccc033333333
09a333a9033a932009333339efee33e3333e333e3333eefee5e333e333333e5eff1ff1ffff1fffffff1ff1fffffff1ffdddddddd1111111100c00c0000300300
023333323333320000222220efe333e3333e333e33333efee5e333e333333e5eff1ff1ffff1fffffff1ff1fffffff1ffdddddddd1111111100c00c0000300300
002222200000220000222220efe33eeeeeeeeeeeeee33efeeee33eeeeee33eeeff1111ffff111111ff1ff1ff111111ffdddddddd111111110cccccc033333333
000222c002222c0000022200efeeee555e555e55e5eeeefee5eeeeffffeeee5effffffffffffffffff1ff1ffffffffffdddddddd111111110cc00cc033300333
00000cc00000cc0000000cc0efe33e5eeeeeeeeee5e33efee5e33efeefe33e5e1ffffff11fffffffff1ff1fffffffff1dddddddd111111110000000033300333
0000ff000000000000000000efe33e5e11111111e5e33efee5e33efeefe33e5eff1ff1ffffffffffffffffffffffffff88888888555555555555555588888888
000f00f0000000000aa00aa0efe33eee11ffff11eee33efeeee33effffe33e5eff1ff1ffffffffffffffffffffffffff88888888558855885588558888888888
00d0000f000000000aaaaaa0efe33e5e1ff11ff1e5e33efee5e33eeeeee33eeeff1ff1fffff11111ffffffff11111fff88888888888888888888888888888888
00d0d00f00c040500aaaaaa0efeeee5e1f1111f1e5eeeefee5e333e333333e5eff1ff1fffff1ffffff1111ffffff1fff88888888888888888888888888888888
00dd00ee00c4455000999900efe33e5e1f1111f1e5e33efee5e333e333333e5eff1111fffff1ffffff1ff1ffffff1fff88888888888888888888888888888888
00000ee00c44455500aaaa00efe33eee1ff11ff1eee33efeeeeeeeeeeeeeee5efffffffffff11111ff1ff1ff11111fff88888888888888888888888888888888
00eeee000c004005000aa000efe33e5e11ffff11e5e33efee5555e555e555e5effffffffffffffffff1ff1ffffffffff88888888888888888855885588558855
eeee0000cc04405500444400efeeee5e11111111e5eeeefeeeeeeeeeeeeeeeeeffffffffffffffffff1ff1ffffffffff88888888888888885555555555555555
00000000000a900000000000efe33eeeeeeeeeeeeee33efeff1ff1ffffffffffffffffff00000000000000000000000000000000000000000000000000000000
00000aaaaaaa910000000000efe33e5555e555e555e33efeff1ff1ffffffffffffffffff00000000000000000000000000000000000000000000000000000000
0000aaaaaa1a911000a00200efe33eeeeeeeeeeeeee33efeff1ff1ff11111111ff1111ff00000000000000000000000000000000000000000000000000000000
0aaaaaaaaa1a9111000a2000efe333e3333e333e33333efeff1ff1ffffffffffff1ff1ff00000000000000000000000000000000000000000000000000000000
0aaaaaaaa41a91a10002a000efee33e3333e333e3333eefeff1ff1ffffffffffff1ff1ff00000000000000000000000000000000000000000000000000000000
0a000aa4441a91a100200a00effeeeeeeeeeeeeeeeeeeffeff1ff1ff11111111ff1111ff00000000000000000000000000000000000000000000000000000000
00a0044449a110a100000000eeffffffffffffffffffffeeff1ff1ffffffffffffffffff00000000000000000000000000000000000000000000000000000000
000aa1119911111000000000eeeeeeeeeeeeeeeeeeeeeeeeff1ff1ffffffffffffffffff00000000000000000000000000000000000000000000000000000000
Better debug mouse (#20) Debug mouse is now its own module, so it can be separated from the hint system, since it is useful for more than just positioning hints. It now has the following enhancements: 1. Clock-based table cyclng now has a helper function (cycle) 2. Debug mouse color cycling is distinct from hint color cycling, so debug position readout remains legible 3. Debug position readout now stays on screen even when the cursor is near or past the edges 4. Debug cursor cycles between a mouse sprite specifically marking the exact pixel that is being sampled, an "X" for text character sizing, and a "□" for positioning the centered 3x3 characters often used as hint target markers 5. Map cell coordinates (in square brackets) are displayed in addition to pixel coordnates (in parentheses) Sprite 50 is now the mouse cursor. Color 15 is color cycling for debug readouts. Debug mouse features can be disabled by commenting out `add(real_modules, debugmouse)`. I've done a little bit of golfing but this is stiill a token expense. I'm going to write a crappy sprintf function to save tokens everywhere we're assembling strings from their component parts. Simplify debug info display. Save tokens by omitting parentheses and map coordinates. Adjust location to match. Instead of cycling between symbols, the cursor shape can be chosen by using left, right, or both mouse buttons. Reviewed-on: https://git.chromaticdragon.app/pyrex/chameleonic/pulls/20 Co-authored-by: Kistaro Windrider <kistaro@gmail.com> Co-committed-by: Kistaro Windrider <kistaro@gmail.com>
2023-01-02 00:31:34 +00:00
0000000099100000f765000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111999999111111111
00000000990000007700000000000000000000000000000000000000000000000000000000000000000000000000000019911991999999911999999119999999
00000000990000006060000000000000000000000000000000000000000000000000000000000000000000000000000019977991999999911999999119999999
00000000090000005005000000000000000000000000000000000000000000000000000000000000000000000000000019911991999117111991199111711999
00000000aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000019911991999117111991199111711999
0000000077a000000000000000000000000000000000000000000000000000000000000000000000000000000000000019999991999999911997799119999999
00000007777a00000000000000000000000000000000000000000000000000000000000000000000000000000000000019999991999999911991199119999999
00044444444444000000000000000000000000000000000000000000000000000000000000000000000000000000000019999991111111111111111111111111
2022-12-29 02:11:41 +00:00
44444444444004444444444444400444444444444440044444444444444004444444444444400444444444444440044444444444444004444444444444400444
477dd77447711774477dd77447711774477dd77447711774477dd77447711774477dd77447711774477dd77447711774477dd77447711774477dd77447711774
2022-12-21 07:22:27 +00:00
47777774477777744777777447777774477777744777777447777774477777744777777447777774477777744777777447777774477777744777777447777774
4d7117d44d7117d44d7117104d7117104d7117d44d7117d44d7117104d711710017117d4017117d40171171001711710017117d4017117d40171171001711710
4d7117d44d7117d44d7117104d7117104d7117d44d7117d44d7117104d711710017117d4017117d40171171001711710017117d4017117d40171171001711710
2022-12-21 07:22:27 +00:00
47777774477777744777777447777774477777744777777447777774477777744777777447777774477777744777777447777774477777744777777447777774
477dd774477dd774477dd774477dd77447711774477117744771177447711774477dd774477dd774477dd774477dd77447711774477117744771177447711774
2022-12-21 07:22:27 +00:00
44444444444444444444444444444444444004444440044444400444444004444444444444444444444444444444444444400444444004444440044444400444
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000cc0cc0cccccccccccccccccccccccccccccccc0bb000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000cc0cc0000cc0000000000000000000cc0000000bb0bb0bbbb0bbbbb0bbbbb0bbb000000000000000000000000000000000000000000000000000000000000
000cc0cc0cc0cc0cc0cccccccc0ccccc0cc0ccccc0bb0bb000bb0000bb0bb0bb0bb0b00000000000000000000000000000000000000000000000000000000000
000cc0cc0cc0cc0cc0cc0cc0cc0000cc0cc0cc0cc0bb0bb0bb000bbbbb0bbb000bb0b00000000000000000000000000000000000000000000000000000000000
000cc0cc0cc0cc0cc0cc0cc0cc0ccccc0cc0ccccc0bb0bb0bbbb0bbbbb0bb0bb0bbbb00000000000000000000000000000000000000000000000000000000000
000cc0cc0cc0000cc0cc0cc0cc0cc0cc0cc0cc0000bb000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000ccccc0ccccc0cc0cc0cc0cc0ccccc0cc0ccccc0bbbbbbbbbbbbbbbbbbbbbbbbbbb00000000000000000000000000000000000000000000000000000000000
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
88888888888888888888880aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000000000000000
0088000000088000000000000000000000000aa00000000000000000aa0000000000000000000000000000000000000000000000000000000000000000000000
00880888880880888880880aaa00aaa0aaaa0aa0aaaaa0aa0a0aaaa0aa0aa0aaaaa0aaa000000000000000000000000000000000000000000000000000000000
00880880880880000880880aa0a0aa00aa000aa0aa0aa0aa0a0aa000aa0aa0aa0aa0aa0a00000000000000000000000000000000000000000000000000000000
00880880880880888880880aa0a0aa0000aa0aa0aaa000aa0a0aa000aa0aa0aa0aa0aa0a00000000000000000000000000000000000000000000000000000000
00880880880880880880880aaaa0aaa0aaaa0aa0aa0aa0aaaa0aaaa0aa0aa0aaaaa0aa0a00000000000000000000000000000000000000000000000000000000
00880888880880888880880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000888888800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030404040404040402140404040404050
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0c0c0c0c0c000c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0c0c0c0c0c000c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0c0c0c0c0c000c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0c0c0c0c0c000c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0c0c0c0c0c000c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0c0c0c0c0c000c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c000000000f300c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c00000e1e10000c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c00000000491b100c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c000040000000000c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0000000c000c0c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0c0c0c0c000c0c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0c0c0c0c000c0c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c0c0c0c0c0c000c0c0c0c0c0c0c051
2022-12-29 02:11:41 +00:00
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032424242424242104242424242424252
2023-01-02 04:24:24 +00:00
d0d0d0d0d0d0d0d0e3d0d0d0d0d0d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
2023-01-02 04:24:24 +00:00
d0d0d0d0d0d04100000041d0d0d0d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:24:24 +00:00
d0d0d0d0d0d04100000041d0d0d0d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:18:38 +00:00
4141304040404040004040404050d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:18:38 +00:00
d300e1e1e1e1d1d100d1d1d1d151d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:18:38 +00:00
d00031000000c1f100c1f1c1f151d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:24:24 +00:00
d00031000400f100e1f124c1005141d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:24:24 +00:00
d000e10000000404f30400c100000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000212000000000000c0
2023-01-02 04:24:24 +00:00
d00031000400e1e1e1e1e1f1005141d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000313000000000000c0
2023-01-02 04:24:24 +00:00
d000310000000000000000000051d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:24:24 +00:00
4100e1e1e1e1e1e1a4e1e1e1e151d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000c0
2023-01-02 04:24:24 +00:00
4141324242424242004242424252d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:24:24 +00:00
d0d0d0d0d0d0d0410041d0d0d0d0d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:24:24 +00:00
d0d0d0d0d0d0d0410041d0d0d0d0d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:24:24 +00:00
d0d0d0d0d0d0d0410041d0d0d0d0d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000c0
2023-01-02 04:18:38 +00:00
d0d0d0d0d0d0d0d021d0d0d0d0d0d0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2023-01-01 23:04:49 +00:00
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
2022-12-17 20:16:26 +00:00
__label__
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77766777777667777776677777766777777667777776677777766777777667777776677777766777777667777776677777766777777667777776677777766777
77766777777667777776677777766777777667777776677777766777777667777776677777766777777667777776677777766777777667777776677777766777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777777700000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777777700000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777777700000000000000000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000000000000777667777776677700000000000000000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000000000000777667777776677700000000000000000000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000000000000777777777777777700000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777777700000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777777700000000000000000000000000000000000000000000000077777777
77777777000000000000000077777777000000000000000000000000000000000000000000000000000000000000000077777777000000000000000077777777
77777777000000000000000077777777000000000000000000000000000000000000000000000000000000000000000077777777000000000000000077777777
77777777000000000000000077777777000000000000000000000000000000000000000000000000000000000000000077777777000000000000000077777777
77766777000000000000000077766777000000000000000000000000000000000000000000000000000000000000000077766777000000000000000077766777
77766777000000000000000077766777000000000000000000000000000000000000000000000000000000000000000077766777000000000000000077766777
77777777000000000000000077777777000000000000000000000000000000000000000000000000000000000000000077777777000000000000000077777777
77777777000000000000000077777777000000000000000000000000000000000000000000000000000000000000000077777777000000000000000077777777
77777777000000000000000077777777000000000000000000000000000000000000000000000000000000000000000077777777000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777777000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777777000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777777000000000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000077766777000000000000000077766777000000000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000077766777000000000000000077766777000000000000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000077777777000000000000000077777777000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777777000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777777000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000007777777700000000777777770000000000000000000000000000000000000000000000007777777700000000777777770000000077777777
77777777000000007777777700000000777777770000000000000000000000000000000000000000000000007777777700000000777777770000000077777777
77777777000000007777777700000000777777770000000000000000000000000000000000000000000000007777777700000000777777770000000077777777
77766777000000007776677700000000777667770000000000000000000000000000000000000000000000007776677700000000777667770000000077766777
77766777000000007776677700000000777667770000000000000000000000000000000000000000000000007776677700000000777667770000000077766777
77777777000000007777777700000000777777770000000000000000000000000000000000000000000000007777777700000000777777770000000077777777
77777777000000007777777700000000777777770000000000000008000000000000000080000000000000007777777700000000777777770000000077777777
77777777000000007777777700000000777777770000000000000088888888888888888888000000000000007777777700000000777777770000000077777777
77777777000000000000000000000000000000000000000000000088888877777778888888800000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088877777777777777788880000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088877777777777777708888000000000000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000000000088877667777776677700888800000000000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000000000088777667777776677700088880000000000000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000000000088777777777777777700008888000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088777777777777777700000888000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088777777777777777700000008880000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088777777777777777700000000888000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088777777777777777700000000088800000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088777777777777777700000000008880000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000000000088777667777776677700000000000888000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000000000088877667777776677700000000000088800000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000000000088877777777777777700000000000008880000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088877777777777777700000000000000888000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088877777777777777700000000000000088800000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088880000000000000000000000000000008880000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000088888800000000000000000000000000000888000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000088888000000000000000000000000000088800000000000000000000000000077777777
77766777000000000000000000000000000000000000000000000000000088880000000000000000000000000000888000000000000000000000000077766777
77766777000000000000000000000000000000000000000000000000000000088880000000000000000000000000888800000000000000000000000077766777
77777777000000000000000000000000000000000000000000000000000000000888880000000000000000000000088880000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000008888880000000000000000000008888000000033000000000000077777777
777777770000000000000000000000000000000000000000000000000000000000000888880000000000000000000008883330003bb300000000000077777777
777777770000000077777777000000007777777700000000000000007777777777777778880000000000000077777777833b33003ab337770000000077777777
77777777000000007777777700000000777777770000000000000000777777777777777888800000000000007777777733333300331137770000000077777777
77777777000000007777777700000000777777770000000000000000777777777777777788800000000000007777777700883330711337770000000077777777
77766777000000007776677700000000777667770000000000000000777667777776677788800000000000007776677703333333733367770000000077766777
77766777000000007776677700000000777667770000000000000000777667777776677708880000000000007776677700333330333667770000000077766777
77777777000000007777777700000000777777770000000000000000777777777777777700880000000000007777777700033133311777770000000077777777
77777777000000007777777700000000777777770000000000000000777777777777777700888000000000007777777700003100317777770000000077777777
77777777000000007777777700000000777777770000000000000000777777777777777700088000000000007777777700033103317777770000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000088800000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000008880000000000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000000000000000000000000000000000888000000000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000000000000000000000000000000000888000000000000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000000000000000000000000000000000888800000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000088800000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000088880000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777778880000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777778880000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777778800000000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000077766777000000000000000077766778800000000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000077766777000000000000000077766778800000000000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000077777777000000000000000077777778800000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777778880000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000077777777000000000000000077777778880000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777777700000088880000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777777700000888800000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777777700008888000000000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000000000000777667777776677700088800000000000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000000000000777667777776677700880000000000000000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000000000000777777777777777708800000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777777788000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000777777777777778880000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000888800000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000008888000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000008880000000000000000000000000000000000000000000000000077777777
77766777000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000077766777
77766777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077766777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77766777777667777776677777766777777667777776677777766777777667777776677777766777777667777776677777766777777667777776677777766777
77766777777667777776677777766777777667777776677777766777777667777776677777766777777667777776677777766777777667777776677777766777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
__gff__
000000c0c0c0c0c0c0c0c0c0c0c00000000000c0c0c0c0c0c0c0c0c020202020004000c0c0c0c0c0c008080800000000404000000000080808080808c0c0c0c000000000080808080808080800000008000000000808080808080808000000000008080808080808080808080000000000080808080808080808080800000000
2022-12-17 20:16:26 +00:00
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__map__
2023-01-02 04:24:24 +00:00
0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d1203040404050d0d0d0d010d0d0d0d0d0d0d0d0d0d0d0d0d0d120d0d0d0d0d0d0d0d0d0d0d0d0d03043e0a040404050d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d
2023-01-02 02:03:55 +00:00
0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0a0d0d0d0d0a0d0304040405140013004f00150d0d0d1400140d0d0d0d0d0d0d0d0d0d0d0d1400140d0d0d0d0d0304040404040417000026000000150d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d030404043e050d0d0d0d0d0d033e0404040404050d0d0d0d0d0d0d
2023-01-01 23:46:03 +00:00
0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d03042604040404260417000000151400001e0000150304040400040404050d0d0d0d0d03040404050003040404050d1300000000000000000018000000150d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0304041700000000150d0d0d0d0d0d134400000000001514140d0d0d0d0d
2022-12-31 02:34:48 +00:00
0d0d0d0d0d0d0d0d0d0a0d0d0d0d0d0d0d14130018000000001800000000001514141300000015130000000000000015030404040513000000160017000000150d1300000000000000421e00000000150d0d0d0d0d0d0d0d0d0a0d0d0d0d0d0d0d0d1300000000000000150d0d0d0d0d12001d0000000000000003040404050d
0d0d0d0d0d0d0d0d0d260d0d0d0d0d0d010000001e0000004f000000000000150d031700000015130000000000000015130000001513004200001e43000000150d130000000000000000001a000041150d0d0d0d0d0d0d0d0d260d0d0d0d0d0d0d0d13000000001d1d00150d0d0d0d0d0d131c0000000000150013000000150d
0d0d0d0d0d0d0d0d0d260d0d0d0d0d0d0d1413001a000000001a0000000000150d13000000001513000000000000001513001d1d0000000000000000000000150d232424002424240700002600001e150d0d0d0d0d0d0d0d0d260d0d0d0d0d0d0d0d1346062407471c00150d0d0d0d0d0d231c24241d2424250000000000150d
0d0d0d0d03040404042604050d0d0d0d0d0d232426242424242624071e001e150d13000000001513000000000000001513001f481523242424070006242424250d0304040004040523242408242400250d0d0d0d03040404041804050d0d0d0d0d0d1346150d131c1f0016040404050d0d031f04051c0d030404170000001605
0d14141413000000001800151414140d0d0d0d0d080d0d0d0d080d23240024250d23240000242513000000000000001513000000150d0d0d0d2324250d0d0d0d0d3d001c001c003f03040404040400050d1414141300001d1d1d003f1414140d0d0d13441604171f1a0000000000150d0d130000161f053d44001d1d001d0015
0100000000000000004f0000000000120d0d0304040404050d0d0d0d1400140d0d030400000405130000004f000000151300000015030404050d0d0d030404050d13001c1d1c00151300000000000015010000000000001c1c1c0000000000120d0d13001c000000181d1a1d1a1d150d0d131d1d0000151342001c1c001c003f
0d14141413000000001a00151414140d0d0d1300000000150d0304040400050d0d13001e1e4f15130000001e00000015130000001513000016040404170000150d13001f401f00151300481e000000150d1414141300001f1f1f003f1414140d0d0d13001f0043003f1f181c181f150d0d131f1f0000151300001c1c1d1c4915
0d0d0d0d23242424242624250d0d0d0d0d0d1300000000150d1300000000150d0d130000000015130000150013000015130000431513000000000000000000150d1300000000001523242400242424250d0d0d0d23242424241a24250d0d0d0d0d0d13001a001a1d1a00001f0000150d0d230747000015131e1e1f1f1f1f3e15
0d0d0d0d0d0d0d0d0d260d0d0d0d0d0d0d091b00191b00192727271b1e19270b0d2324240024252324242500232424251300000000004d0000000000000000150d1300000000001503040000040514140d0d0d0d0d0d0d0d0d260d0d0d0d0d0d0d0d131e1800181f18001a00063c250d0d0d2324243c25130040000000000015
0d0d0d0d0d0d0d0d0d260d0d0d0d0d0d0d0d1300001e4f1e000000004f00150d0d0d03040004050d0d0d1400140d0d0d232424242513000000000000000000150d130000000000151300001d1d0000140d0d0d0d0d0d0d0d0d260d0d0d0d0d0d0d1413000000000000001800000000120d140304040405130000000000000015
0d0d0d0d0d0d0d0d0d080d0d0d0d0d0d0d0d230024242425141300000000150d0d0d134f1e00151414141400140d0d0d0d0d0d0d0d13000006240024070000150d2324240024242513000040441500140d0d0d0d0d0d0d0d0d080d0d0d0d0d0d0100000000000000062424242514140d0100001d1d483f230024242424242425
0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d1400140d0d0d0d2324242424250d0d0d13000000000000000000140d0d0d0d0d0d0d0d23242425140014232424250d0d0d1400140d0d13000000001500120d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d1423242424243c250d0d0d0d0d0d0d0d14131f1f00000000140d0d0d0d0d0d
0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d120d0d0d0d0d0d0d0d0d0d0d0d0d0d23242424251414141414140d0d0d0d0d0d0d0d0d0d0d0d0d010d0d0d0d0d0d0d0d0d010d0d0d232424242425140d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d23242424251414140d0d0d0d0d0d
0d0d0d0d0d0d0d0d030404040404050d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d010d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d0d0d0d0d0d0d0d0d0d0d120d0d0d00000000000000000000000000000000
0d03040404040405133d00001c00150d0d0d0d0d0d0d0d0d0304043e0404050d0d0d0d0d030404000404050d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d0d14030404040404041400140d0d00000000000000000000000000000000
0d13001c1c004f0000421e1d1f00150d0d0d0d0d0d0d0d0d130000000000150d0d0d0d0317420000004816050d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d141413000000000000001e003f0d00000000000000000000000000000000
0d13001c1c1d00150000001c000000010d03040404040405130000000000150d0d0d141300191b1d191b0015140d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d030417001d1d1d1d1d0015140d0d00000000000000000000000000000000
0d13001f1f000015131e1e1f1d1d150d0d13460044004c15130000000000150d0d3d001e0042001f0048001e003f0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d130000001c1c421c1c00150d0d0d00000000000000000000000000000000
0d13000000000015130000001c1c150d0d131d1d1e1d1d152324241d2424250d0d140023240700410006242500140d0d0d0d0d0d030404040404050d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d13001d1d1f1f001c1c00150d0d0d00000000000000000000000000000000
0927271b1e1e0015130014001c1c150d0d131c3d001c1c000000001f040404050d1400000023243c2425000000140d0d0d0d0d0d130000001c000000000d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d13001c1c0000001c1c00150d0d0d00000000000000000000000000000000
0d131c1c00000000000000001c1c150d0d131f1f1e1f1f1514141300280000150d14000000001f1f1f00000000140d0d0d141414130028001c4516050014140d00000000000000000000000000000000000000000000000000000000000000000d0d13001c1c001e001c1c00150d0d0d00000000000000000000000000000000
0d131c1c0014001513001e1e1927270b0d1300004100001514141300000000010d144f47411400000014000000140d0d01000000000000001f0000150000001200000000000000000000000000000000000000000000000000000000000000000d0d13001c1c0000001c1c00150d0d0d00000000000000000000000000000000
0d131c1c00000015130000000000150d0927271b001927270b031741280000150d14434b491400000014000000140d0d0d14141413002800000000151414140d00000000000000000000000000000000000000000000000000000000000000000d0d13001c1c001d1d1f1f00150d0d0d00000000000000000000000000000000
0d131f1f1d1e1e151300001d1d00150d0d131f1c001c1c151f130000004900150d03040404040000000304040405140d0d0d0d0d13000000000006250d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d13001c1c481c1c000000150d0d0d00000000000000000000000000000000
120000001c00000013001f1c1c00150d0d13001f001f1c0000131d1d000000150d1300000000000003170000000000120d0d0d0d232424242424250d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d1413001f1f1f1f1f000624250d0d0d00000000000000000000000000000000
0d13001d1f1e4800004f001c1c00150d0d13000000001f1500232424242424250d13000000001d1d1d0000000015140d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0000000000000000000000000000000000000000000000000000000000000000010000000000000000001514140d0d0d00000000000000000000000000000000
0d13001c00003f15232424242424250d0d1300000000001500140d0d0d0d0d0d0d130000000625031700000000150d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d14232424242424242425140d0d0d0d00000000000000000000000000000000
0d232424242424250d0d0d0d0d0d0d0d0d2324242424242500140d0d0d0d0d0d0d130000062503170000000000150d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000
0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d120d0d0d0d0d0d0d0d232424250d23242424242424250d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000000000000000000000000000000000000d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000000000000000000000000000000
2022-12-18 07:25:42 +00:00
__sfx__
2022-12-24 00:05:38 +00:00
00110000250002500025030250302503000000230350000023030230302303023030230302303023030230302103021030210302103021030210300000000000177401774017740177311e7501e7501e7501e750
00110000290202a0212a0202a0202a0202a02025030250052503025030250302503025030250302503025030250302503025030250302503225030230322504526030260302a040000002d0402d0402d0402d040
001100001e7401e7401e7401e74010730107301073010730157301573015730157301573015730157301573015730157301573015730000000000000000000000000000000000000000019030190300000000000
001100002d0422d0402a0302a0302c0302c0302c0322c0322d0402d0312d0302d0302d0302d0302d0302d0302d0302d0302d0322d03200000000000000000000000000000000000000002b0402c0410000000000
001100001274012740127401274012740127401274012740177301773017730177301773017730177301773014730147301474014740107401074010740000001573015730157301573009720097300973009730
001100002a0402a0412a0412a0402a0402a0402a042290412a0412a0402a0402a0402a0402a0402a0422903128041280402804028040280402804226032000002504025040250402603026030260322803200000
001100000e0300e0300e0300e0300e0300e0300000000000000000000000000000000000000000150301503014030140301403014030120301203012030120300d0200d0200d0200d0200d0200d0200d0200d020
001100002804028040280402804028040280402104000000210402104021040210402104021040150001500014000140001400014000120001200012000240342503125030250302503025030250322503225032
00110000150301503015030150301503015030150301503015030150301503015030150301503015030150300b0200b0200b0200b0200b0200b0200b0200b0200b0200b0200b0200b02000000000000000000000
001100002501425010250102501025010250102501025010250212502025020250202502125020250202502027540275402754027540275402754027540275402703027030270302703027030270302703027030
001100002312023120231202312023120231202312023120231202312023120231202312023120231202212123141231402314023140231402314021140201401e1401e1401e1401e1401c140001001e14020140
00110000000000000006322063250d3320d33209320093200932009325093200932509320000001703017030170300b0200b0200b0200b02017030170300b0301403014030140301403514030140300000014330
0011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b0301b0301b030000001b0301b0301b030000001b0301b0301b03000000
0011000020140201402013020130201302013020130201301d1401e1411e1401e1401c140002001b2401b2401b240000000000022554235512355023550235402354023540235402354023540235402314023140
0011000000000150301503000000000000e0300e0300e0300e0320e0320e0320e0320e0300e0300e030000000d0300d0300d0300d0300d0300d0300d0300d0300d0300d0300d0300d0300d0300d0300d0300d030
00110000190331903019030000001a0331a0301a0301a0301a0301a0301a0301a0301a0301a0301a0300000027320273202732027320000000000027320273202732027320273202732000000000000000000000
00110000211402d1402d145000002a1302a1302a1302a1302a1322a1322a1322a1322a1322a13000100000002c3202c3202d3202d3202f320003002d3302d3302d3302d3302c3312c3302a3302a3302833000000
001100000b0300b0300b0000b0000b0300b0300b0300b0300b0300b0300b0300b0300b0300b0300b0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001100002704027040000000000027040270402704027040270402704027040270402704027040000000000028020280202a020000002c030000002a0202a02000000000002c0302c0302c0302c0300000000000
001100002a3302a3302c330003002a3302a3302a3302a3302a3302a3322a3322a3322a3322a332283322a3322c3302c3302d330003002f3302f3052d3302d33000300003002f3302f3302f3302f3302804028045
00110000000000000015310153101531015310153101531000000000001032010320103201032010320103200e3200e3200e3200e3200e3200e3200e3200e32000000000000d3200d3200d3200d3200d3200d320
001100003102031022310223102231022310222f0322d0302c030000002a0400000028030000002603026030260302603026030260302603026030000000000029040000002a040000002c040000002d0502d050
0111000034040340403404034042340423404232042310422f040000002d040000002c040000002a0402a0402a0402a0402a0422a0422a0422a042290402a0402c040000002d040000002f040000003104031040
001100001203012030120351230010030100301003010030020200202002020020200202002020020200202002020020200202002020020220202202022020220b0400b040000000000010040100400000000000
0011000000000000002c0402c04000000000002a0302a0302a0302a0302a0302a0302a0302a0302a0302a0302a0302a0302a0302a0302a0302a0302a030000002604026040000000000028040280400000000000
0011000000000000002f0402f04000000000002d0402d0402d0422d0422d0422d0422d0422d0422d0402d0402d0402d0402d0402d0402d0402d0402d040000002a0402a04000000000002c0302c0300000000000
001100000932209322093220932209322093220932209322043220432204322043220432204322023220232202322023220232202322023120231204312023120131000000033100000005310000000632006320
00110000250402504025040250402504025040230402104020040000001e040000001c040000001a0401a0401a0401a0401a0401a0401a0400000000000000000000000000000000000000000000000000000000
0011000028030280302803028030280302803026030250402304000000210400000020040000001e0401e0401e0401e0401e0401e0401e040000001d0401e0402004000000210400000023040000002504025040
00110000063200632012310123100431004310103101031002310023100231002310023150200002745017450b7351770017735060001274506000107550400004000107550b7550400004755010000172001722
00110000250502505023040230402304023040250402303021050210502105221050210502105021050210502a030000002d030000003203000000310403104031040310402f0302d0402f0502f0502d0402c040
001100000e7450e7050000012745000000070010740107401074210742107421074210740000000e7400e7400d7450d00500000117450000000000127401274012742127421e7421e7421c7401c7451074010745
001100002a05512005000003205500000000002f0502f0502f0502f0502f0502f0502f050000002c0402a0502905500000000003105500000000002d0402d0402d0402d0402d0402d0402c0402c0402c0402c040
001100000e0400e0400e0400e0400e0400e0400d040000000b0400b0400b0400b0400b0400b040020400000004040040400404004040040400404504040000000404004040040300400001000010000104001030
001100002a0402a0402a0402a0400000000000260302503023030230302303023030320503205232052320523104031040310403104031040310402f040000002f0402f0402f0402f0002a0402c0402a04028040
001100001731517310173151731517020170251033010330103301033010330103300233002325023300232501330013300133501335013300133506330063300633006330063300633004040040400404004040
00110000173601733023030233300b6630b3352a66317330173302a6532c230282302c230282302a6531a230190301903025030250330b6650b6702a6231e0302a7001e7302a6231e730287301c7302a6231c730
001100002634026340263403234032340323402f3402f3402f3422f3422f3422f3422f3422f34228342263402533025330253303135031350313502d3402d3402d3422d3422d3422b3412c3412c3422c34229341
001100000e7300e7300e7300e7300e7300e7300d7300d7300b7400b7400b7400e7400e7400e740100401004010030100300403004030040300403004030040300403004030040300403004030040300403000000
00110000260301a030260301a030260301a03000000000002304017040230402603017030260302a0401c0402a0401c0402a0401c0402a0401c0402a0401c040280401c040280401c04028040000001c04000000
00110000293402a3412a3422a3422a3422a34228350000002634026340263403234032340323402f3502f3502f3522f3522f3522f3422f3422f3422f3422f3422f3422f3422f3422f3422f340000002d3402d345
001100001004010040100401004010040100401004010040100301003010030100301003010030100301003010020100201000010000100051000010000100000000000000000000000000000000000000000000
001100002604028040260302803026040280402603028030260202802026020280202601028010260102801025010250152500028000250052800025000340000d5100d0300d0300000000000125140603006030
001100002d3322d3322d3322d3322d3322d3322d3322d3322d3222d3222d3222d3222d3222d3222d3222d3222d4122d4122d4022d4052d4002d4002d400000003843038430384303843500000000003473034730
001100000601006015000000000000000000000000000000215401a030210400000000000000001c540150301c0400000000000000001e540170301e040000000000000000195401203019040120300d0350d005
0011000034720347203472034720347250000000000001003173031730317302f7352d735001002c7402c7402c7402d7452f745007002d7502d7502d7502c7452a74500700287402874028740007002574500100
001100001a0302a0321a0301a0351a0001a00000000000000000000000000000000000000000000000000000000000000000000000002f0401c0222f04000000000001c0202d0422502019040190401904019040
00110000217302173021710217102171021715217002170021000210002100021000210002100021000210000000000000000001c700387303873038730387300000000000347303473034730347303473034730
0111000025020250202d0402c0402a140022150e0251202012020151250d2152502019020280351a030230251702026030260301703023030200001c000200301c02023040040200402004020040200000000000
001100003403034030317302f7302d7302d7302d7202f72031720001002f7402f7402f740007002d740007002a7502a75032750327502f7402f7402f7402f7422f7422f7422f7422f74500700007001c75000700
00110000253401c34009360093600936009340093401734004340043400434004340043401734002340023400234002340023401a340023400434002340023400134000300033400030005340003000635006350
001100001c567285303453034540345403454032540315402f540255402d540255402c540255402a5402a5402a5402a54021540215402154021540295302a5302c540235402d540255402f540255403155031550
00110000000000000000000000000000000000000000000021440204401e4401e4401e4401e4401e4401e4401a44000000174401a000174401a00012440124401224012240102401024010240102400d0000d000
001100000635006350123401234004350043501034010340023400234002340023400234002340023400234017340230001a3402a0001a340000002d3402d3402d3402d3402c3402a3402c3402c3402d0352c035
0011000031560255602f5602f5602f56025560315602f5602d5602f5602d5602d5602d5602d5602d5602c5601e16000100211500000026130000002514025140251402514023130211402315023155201001e100
011100002804026040280402604028030260302803026030280302603028030260302802026020280202602028020250202802025020280102501028010250102801025010280102501028010250102802025020
001120002d3202d3202d3202d3202d3202d3202d3202d3202d3202d3202d3202d3202d3202d3202d3202d3202d3112d3102d3102d3102d3102d3102d310014000140001400014000140001400014000140001400
0111000034530345323453234532345323453232532315302f540005002d540005002c540005002a5402a5402a5402a5402a5402a5402a5402a540295402a5402c540005002d540005002f540001003104031040
2022-12-20 00:38:21 +00:00
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
010300000015000250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2022-12-18 07:25:42 +00:00
__music__
2022-12-24 00:05:38 +00:00
01 00014140
00 02034340
00 04054540
00 06074740
00 08090a40
00 0b0c0d40
00 0e0f1040
00 11121340
00 14151640
00 17181940
00 1a1b1c40
00 1d1e5e40
00 1f206040
00 21226240
00 23242540
00 26272840
00 292a2b40
00 2c2d6d40
00 2e2f6f40
00 30317140
00 14153940
00 17181940
00 32335472
00 34353640
00 1f204040
00 21224040
00 23242561
00 26272840
02 37387840
2022-12-29 02:11:41 +00:00