chameleonic/chameleonic.p8

1622 lines
51 KiB
Lua
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
function _doall(x)
for n in names(x) do
for mod in all(modules) do
local f=mod[n]
if (f) f(mod)
end
end
end
-- source: https://www.lexaloffle.com/bbs/?pid=78990
gaps=split"57,23,10,4,1"
--{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
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
-- 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
end
x0+=dx
end
x0,y0=_x1,_y1
end
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)
end
function _mnmx(x,y)
return min(x,y),max(x,y)
end
-->8
bg={}
add(modules,bg)
function bg:draw0()
cls(0)
end
-->8
level={}
add(modules,level)
function level:init()
level:reinit(0)
end
function level:reinit(n)
self.ix=n
self.todo={}
self.bigx=(n%16)
self.bigy=(n\16)
self:load_dynobjs()
self:recollide()
self:reanchor(true)
self:spawn_exit()
end
function level:restart()
self:reinit(self.ix)
end
function level:advance()
self:reinit(self.ix+1)
end
function level:draw()
cls(1)
pal(1,0)
map(
self.bigx*16,self.bigy*16,
0,0,16,16,
64 -- flag 6: visible
)
for _,pit in pairs(self._pits) do
spr(pit.s,pit.px,pit.py)
if pit.contents then
pal(7,0)
pal(0,1)
palt(0,false)
spr(pit.contents,pit.px,pit.py)
pal()
end
for _,crate in pairs(self._crates) do
spr(crate.s,crate.px,crate.py)
end
end
pal()
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)
local remove={}
for cix,crate in pairs(self._crates) do
_apply(crate, crate.todo)
if #crate.todo==0 then
local pit=self._pits[_mix(crate.mx,crate.my)]
if pit!=nil and pit.contents==nil then
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)
end
end
function level:load_dynobjs()
self._crates={}
self._pits={}
for mx=0,15,1 do
for my=0,15,1 do
local mxy=_mix(mx,my)
local px,py=mx*8,my*8
local s=self:_mget(mx,my)
local def=self:_get_cratedef(s)
if def!=nil then
self._crates[mxy]={
s=s,def=def,
mx=mx,my=my,
px=px,py=py,
todo={}
}
end
if s==28 then -- pit
self._pits[mxy]={
s=s,
mx=mx,my=my,
px=px,py=py,
contents=nil
}
end
end
end
end
function level:recollide()
self._coll={}
for mx=0,15,1 do
for my=0,15,1 do
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 self._anch==nil then
self._anch={}
end
for ax0=0,31,1 do
for ay0=0,31,1 do
local ax1,ay1=ax0-1+2*(ax0%2),ay0-1+2*(ay0%2)
local mx0,my0=ax0\2,ay0\2
local mx1,my1=ax1\2,ay1\2
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
function level:win_at(mx,my)
return self._wins[_mix(mx,my)]
end
function level:anchor_points()
return pairs(self._anch)
end
function level:anchors_in(px0,py0,px1,py1)
ancs={}
for ax=px0\4,(px1+3)\4 do
for ay=py0\4,(py1+3)\4 do
local anc=self._anch[_amix(ax,ay)]
if (anc!=nil) add(ancs, anc)
end
end
return ancs
end
function level:get_open_pit(mx,my)
local pit=self._pits[_mix(mx,my)]
if (pit and pit.contents==nil) return pit
end
function level:point_anchor(px,py)
local ax,ay=self:p2a(px,py)
local anc=self._anch[_amix(ax,ay)]
return anc
end
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)
player.orientx=-1
if (x<8) player.orientx=1
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
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)
return self._coll[_mix(mx,my)]!=false
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(
is_player,
mx0,my0,dmx,dmy,exclude_src,exclude_dst
)
if is_player and self:win_at(mx0+dmx,my0+dmy) then
return true
end
if self:mcoll(mx0+dmx,my0+dmy) then
return false
end
if player.x==mx0+dmx and player.y==my0+dmy then
return false
end
-- 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)
-- don't change this on reinit:
-- it stays the same when the level is changed or reloaded
self.vanish_frame=0
end
function player:reinit(x,y)
self.x=x
self.y=y
self.px=0
self.py=0
self.todo={}
self.fall_frame=0
self.reset_frame=0
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
-- this is a non-gameplay action that takes precedence over
-- all gameplay actions
self:_vanish_if_requested()
if not self:any_busy() then
if level:win_at(self.x,self.y) then
level:advance()
return
end
if level:get_open_pit(self.x,self.y) then
self.todo={{update=self._fall}}
return
end
if btn() then
if level:can_move(true,self.x,self.y,-1,0,0,2) then
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
if level:can_move(true,self.x,self.y,1,0,0,2) then
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
if level:can_move(true,self.x,self.y,0,-1,0,2) then
self.todo=f4({{orienty=-1,py=-2},{py=-7},{y=self.y-1}})
else
self.orienty=-1
end
elseif btn() then
if level:can_move(true,self.x,self.y,0,1,0,2) then
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)
local tdx,tdy=self.rope:tug_orientxy()
if (tdx!=0) self.orientx=tdx
if (tdy!=0) self.orienty=tdy
if self.rope:done() then
self.rope=nil
add(self.todo,{})
add(self.todo,{})
add(self.todo,{})
end
end
end
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
if (self.fall_frame>0 or self.vanish_frame>20) then
level:restart()
self.vanish_frame=20
self.vanishing=false
end
else
self.vanish_frame-=1
end
self.vanish_frame=max(self.vanish_frame,0)
end
function player:_fall()
if (self.fall_frame<10) self.fall_frame+=1
end
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
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
if self.fall_frame>3 then
for i=0,15 do pal(i,1) end
end
end
if self.orientx==-1 then
setpal()
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()
spr(head,px-3,py-3,1,1)
else
setpal()
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()
spr(head,px+3,py-3,1,1,true)
end
pal()
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
if self.latch.rec.dead==true then
self.under_destruction=true
return
end
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
return
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())
local busy=self:busy()
for x,y in self:_rast(
anc.x,anc.y,x,y
) do
local a=self:_anc(i())
if not (_point_eq(a,{x=x,y=y})) then
a.x=x
a.y=y
a.dirty=true
self.dirty=true
if (not busy) self:_tidy_up_gen()
end
end
end
function rope:_tidy_up_gen()
if (self.under_destruction) return
if (not self.dirty) return
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
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)
if (anc.seen) anc.dirty=anc.changed
end
if (settled) break
end
self.dirty=false
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 all(level:anchors_in(x0-1,y0-1,x2+1,y2+1)) do
add(anchors_bydist,{el=a1,key=_linedist(a0,a1,a2)})
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)
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
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
-- 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)
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
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
for x,y in self:_rastn(a1_0.x,a1_0.y,a1_1.x,a1_1.y,8,8) do
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
if (level:pcoll(p1.x,p1.y)) return false
if (level:pcoll(p2.x,p2.y)) return false
local res=true
for x,y in self:_rastn(p1.x,p1.y,p2.x,p2.y,8,8) do
if level:pcoll(x,y) then
res=false
break
end
end
return res
end
function rope:_rastn(
x0,y0,x1,y1,dx,dy
)
-- 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
local x8 = x\dx
local y8 = y\dy
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
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
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
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
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
if not level:can_move(false,o.mx,o.my,o.dmx,o.dmy,0,0) then
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
self.dirty=true
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
level:can_move(false,mx0,my0,dmx,dmy,1,0)
then
level:tug_crate(
mx0,my0,
dmx,dmy
)
-- be busy for 4 ticks while the crate moves
self:_anc(0).todo={{},{},{},{}}
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
0000ff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
000f00f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00d0000f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00d0d00f00c040500000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00dd00ee00c445500000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00000ee00c4445550000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00eeee000c0040050000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
eeee0000cc0440550000000000000000000000000000000000000000000000000000000000000000000000000000000011111111000000000000000000000000
00000000000a90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000aaaaaaa91000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000aaaaaa1a91100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0aaaaaaaaa1a91110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0aaaaaaaa41a91a10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0a000aa4441a91a10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00a0044449a110a10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000aa111991111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000991000000000000000000000000000000000000000000000000000000000000000000000000000000000000077700777777777777777777777777777
00000000990000000000000000000000000000000000000000000000000000000000000000000000000000000000000077700777777777777777777777777777
00000000990000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777777777777777777
00000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000077700777777007007770077700700777
00000000aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000077700777777007007770077700700777
0000000077a000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777777777777777777
00000007777a00000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777770077777777777
00044444444444000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777770077777777777
77077077777007777707707777700777770770777770077777077077777007777707707777700777770770777770077777077077777007777707707777700777
77777777777007777777777777700777777777777770077777777777777007777777777777700777777777777770077777777777777007777777777777700777
07777770077777700777777707777777077777700777777007777777077777777777777077777770777777777777777777777770777777707777777777777777
77700777777007777770070077700700777007777770077777700700777007000070077700700777007007000070070000700777007007770070070000700700
77700777777007777770070077700700777007777770077777700700777007000070077700700777007007000070070000700777007007770070070000700700
07777770077777700777777707777777077777700777777007777777077777777777777077777770777777777777777777777770777777707777777777777777
77777777777777777777777777777777777007777770077777700777777007777777777777777777777777777777777777700777777007777770077777700777
77077077770770777707707777077077777007777770077777700777777007777707707777077077770770777707707777700777777007777770077777700777
__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__
000000000000000000000000c00000000000000000000000000000000000000040400000000000000000000000000000404000000000000000000000c0c0c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__map__
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c000000000044000c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c000000000000000c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0100000000001c000c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c000000000000000c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c000000000000000c0c0c0c0c0c0c0c0c00000000000020210000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c000000000000000000000c0c0c0c0c0c00000000000030310000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c00000000000000040100000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c00000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000