chameleonic/chameleonic.p8

1620 lines
51 KiB
Plaintext
Raw Normal View History

2022-12-17 20:16:26 +00:00
pico-8 cartridge // http://www.pico-8.com
version 38
__lua__
modules={}
frame=0
function _init()
_doall("init") end
function _update()
frame+=1
if (frame%1==0) _doall("update") end
function _draw()
_doall("draw") 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
local d=max(abs(dx),abs(dy))
local n=min(abs(dx),abs(dy))/d
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
local s={
{0,-r},{d,-r},{d,r},{0,r}
}
local u,v,spans=s[4][1],s[4][2],{}
local x0,y0=ax+u*ca+v*sa,ay-u*sa+v*ca
for i=1,4 do
local u,v=s[i][1],s[i][2]
local x1,y1=ax+u*ca+v*sa,ay-u*sa+v*ca
local _x1,_y1=x1,y1
if(y0>y1) x0,y0,x1,y1=x1,y1,x0,y0
local dx=(x1-x0)/(y1-y0)
if(y0<0) x0-=y0*dx y0=-1
local cy0=y0\1+1
-- sub-pix shift
x0+=(cy0-y0)*dx
for y=y0\1+1,min(y1\1,127) do
-- open span?
local span=spans[y]
if span then
rectfill(x0,y,span,y)
else
spans[y]=x0
2022-12-17 20:16:26 +00:00
end
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
if k=="update" then
if not v(x,a) then
add(ts,t,1)
end
else
x[k]=v
end
end
end
function sgn0(x)
if (x==0) return x
return sgn(x)
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
-->8
level={}
add(modules,level)
function level:init()
level:reinit(0)
end
function level:reinit(n)
self.ix=n
self.todo={}
2022-12-17 23:08:54 +00:00
self.bigx=(n%16)
self.bigy=(n\16)
2022-12-17 20:16:26 +00:00
self:load_dynobjs()
self:recollide()
2022-12-17 23:15:56 +00:00
self:reanchor(true)
2022-12-17 23:08:54 +00:00
self:spawn_exit()
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
pitpal = {[0]=1, [7]=0}
2022-12-17 20:16:26 +00:00
function level:draw()
2022-12-17 23:48:52 +00:00
cls(1)
pal(1,0)
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
spr(pit.s,pit.px,pit.py)
if pit.contents then
pal(pitpal)
2022-12-17 23:48:52 +00:00
palt(0,false)
spr(pit.contents,pit.px,pit.py)
pal()
pal(1,0)
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)
2022-12-17 23:48:52 +00:00
end
2022-12-17 20:16:26 +00:00
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
if (#crate.todo>0) return true
end
return false
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
local pit=self._pits[_mix(crate.mx,crate.my)]
if pit and not pit.contents then
2022-12-17 23:48:52 +00:00
add(remove,cix)
crate.dead=true
pit.contents=crate.s
end
end
end
for cix in all(remove) do
self._crates[cix]=nil
end
if #remove>0 then
self:recollide()
self:reanchor(true)
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-17 20:16:26 +00:00
for mx=0,15,1 do
for my=0,15,1 do
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,
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={}
}
end
2022-12-17 23:48:52 +00:00
if s==28 then -- pit
self._pits[mxy]={
s=s,
mx=mx,my=my,
px=px,py=py,
contents=nil
}
end
2022-12-17 20:16:26 +00:00
end
end
end
function level:recollide()
self._coll={}
for mx=0,15 do
for my=0,15 do
2022-12-17 20:16:26 +00:00
local mxy=_mix(mx,my)
self._coll[mxy]=
fget(self:_mget(mx,my),7) or
self._crates[mxy]!=nil
end
end
end
function level:reanchor(remove)
if remove or not self._anch then
2022-12-17 20:16:26 +00:00
self._anch={}
end
for ax0=0,31 do
local ax1 = ax0-1+2*(ax0%2)
local mx0,mx1 = ax0\2,ax1\2
for ay0=0,31 do
local ay1=ay0-1+2*(ay0%2)
local my0,my1=ay0\2,ay1\2
2022-12-17 20:16:26 +00:00
if (
not self:mcoll(mx0,my0) and
not self:mcoll(mx0,my1) and
not self:mcoll(mx1,my0) and
self:mcoll(mx1,my1)
) then
local px0,py0=level:a2p(ax0,ay0)
self._anch[_amix(ax0,ay0)]={ax=ax0,ay=ay0,x=px0,y=py0}
end
end
end
end
2022-12-17 23:08:54 +00:00
function level:win_at(mx,my)
return self._wins[_mix(mx,my)]
end
2022-12-17 20:16:26 +00:00
function level:anchor_points()
return pairs(self._anch)
end
function level:anchors_in(px0,py0,px1,py1)
local anch,ax,xlim,sy,ylim=self._anch,px0\4,(px1+3)\4,py0\4,(py1+3)\4
local ay=sy-1
return function()
while true do
ay+=1
if(ay>ylim)ay,ax=sy,ax+1
if(ax>xlim)return nil
local anc=anch[_amix(ax,ay)]
if (anc) return anc
end
end
end
2022-12-17 23:48:52 +00:00
function level:get_open_pit(mx,my)
local pit=self._pits[_mix(mx,my)]
if (pit and pit.contents==nil) return pit
end
2022-12-17 20:16:26 +00:00
function level:point_anchor(px,py)
local ax,ay=self:p2a(px,py)
local anc=self._anch[_amix(ax,ay)]
return anc
end
2022-12-17 23:08:54 +00:00
function level:spawn_exit()
self._wins={}
local spawned=false
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)
if (self:_mget(x,y)!=4) return
for n in all(neighbors{x=x,y=y}) do
if n.x<0 or n.y<0 or n.x>15 or n.y>15 then
self._wins[_mix(n.x,n.y)]=true
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
2022-12-17 20:16:26 +00:00
function level:p2a(px,py)
return px\4,py\4
end
function level:a2p(ax,ay)
local px=ax*4+3*(ax%2)
local py=ay*4+3*(ay%2)
return px,py
end
function level:mcoll(mx,my)
2022-12-17 23:08:54 +00:00
return self._coll[_mix(mx,my)]!=false
2022-12-17 20:16:26 +00:00
end
function level:pcoll(px,py)
return self:mcoll(px\8,py\8)
end
function level:get_crate(mx,my)
return self._crates[_mix(mx,my)]
end
function level:_mget(mx,my)
return mget(
self.bigx*16+mx,
self.bigy*16+my
)
end
function _amix(ax,ay)
return ax..","..ay
--if (ax<0 or ay<0 or ax>31 or ay>31) return nil
--return ay*32+ax
end
function _mix(mx,my)
return mx..","..my
--if (mx<0 or my<0 or mx>15 or my>15) return nil
--return my*16+mx
end
function level:_get_cratedef(s)
if (s<64 or s>=80) return nil
local s2=s-64
return {
up=s2&1!=0,
right=s2&2!=0,
down=s2&4!=0,
left=s2&8!=0
}
end
function level:get_latch(dx,dy,px,py)
local mx,my=px\8,py\8
local mxy=_mix(mx,my)
local crate=self._crates[mxy]
if crate then
if
(crate.def.up and dy>0) or
(crate.def.down and dy<0) or
(crate.def.left and dx>0) or
(crate.def.right and dx<0)
then
return {
el="crate",
dx=-dx,dy=-dy,
px_offset=px-crate.px-sgn0(dx),
py_offset=py-crate.py-sgn0(dy),
rec=crate
}
end
end
local m=self:_mget(mx,my)
if
(m==60 and dy>0) or
(m==61 and dx<0) or
(m==62 and dy<0) or
(m==63 and dx>0)
then
return {
el="eyehook",
dx=-dx,dy=-dy,
mx=mx,my=my
}
end
end
function level:can_move(
2022-12-17 23:08:54 +00:00
is_player,
2022-12-17 20:16:26 +00:00
mx0,my0,dmx,dmy,exclude_src,exclude_dst
)
2022-12-17 23:08:54 +00:00
if is_player and self:win_at(mx0+dmx,my0+dmy) then
return true
end
2022-12-17 20:16:26 +00:00
if self:mcoll(mx0+dmx,my0+dmy) then
return false
end
2022-12-18 00:57:47 +00:00
if player.x==mx0+dmx and player.y==my0+dmy then
return false
end
2022-12-17 20:16:26 +00:00
-- todo: check tongue collision
if player.rope then
local px,py=mx0*8,my0*8
local chk=false
if dmx==0 and dmy==-1 then
chk=player.rope:collide_rect(px+3,py-5,px+4,py+5,exclude_src,exclude_dst)
elseif dmx==0 and dmy==1 then
chk=player.rope:collide_rect(px+3,py+3,px+4,py+13,exclude_src,exclude_dst)
elseif dmx==-1 and dmy==0 then
chk=player.rope:collide_rect(px-5,py+3,px+5,py+4,exclude_src,exclude_dst)
elseif dmx==1 and dmy==0 then
chk=player.rope:collide_rect(px+3,py+3,px+13,py+4,exclude_src,exclude_dst)
end
if (chk) return false
end
return true
end
function level:tug_crate(mx0,my0,dmx,dmy)
local mxy0=_mix(mx0,my0)
local existing=self._crates[mxy0]
if (existing==nil) return
self._crates[mxy0]=nil
local mx1,my1=mx0+dmx,my0+dmy
local mxy1=_mix(mx1,my1)
existing.mx=mx1
existing.my=my1
existing.todo={
{px=mx0*8+dmx*2,py=my0*8+dmy*2},
{px=mx0*8+dmx*7,py=my0*8+dmy*7},
{px=mx1*8,py=my1*8,update=function()
self:reanchor(true)
return true
end}
}
self._crates[mxy1]=existing
self:recollide()
self:reanchor(false)
end
-->8
player={}
add(modules,player)
function player:init()
--self:reinit(8,14)
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)
self.x=x
self.y=y
self.px=0
self.py=0
self.todo={}
2022-12-17 23:48:52 +00:00
self.fall_frame=0
2022-12-18 00:25:20 +00:00
self.reset_frame=0
2022-12-17 20:16:26 +00:00
self.orientx=-1
self.orienty=0
self.rope=nil
end
function player:any_busy()
if (#self.todo>0) return true
if (level:busy()) return true
if (self.rope!=nil and self.rope:busy()) return true
return false
end
function player:update()
local _addall=function(t,xs)
for i in all(xs) do
add(t,i)
end
end
local f4 = function(xs)
-- todo: other anim stuff
xs[#xs].px=0
xs[#xs].py=0
return xs
end
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-17 20:16:26 +00:00
if not self:any_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-17 20:16:26 +00:00
if btn(⬅️) then
2022-12-17 23:08:54 +00:00
if level:can_move(true,self.x,self.y,-1,0,0,2) then
2022-12-17 20:16:26 +00:00
self.todo=f4({{orientx=-1,orienty=0,px=-2},{px=-7},{x=self.x-1}})
else
self.orientx=-1
self.orienty=0
end
elseif btn(➡️) then
2022-12-17 23:08:54 +00:00
if level:can_move(true,self.x,self.y,1,0,0,2) then
2022-12-17 20:16:26 +00:00
self.todo=f4({{orientx=1,orienty=0,px=2},{px=7},{x=self.x+1}})
else
self.orientx=1
self.orienty=0
end
elseif btn(⬆️) then
2022-12-17 23:08:54 +00:00
if level:can_move(true,self.x,self.y,0,-1,0,2) then
2022-12-17 20:16:26 +00:00
self.todo=f4({{orienty=-1,py=-2},{py=-7},{y=self.y-1}})
else
self.orienty=-1
end
elseif btn(⬇️) then
2022-12-17 23:08:54 +00:00
if level:can_move(true,self.x,self.y,0,1,0,2) then
2022-12-17 20:16:26 +00:00
self.todo=f4({{orienty=1,py=2},{py=7},{y=self.y+1}})
else
self.orienty=1
end
elseif btn(🅾️) then
if self.rope==nil then
local rx,ry,rx2,ry2=self:_rope_pos()
local dx,dy=12*self.orientx,12*self.orienty
if (dy!=0) dx=0
self.rope=rope:new(rx,ry,rx2,ry2,dx,dy)
self.todo={{
update=function()
return self.rope==nil or not self.rope:casting()
end
},{},{}}
else
self.rope:tug()
self.todo={{},{},{}}
end
elseif btn(❎) then
if self.rope!=nil then
self.rope=nil
end
end
end
_apply(self,self.todo)
if self.rope then
self.rope:update()
local rx,ry=self:_rope_pos()
self.rope:drag_dst(rx,ry)
2022-12-18 00:57:47 +00:00
local tdx,tdy=self.rope:tug_orientxy()
if (tdx!=0) self.orientx=tdx
if (tdy!=0) self.orienty=tdy
2022-12-17 20:16:26 +00:00
if self.rope:done() then
self.rope=nil
add(self.todo,{})
add(self.todo,{})
add(self.todo,{})
end
end
end
2022-12-18 00:25:20 +00:00
function player:_vanish_if_requested()
local bvan=btn(❎)
if self.bvan and not bvan then
self.vanishing=false
elseif not self.bvan and bvan then
self.vanishing=true
end
self.bvan=bvan
if self.vanishing then
self.vanish_frame+=1
2022-12-18 00:26:30 +00:00
if (self.fall_frame>0 or self.vanish_frame>20) then
2022-12-18 00:25:20 +00:00
level:restart()
2022-12-18 00:26:30 +00:00
self.vanish_frame=20
2022-12-18 00:25:20 +00:00
self.vanishing=false
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:_rope_pos()
local px=self.x*8+self.px
local px2=px+4
if self.orientx==-1 then
px+=2
else
px+=6
end
local py=self.y*8+self.py+2
local py2=py+1
return px,py,px2,py2
end
function player:draw()
local px=self.x*8+self.px
local py=self.y*8+self.py
local head=2-self.orienty
2022-12-17 23:48:52 +00:00
2022-12-18 00:25:20 +00:00
local vanish_level=self.vanish_frame/20
local invis_level=max(self.fall_frame/10,4*(vanish_level-0.75))
if (invis_level>=1.0) return
--px+=sin(vanish_level*16)*max(vanish_level-0.1,0)*1
local HEAD=14--3
local BODY=12--12
local TAIL=14--14
local IRIS=7--9
local PUPIL=0--0
local setpal=function()
-- base colors
pal(13,TAIL)
pal(14,TAIL)
pal(15,TAIL)
pal(4,BODY)
pal(5,BODY)
pal(12,BODY)
pal(2,HEAD)
pal(3,HEAD)
pal(9,IRIS)
pal(10,PUPIL)
-- vanish colors
local vanish=split"13,15,14,5,4,12,2,3,9,10"
for i,ilc in ipairs(vanish) do
if (vanish_level>i/#vanish) pal(ilc,1)
end
2022-12-18 00:25:20 +00:00
if self.fall_frame>3 then
for i=0,15 do pal(i,1) end
end
2022-12-17 23:48:52 +00:00
end
2022-12-17 20:16:26 +00:00
if self.orientx==-1 then
setpal()
2022-12-17 20:16:26 +00:00
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() setpal()
2022-12-17 20:16:26 +00:00
spr(head,px-3,py-3,1,1)
else
setpal()
2022-12-17 20:16:26 +00:00
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() 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={}
rope.__index=rope
function rope:new(
x,y,src_x,src_y,dx,dy
)
local r={
id=0,
src={x=src_x,y=src_y,todo={}},
ancs={},
dst={x=x,y=y,todo={}},
cast={dx=dx,dy=dy},
latch=nil,
latch_frame=0,
under_destruction=false,
}
setmetatable(r,rope)
return r
end
function rope:casting()
return self.cast!=nil
end
function rope:done()
return self.latch_frame>=2 and (
self.latch==nil or
self.under_destruction
)
end
function rope:busy()
for i=0,#self.ancs+1 do
if (#(self:_anc(i).todo)>0) return true
end
return false
end
function rope:update()
if self.cast!=nil then
self:continue_cast()
return
end
self.latch_frame+=1
if self.latch_frame>=10 then
self.latch_frame=10
end
self:_make_consistent()
end
function rope:_make_consistent()
for i=0,#self.ancs+1 do
local anc=self:_anc(i)
_apply(anc,anc.todo,i)
end
if
not self.under_destruction and
self.latch!=nil and
self.latch.rec!=nil
then
self:drag_src(
self.latch.rec.px+self.latch.px_offset,
self.latch.rec.py+self.latch.py_offset
)
if #self.latch.rec.todo==0 then
2022-12-17 23:48:52 +00:00
if self.latch.rec.dead==true then
self.under_destruction=true
return
end
2022-12-17 20:16:26 +00:00
for i=0,#self.ancs do
local a0=self:_anc(i)
local a1=self:_anc(i+1)
if not self:_can_stretch(a0, a1) then
self.under_destruction=true
2022-12-17 23:48:52 +00:00
return
2022-12-17 20:16:26 +00:00
end
end
end
end
end
function rope:continue_cast()
local dx,dy=self.cast.dx,self.cast.dy
local x0=self.src.x
local y0=self.src.y
local x1=x0+dx
local y1=y0+dy
for x,y in self:_rast(
x0,y0,x1,y1
) do
local latch=
level:get_latch(dx,dy,x,y)
if latch!=nil or level:pcoll(x,y) then
self.latch=latch
self.cast=nil
break
end
self.src={x=x,y=y,todo={}}
end
end
function rope:_reindex()
self.src.ix=0
self.dst.ix=#self.ancs
for i,anc in ipairs(self.ancs) do
anc.ix=i
end
end
function rope:draw()
local points=self:_anchors_simplified()
for i=1,(#points-1) do
local src=points[i]
local dst=points[i+1]
local x,y=src.x,src.y
local dx,dy=dst.x-x,dst.y-y
linefill(x,y,x+0.25*dx,y+0.25*dy,1.0,8)
linefill(x+0.25*dx,y+0.25*dy,x+1*dx,y+1*dy,0.5,8)
linefill(x+0.9*dx,y+0.9*dy,x+dx,y+dy,1.0,8)
circfill(x+0.5,y+0.5,1.0,8)
end
for i,p in ipairs(self.ancs) do
rectfill(p.x-1,p.y-1,p.x+1,p.y+1,12)
print(p.id..":"..p.x..","..p.y..","..#p.todo,0,-8+i*8,9)
end
for _,p in pairs(level._anch) do
pset(p.x,p.y,11)
end
if self.all_ops!=nil then
for i,o in ipairs(self.all_ops) do
rect(o.mx*8,o.my*8,o.mx*8+7,o.my*8+7,4)
--print(o.mx..","..o.my,0,i*8,3)
end
end
end
function rope:_anc(i)
if (i==0) return self.src
if (i==#self.ancs+1) return self.dst
return self.ancs[i]
end
function rope:drag_dst(x,y)
self:drag(function() return #self.ancs+1 end,x,y)
end
function rope:drag_src(x,y)
self:drag(function() return 0 end,x,y)
end
function rope:drag(
i,x,y
)
local anc=self:_anc(i())
2022-12-17 21:52:37 +00:00
local busy=self:busy()
for x,y in self:_rast(
anc.x,anc.y,x,y
2022-12-17 20:16:26 +00:00
) do
local a=self:_anc(i())
2022-12-17 21:52:37 +00:00
if not (_point_eq(a,{x=x,y=y})) then
a.x=x
a.y=y
a.dirty=true
2022-12-17 21:52:37 +00:00
self.dirty=true
if (not busy) self:_tidy_up_gen()
end
2022-12-17 20:16:26 +00:00
end
end
function rope:_tidy_up_gen()
if (self.under_destruction) return
2022-12-17 21:52:37 +00:00
if (not self.dirty) return
2022-12-17 20:16:26 +00:00
local settled=true
local touched={}
local loop=function(f)
local a=0
while a<=#self.ancs+1 do
local anc=self:_anc(a)
if anc.dirty then
anc.seen=true
if self[f](self,a) then
settled=false anc.changed=true
end
end
2022-12-17 20:16:26 +00:00
a+=1
end
end
local mark_unseen=function()
touched={}
for a=0,#self.ancs+1,1 do
local anc=self:_anc(a)
anc.seen=false
anc.changed=false
end
end
local propagate_dirty=function(f)
for a=0,#self.ancs+1,1 do
local a1=self:_anc(a)
if a1.dirty then
local a0=self:_anc(a-1)
if (a0!=nil) a0.dirty=true
local a2=self:_anc(a+1)
if (a2!=nil) a2.dirty=true
end
end
end
while true do
settled=true
mark_unseen()
propagate_dirty()
loop("_find_needed_anchors")
loop("_find_touched_anchors")
loop("_elide_point")
for a=0,#self.ancs+1,1 do
local anc=self:_anc(a)
2022-12-17 21:52:37 +00:00
if (anc.seen) anc.dirty=anc.changed
end
if (settled) break
end
2022-12-17 21:52:37 +00:00
self.dirty=false
2022-12-17 20:16:26 +00:00
end
function rope:_find_needed_anchors(i)
if (i<=0) return false
if (#self.ancs+1<i) return false
local a0=self:_anc(i-1)
local a2=self:_anc(i)
if (level:pcoll(a2.x,a2.y)) return false
if (level:pcoll(a0.x,a0.y)) return false
if (self:_can_stretch(a0,a2)) return false
local anchors_bydist={}
local x0,x2=_mnmx(a0.x,a2.x)
local y0,y2=_mnmx(a0.y,a2.y)
for a1 in level:anchors_in(x0-1,y0-1,x2+1,y2+1) do
add(anchors_bydist,{el=a1,key=_linedist(a0,a1,a2)})
2022-12-17 20:16:26 +00:00
end
shellsort(anchors_bydist)
for a1 in all(anchors_bydist) do
a1=a1.el
if self:_can_stretch(a0,a1) and
self:_can_stretch(a1,a2)
then
local id=self.id
add(self.ancs,{id=id,x=a1.x,y=a1.y,dirty=true,todo={}},i)
2022-12-17 20:16:26 +00:00
self.id+=1
return true
end
end
end
function rope:_find_touched_anchors(i)
if (i<=0) return false
if (#self.ancs<i) return false
local a0=self:_anc(i-1)
local a2=self:_anc(i)
if (level:pcoll(a0.x,a0.y)) return false
if (level:pcoll(a2.x,a2.y)) return false
2022-12-17 20:16:26 +00:00
for bx,by in self:_rast(a0.x,a0.y,a2.x,a2.y) do
local a1=level:point_anchor(bx,by)
if
a1!=nil and not _point_eq(a0,a1) and not _point_eq(a1,a2)
and _linedist(a0,a1,a2) == 0.0
2022-12-17 20:16:26 +00:00
-- and self:_can_stretch(p,a2)
then
local id=self.id
add(self.ancs,{id=id,x=a1.x,y=a1.y,dirty=true,todo={}},i)
2022-12-17 20:16:26 +00:00
self.id+=1
return true
end
end
return false
end
function rope:_elide_point(i)
if (i<=0) return false
if (#self.ancs<i) return false
local a0=self:_anc(i-1)
local a1=self:_anc(i)
local a2=self:_anc(i+1)
local level_anc=level:point_anchor(a1.x,a1.y)
if _point_eq(a0,a1) or _point_eq(a1,a2) or level_anc==nil then
-- do it unconditionally
else
if _linedist(a0,a1,a2) < 0.1 then
return false
end
if not self:_can_stretch(a0,a2) then
return false
end
local midpoint={
x=(a0.x+a2.x)\2,
y=(a0.y+a2.y)\2
}
if not self:_can_move_midpoint(a0,a1,midpoint,a2) then
return false
end
end
deli(self.ancs,i)
return true
end
function rope:_can_move_midpoint(a0,a1_0,a1_1,a2)
if (level:pcoll(a0.x,a0.y)) return false
if (level:pcoll(a2.x,a2.y)) return false
if (level:pcoll(a1_0.x,a1_0.y)) return false
if (level:pcoll(a1_1.x,a1_1.y)) return false
2022-12-17 20:16:26 +00:00
if not self:_can_stretch(a1_0, a1_1) then
return false
end
if not self:_can_stretch(a0,a1_1) then
return false
end
if not self:_can_stretch(a1_1,a2) then
return false
end
2022-12-17 21:52:37 +00:00
for x,y in self:_rastn(a1_0.x,a1_0.y,a1_1.x,a1_1.y,8,8) do
2022-12-17 20:16:26 +00:00
local tm={x=x,y=y}
if not self:_can_stretch(a0,tm) then
return false
end
if not self:_can_stretch(tm,a2) then
return false
end
end
return true
end
function _linedist(x0,v,x1)
return 100 * (sum_distance(x0,v,x1)-distance(x0,x1))/distance(x0,x1)
end
function sum_distance(x,y,z)
return distance(x,y) + distance(y,z)
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_rect(x1,y1,x2,y2,exclude_src,exclude_dst)
local last=#self.ancs-exclude_dst
for i=exclude_src,last,1 do
local a0=self:_anc(i)
local a1=self:_anc(i+1)
if (_line_line(a0.x,a0.y,a1.x,a1.y,x1,y1,x2,y1)) return true
if (_line_line(a0.x,a0.y,a1.x,a1.y,x1,y1,x1,y2)) return true
if (_line_line(a0.x,a0.y,a1.x,a1.y,x1,y2,x2,y2)) return true
if (_line_line(a0.x,a0.y,a1.x,a1.y,x2,y1,x2,y2)) return true
end
return false
end
function _line_line(x1,y1,x2,y2,x3,y3,x4,y4)
local denom=((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1))
local ua=
((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/denom
if (ua<0 or ua>1) return false
local ub=
((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/denom
if (ub<0 or ub>1) return false
return true
end
function rope:_can_stretch(
p1,p2
)
-- faster implementation for straight lines
if p1.y\8==p2.y\8 then
local my=p2.y\8
for mx=p1.x\8,p2.x\8 do
if (level:mcoll(mx,my)) return false
end
end
if p1.x\8==p2.x\8 then
local mx=p2.x\8
for my=p1.y\8,p2.y\8 do
if (level:mcoll(mx,my)) return false
end
end
2022-12-17 20:16:26 +00:00
if (level:pcoll(p1.x,p1.y)) return false
if (level:pcoll(p2.x,p2.y)) return false
local res=true
2022-12-17 21:52:37 +00:00
for x,y in self:_rastn(p1.x,p1.y,p2.x,p2.y,8,8) do
2022-12-17 20:16:26 +00:00
if level:pcoll(x,y) then
res=false
break
end
end
return res
end
2022-12-17 21:52:37 +00:00
function rope:_rastn(
x0,y0,x1,y1,dx,dy
2022-12-17 20:16:26 +00:00
)
-- todo: more optimized implementation?
local iter=self:_rast(x0,y0,x1,y1)
local prevx,prevy=nil,nil
local done=false
return function()
while not done do
local x,y=iter()
if (x==nil) done=true return x1, y1
2022-12-17 21:52:37 +00:00
local x8 = x\dx
local y8 = y\dy
2022-12-17 20:16:26 +00:00
if not (x8==prevx and y8==prevy) then
prevx,prevy=x8,y8
return x,y
end
end
end
end
function rope:_rast(
x0,y0,x1,y1
)
local dx=abs(x1-x0)
local dy=abs(y1-y0)
local x=x0
local y=y0
local sx=-1
local sy=-1
if (x0<x1) sx=1
if (y0<y1) sy=1
local done=false,err
if dx>dy then
err=dx/2.0
return function()
if (done) return
if (x==x1) done=true return x1,y1
local oldx,oldy=x,y
err-=dy
if (err<0) y+=sy err+=dx
x+=sx
return oldx,oldy
2022-12-17 20:16:26 +00:00
end
else
err=dy/2.0
return function()
if (done) return
if (y==y1) done=true return x1,y1
local oldx,oldy=x,y
err-=dx
if (err<0) x+=sx err+=dy
y+=sy
return oldx,oldy
2022-12-17 20:16:26 +00:00
end
end
end
function _point_eq(p1,p2)
return p1.x==p2.x and p1.y==p2.y
end
function neighbors(p)
local r={}
for dx=-1,1,1 do
for dy=-1,1,1 do
if dx!=0 or dy!=0 then
add(r,{x=p.x+dx,y=p.y+dy})
end
end
end
return r
end
-->8
-- moved here because it's complicated
2022-12-18 00:57:47 +00:00
function rope:tug_orientxy()
local a1=self:_anc(#self.ancs+1)
local a0=self:_anc(#self.ancs)
local dx=a0.x-a1.x
local tdx=0
if (dx>3) tdx=1
if (dx<-3) tdx=-1
local dy=a0.y-a1.y
local tdy=0
if abs(dy)>abs(dx)/2 then
if (dy>3) tdy=1
if (dy<-3) tdy=-1
end
return tdx,tdy
end
2022-12-17 20:16:26 +00:00
function rope:tug()
self:_make_consistent()
if (self.under_destruction) return
self:_tug()
self:_make_consistent()
end
function rope:_tug()
local ancs=self:_anchors_simplified()
local touched={}
for i=#ancs-1,2,-1 do
local ops= self:_calc_push(ancs[i+1],ancs[i],ancs[i-1])
for o in all(ops) do
add(self.all_ops,o)
end
local can_do=true
for o in all(ops) do
if not level:mcoll(o.mx,o.my) then
-- great!
else
local crate=level:get_crate(o.mx,o.my)
if crate==nil or touched[_mix(o.mx,o.my)] then
can_do=false
else
2022-12-17 23:08:54 +00:00
if not level:can_move(false,o.mx,o.my,o.dmx,o.dmy,0,0) then
2022-12-17 20:16:26 +00:00
can_do=false
end
end
end
if (not can_do) break
end
if can_do and #ops>=1 then
local dmx,dmy=ops[1].dmx,ops[1].dmy
for o in all(ops) do
touched[_mix(o.mx,o.my)]=true
touched[_mix(o.mx+dmx,o.my+dmy)]=true
level:tug_crate(
o.mx,o.my,dmx,dmy
)
end
for node=ancs[i-1].ix,ancs[i].ix do
local anc=self:_anc(node)
local x0,y0=anc.x,anc.y
local upd=function(x,y,force)
return {update=function(s,i)
if force or not level:pcoll(x,y) then
s.x=x
s.y=y
2022-12-17 21:52:37 +00:00
self.dirty=true
2022-12-17 20:16:26 +00:00
end
return true
end}
end
anc.todo={
{},
upd(x0+dmx*2,y0+dmy*2),
upd(x0+dmx*7,y0+dmy*7),
upd(x0+dmx*8,y0+dmy*8),
}
end
for node=ancs[i-1].ix-1,ancs[i].ix+1 do
local anc=self:_anc(node)
end
return
end
end
local latch=self.latch
if (latch==nil) return
if latch.el=="crate" then
local dmx,dmy=
sgn0(latch.dx),
sgn0(latch.dy)
local lanc=ancs[2]
local mx0=latch.rec.mx
local my0=latch.rec.my
local mxa=(lanc.x+dmx)\8
local mya=(lanc.y+dmy)\8
local too_far=false
if
sgn0(mx0-mxa)!=
sgn0(mx0+dmx-mxa) or
sgn0(my0-mya)!=
sgn0(my0+dmy-mya)
then
too_far=true
end
if not too_far and
not touched[_mix(mx0,my0)] and
2022-12-17 23:08:54 +00:00
level:can_move(false,mx0,my0,dmx,dmy,1,0)
2022-12-17 20:16:26 +00:00
then
level:tug_crate(
mx0,my0,
dmx,dmy
)
2022-12-17 21:52:37 +00:00
-- be busy for 4 ticks while the crate moves
self:_anc(0).todo={{},{},{},{}}
2022-12-17 20:16:26 +00:00
end
end
end
function rope:_calc_push(
an,a0,a1
)
local ops={}
if a0.x==a1.x then
local y0,y1=_mnmx(a0.y,a1.y)
local my0,my1=(y0+1)\8,(y1-1)\8
local mx,dmx
if a0.x%8==0 and a0.x>an.x+7 then
-- push left
mx=(a0.x-1)\8
dmx=-1
elseif a0.x%8==7 and a0.x<an.x-7 then
-- push right
mx=(a0.x+1)\8
dmx=1
else
return {}
end
for my=my0,my1,1 do
add(ops,{mx=mx,my=my,dmx=dmx,dmy=0})
end
end
if a0.y==a1.y then
local x0,x1=_mnmx(a0.x,a1.x)
local mx0,mx1=(x0+1)\8,(x1-1)\8
local my,dmy
if a0.y%8==0 and a0.y>an.y+6 then
-- push up
my=(a0.y-1)\8
dmy=-1
elseif a0.y%8==7 and a0.y<an.y-3 then
-- push down
my=(a0.y+1)\8
dmy=1
else
return {}
end
for mx=mx0,mx1,1 do
add(ops,{mx=mx,my=my,dmx=0,dmy=dmy})
end
end
return ops
end
function rope:_anchors_simplified()
-- todo: cache this
self:_reindex()
local points={}
local _slope = function(p0,p1)
return atan2(p1.y-p0.y,p1.x-p0.x)
end
for i=0,#self.ancs+1,1 do
local anc=self:_anc(i)
if #points<=1 then
add(points,anc)
elseif abs(
_slope(points[#points-1],points[#points])-
_slope(points[#points],anc)
)==0 then -- epsilon?
points[#points]=anc
else
add(points,anc)
end
end
return points
end
__gfx__
000000000000300000000022000030000000000000000000000000000000000000000000000000000000000000000000dddddddd000000000000000000000000
000000000033333000003322003333300aa00aa000000000000000000000000000000000000000000000000000000000dddddddd000000000000000000000000
000000000993339900399320093333390aaaaaa000000000000000000000000000000000000000000000000000000000dddddddd000000000000000000000000
0000000009a333a9033a9320093333390aaaaaa000000000000000000000000000000000000000000000000000000000dddddddd000000000000000000000000
000000000233333233333200002222200099990000000000000000000000000000000000000000000000000000000000dddddddd000000000000000000000000
0000000000222220000022000022222000aaaa0000000000000000000000000000000000000000000000000000000000dddddddd000000000000000000000000
00000000000222c002222c0000022200000aa00000000000000000000000000000000000000000000000000000000000dddddddd000000000000000000000000
0000000000000cc00000cc0000000cc00044440000000000000000000000000000000000000000000000000000000000dddddddd000000000000000000000000
2022-12-18 00:25:20 +00:00
0000ff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
000f00f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00d0000f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00d0d00f00c040500000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00dd00ee00c445500000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00000ee00c4445550000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00eeee000c0040050000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
eeee0000cc0440550000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
2022-12-17 23:08:54 +00:00
00000000000a90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000aaaaaaa91000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000aaaaaa1a91100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0aaaaaaaaa1a91110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0aaaaaaaa41a91a10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0a000aa4441a91a10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00a0044449a110a10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000aa111991111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000991000000000000000000000000000000000000000000000000000000000000000000000000000000000000077700777777777777777777777777777
00000000990000000000000000000000000000000000000000000000000000000000000000000000000000000000000077700777777777777777777777777777
00000000990000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777777777777777777
00000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000077700777777007007770077700700777
00000000aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000077700777777007007770077700700777
0000000077a000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777777777777777777
00000007777a00000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777770077777777777
00044444444444000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777770077777777777
2022-12-17 23:48:52 +00:00
77077077777007777707707777700777770770777770077777077077777007777707707777700777770770777770077777077077777007777707707777700777
77777777777007777777777777700777777777777770077777777777777007777777777777700777777777777770077777777777777007777777777777700777
07777770077777700777777707777777077777700777777007777777077777777777777077777770777777777777777777777770777777707777777777777777
77700777777007777770070077700700777007777770077777700700777007000070077700700777007007000070070000700777007007770070070000700700
77700777777007777770070077700700777007777770077777700700777007000070077700700777007007000070070000700777007007770070070000700700
07777770077777700777777707777777077777700777777007777777077777777777777077777770777777777777777777777770777777707777777777777777
77777777777777777777777777777777777007777770077777700777777007777777777777777777777777777777777777700777777007777770077777700777
77077077770770777707707777077077777007777770077777700777777007777707707777077077770770777707707777700777777007777770077777700777
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__
2022-12-17 23:08:54 +00:00
000000000000000000000000c00000000000000000000000000000000000000040400000000000000000000000000000404000000000000000000000c0c0c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2022-12-17 20:16:26 +00:00
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__map__
2022-12-17 23:08:54 +00:00
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2022-12-17 23:48:52 +00:00
0c000000000044000c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2022-12-17 23:08:54 +00:00
0c000000000000000c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2022-12-17 23:48:52 +00:00
0100000000001c000c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2022-12-17 23:08:54 +00:00
0c000000000000000c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c000000000000000c0c0c0c0c0c0c0c0c00000000000020210000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c000000000000000000000c0c0c0c0c0c00000000000030310000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c00000000000000040100000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000