Rewrite rope #11
415
chameleonic.p8
415
chameleonic.p8
@ -116,29 +116,6 @@ function _mnmx(x,y)
|
|||||||
return x,y
|
return x,y
|
||||||
end
|
end
|
||||||
|
|
||||||
function _rastn(
|
|
||||||
x0,y0,x1,y1,dx,dy
|
|
||||||
)
|
|
||||||
-- todo: more optimized implementation?
|
|
||||||
local iter=_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 _rast(
|
function _rast(
|
||||||
x0,y0,x1,y1
|
x0,y0,x1,y1
|
||||||
@ -161,7 +138,7 @@ function _rast(
|
|||||||
if (x==x1) done=true return x1,y1
|
if (x==x1) done=true return x1,y1
|
||||||
local oldx,oldy=x,y
|
local oldx,oldy=x,y
|
||||||
err-=dy
|
err-=dy
|
||||||
if (err<0) y+=sy err+=dx+dy return oldx,y
|
if (err<0) y+=sy err+=dx
|
||||||
x+=sx
|
x+=sx
|
||||||
return oldx,oldy
|
return oldx,oldy
|
||||||
end
|
end
|
||||||
@ -172,17 +149,13 @@ function _rast(
|
|||||||
if (y==y1) done=true return x1,y1
|
if (y==y1) done=true return x1,y1
|
||||||
local oldx,oldy=x,y
|
local oldx,oldy=x,y
|
||||||
err-=dx
|
err-=dx
|
||||||
if (err<0) x+=sx err+=dy+dx return x,oldy
|
if (err<0) x+=sx err+=dy
|
||||||
y+=sy
|
y+=sy
|
||||||
return oldx,oldy
|
return oldx,oldy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _point_eq(p1,p2)
|
|
||||||
return p1.x==p2.x and p1.y==p2.y
|
|
||||||
end
|
|
||||||
|
|
||||||
-->8
|
-->8
|
||||||
-- input
|
-- input
|
||||||
kbd={}
|
kbd={}
|
||||||
@ -232,6 +205,33 @@ function kbd:release(i)
|
|||||||
self.down&=~(1<<i)
|
self.down&=~(1<<i)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function tostring(any)
|
||||||
|
if type(any)=="function" then
|
||||||
|
return "function"
|
||||||
|
end
|
||||||
|
if any==nil then
|
||||||
|
return "nil"
|
||||||
|
end
|
||||||
|
if type(any)=="string" then
|
||||||
|
return any
|
||||||
|
end
|
||||||
|
if type(any)=="boolean" then
|
||||||
|
if any then return "true" end
|
||||||
|
return "false"
|
||||||
|
end
|
||||||
|
if type(any)=="table" then
|
||||||
|
local str = "{ "
|
||||||
|
for k,v in pairs(any) do
|
||||||
|
str=str..tostring(k).."->"..tostring(v).." "
|
||||||
|
end
|
||||||
|
return str.."}"
|
||||||
|
end
|
||||||
|
if type(any)=="number" then
|
||||||
|
return ""..any
|
||||||
|
end
|
||||||
|
return "unknown" -- should never show
|
||||||
|
end
|
||||||
|
|
||||||
-->8
|
-->8
|
||||||
-- title screen
|
-- title screen
|
||||||
title={}
|
title={}
|
||||||
@ -293,7 +293,7 @@ function level:reinit(n)
|
|||||||
self.todo={}
|
self.todo={}
|
||||||
self.bigx=(n%8)
|
self.bigx=(n%8)
|
||||||
self.bigy=(n\8)
|
self.bigy=(n\8)
|
||||||
self.cache_can_stretch=dcache:new()
|
self.next_crate_id=1
|
||||||
|
|
||||||
self:load_dynobjs()
|
self:load_dynobjs()
|
||||||
self:recollide()
|
self:recollide()
|
||||||
@ -327,15 +327,15 @@ function level:draw()
|
|||||||
pal()
|
pal()
|
||||||
pal(1,0)
|
pal(1,0)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
for _,crate in pairs(self._crates) do
|
for _,crate in pairs(self._crates) do
|
||||||
spr(crate.s,crate.px,crate.py)
|
spr(crate.s,crate.px,crate.py)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
pal()
|
pal()
|
||||||
end
|
end
|
||||||
|
|
||||||
function level:busy()
|
function level:busy()
|
||||||
for _,crate in pairs(self.crates) do
|
for _,crate in pairs(self._crates) do
|
||||||
if (#crate.todo>0) return true
|
if (#crate.todo>0) return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
@ -379,10 +379,12 @@ function level:load_dynobjs()
|
|||||||
if def then
|
if def then
|
||||||
self._crates[mxy]={
|
self._crates[mxy]={
|
||||||
s=s,def=def,
|
s=s,def=def,
|
||||||
|
id=self.next_crate_id,
|
||||||
mx=mx,my=my,
|
mx=mx,my=my,
|
||||||
px=px,py=py,
|
px=px,py=py,
|
||||||
todo={}
|
todo={}
|
||||||
}
|
}
|
||||||
|
self.next_crate_id+=1
|
||||||
end
|
end
|
||||||
|
|
||||||
if s==28 then -- pit
|
if s==28 then -- pit
|
||||||
@ -399,15 +401,17 @@ end
|
|||||||
|
|
||||||
function level:recollide()
|
function level:recollide()
|
||||||
self._coll={}
|
self._coll={}
|
||||||
|
self._coll_nocrate={}
|
||||||
for mx=0,15 do
|
for mx=0,15 do
|
||||||
for my=0,15 do
|
for my=0,15 do
|
||||||
local mxy=_mix(mx,my)
|
local mxy=_mix(mx,my)
|
||||||
|
self._coll_nocrate[mxy]=
|
||||||
|
fget(self:_mget(mx,my),7)
|
||||||
self._coll[mxy]=
|
self._coll[mxy]=
|
||||||
fget(self:_mget(mx,my),7) or
|
self._coll_nocrate[mxy] or
|
||||||
self._crates[mxy]!=nil
|
self._crates[mxy]!=nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.cache_can_stretch:clear()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function add_adjacent_anchors(tbl,mx,my)
|
function add_adjacent_anchors(tbl,mx,my)
|
||||||
@ -420,33 +424,72 @@ function add_adjacent_anchors(tbl,mx,my)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function level:reanchor()
|
function level:reanchor()
|
||||||
self._anch={}
|
local anch_new={}
|
||||||
for dxy in all{{-1,-1},{1,-1},{-1,1},{1,1}} do
|
for dxy in all{{-1,-1},{1,-1},{-1,1},{1,1}} do
|
||||||
local dx,dy=unpack(dxy)
|
local dx,dy=unpack(dxy)
|
||||||
assert(dx!=0 and dy!=0)
|
assert(dx!=0 and dy!=0)
|
||||||
for mx0=0,15 do
|
for mx0=0,15 do
|
||||||
for my0=0,15 do
|
for my0=0,15 do
|
||||||
local mx1,my1=mx0+dx,my0+dy
|
local mx1,my1=mx0+dx,my0+dy
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self:mcoll(mx0,my0) and
|
self:mcoll_nocrate(mx0,my0) and
|
||||||
not self:mcoll(mx0,my1) and
|
not self:mcoll(mx0,my1) and
|
||||||
not self:mcoll(mx1,my0) and
|
not self:mcoll(mx1,my0) and
|
||||||
not self:mcoll(mx1,my1)
|
not self:mcoll(mx1,my1)
|
||||||
) then
|
) then
|
||||||
add(self._anch, {
|
local key="GEOM"..mx0..","..my0..","..dx..","..dy
|
||||||
|
anch_new[key]= {
|
||||||
ax=max(mx0,mx1),ay=max(my0,my1),adx=-dx,ady=-dy
|
ax=max(mx0,mx1),ay=max(my0,my1),adx=-dx,ady=-dy
|
||||||
})
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for _,cr in pairs(self._crates) do
|
||||||
|
local key="CRATE"..cr.id..","..dx..","..dy
|
||||||
|
local mx0,my0=cr.mx,cr.my
|
||||||
|
local mx1,my1=mx0+dx,my0+dy
|
||||||
|
anch_new[key]={
|
||||||
|
ax=max(mx0,mx1),ay=max(my0,my1),adx=-dx,ady=-dy
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local anch_old=self._anch
|
||||||
|
if (anch_old==nil) anch_old={}
|
||||||
|
for _,old in pairs(anch_old) do
|
||||||
|
old.dropped=true
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,new in pairs(anch_new) do
|
||||||
|
local old=anch_old[k]
|
||||||
|
if old then
|
||||||
|
anch_new[k]=old
|
||||||
|
old.ax,old.ay,old.adx,old.ady=new.ax,new.ay,new.adx,new.ady
|
||||||
|
old.dropped=nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self._anch=anch_new
|
||||||
|
self._anch_keys={}
|
||||||
|
for k,_ in pairs(self._anch) do
|
||||||
|
add(self._anch_keys,{key=k})
|
||||||
|
end
|
||||||
|
|
||||||
|
if (player.rope!=nil) player.rope:relax()
|
||||||
|
end
|
||||||
|
|
||||||
function level:win_at(mx,my)
|
function level:win_at(mx,my)
|
||||||
return self._wins[_mix(mx,my)]
|
return self._wins[_mix(mx,my)]
|
||||||
end
|
end
|
||||||
|
|
||||||
function level:anchor_points()
|
function level:anchor_points()
|
||||||
return pairs(self._anch)
|
keys=all(self._anch_keys)
|
||||||
|
return function()
|
||||||
|
local k=keys()
|
||||||
|
if (k==nil) return nil
|
||||||
|
return self._anch[k.key]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function level:get_open_pit(mx,my)
|
function level:get_open_pit(mx,my)
|
||||||
@ -499,6 +542,9 @@ end
|
|||||||
function level:mcoll(mx,my)
|
function level:mcoll(mx,my)
|
||||||
return self._coll[_mix(mx,my)]!=false
|
return self._coll[_mix(mx,my)]!=false
|
||||||
end
|
end
|
||||||
|
function level:mcoll_nocrate(mx,my)
|
||||||
|
return self._coll_nocrate[_mix(mx,my)]!=false
|
||||||
|
end
|
||||||
|
|
||||||
function level:pcoll(px,py)
|
function level:pcoll(px,py)
|
||||||
return self:mcoll(px\8,py\8)
|
return self:mcoll(px\8,py\8)
|
||||||
@ -574,6 +620,8 @@ function level:get_latch(dx,dy,px,py)
|
|||||||
return {
|
return {
|
||||||
el="eyehook",
|
el="eyehook",
|
||||||
dx=dx1,dy=dy1,
|
dx=dx1,dy=dy1,
|
||||||
|
ax_offset=dx1*0.5,
|
||||||
|
ay_offset=dy1*0.5,
|
||||||
mx=mx,my=my
|
mx=mx,my=my
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -597,16 +645,15 @@ function level:can_move(
|
|||||||
|
|
||||||
-- todo: check tongue collision
|
-- todo: check tongue collision
|
||||||
if player.rope then
|
if player.rope then
|
||||||
local px,py=mx0*8,my0*8
|
|
||||||
local chk=false
|
local chk=false
|
||||||
if dmx==0 and dmy==-1 then
|
if dmx==0 and dmy==-1 then
|
||||||
chk=player.rope:collide_rect(px+3,py-5,px+4,py+5,exclude_src,exclude_dst)
|
chk=player.rope:collide_mrect(mx0,my0-1,1,2,exclude_src,exclude_dst)
|
||||||
elseif dmx==0 and dmy==1 then
|
elseif dmx==0 and dmy==1 then
|
||||||
chk=player.rope:collide_rect(px+3,py+3,px+4,py+13,exclude_src,exclude_dst)
|
chk=player.rope:collide_mrect(mx0,my0,1,2,exclude_src,exclude_dst)
|
||||||
elseif dmx==-1 and dmy==0 then
|
elseif dmx==-1 and dmy==0 then
|
||||||
chk=player.rope:collide_rect(px-5,py+3,px+5,py+4,exclude_src,exclude_dst)
|
chk=player.rope:collide_mrect(mx0-1,my0,2,1,exclude_src,exclude_dst)
|
||||||
elseif dmx==1 and dmy==0 then
|
elseif dmx==1 and dmy==0 then
|
||||||
chk=player.rope:collide_rect(px+3,py+3,px+13,py+4,exclude_src,exclude_dst)
|
chk=player.rope:collide_mrect(mx0,my0,2,1,exclude_src,exclude_dst)
|
||||||
end
|
end
|
||||||
|
|
||||||
if (chk) return false
|
if (chk) return false
|
||||||
@ -639,74 +686,6 @@ function level:tug_crate(mx0,my0,dmx,dmy)
|
|||||||
self:recollide()
|
self:recollide()
|
||||||
self:reanchor(false)
|
self:reanchor(false)
|
||||||
end
|
end
|
||||||
-->8
|
|
||||||
-- collision checks
|
|
||||||
function level:can_stretch(
|
|
||||||
p1,p2
|
|
||||||
)
|
|
||||||
local key=p1.x..","..p1.y..","..p2.x..","..p2.y
|
|
||||||
return self.cache_can_stretch:wrap(key,function()
|
|
||||||
return self:_can_stretch(p1,p2)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
function level:_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 _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
|
|
||||||
|
|
||||||
-->8
|
|
||||||
--cache impl for collision checks
|
|
||||||
dcache={}
|
|
||||||
dcache.__index=dcache
|
|
||||||
|
|
||||||
function dcache:new()
|
|
||||||
local d={}
|
|
||||||
setmetatable(d,dcache)
|
|
||||||
d:clear()
|
|
||||||
return d
|
|
||||||
end
|
|
||||||
function dcache:clear()
|
|
||||||
self.old,self.new,self.new_n={},{},0
|
|
||||||
end
|
|
||||||
|
|
||||||
function dcache:wrap(key,f)
|
|
||||||
local el=self.new[key]
|
|
||||||
if (el!=nil) return el
|
|
||||||
local el=self.old[key]
|
|
||||||
if (el==nil) el=f()
|
|
||||||
self.new[key]=el
|
|
||||||
self.new_n+=1
|
|
||||||
if (self.new_n>1000) self.old,self.new,self.new_n=self.new,{},0
|
|
||||||
return el
|
|
||||||
end
|
|
||||||
|
|
||||||
-->8
|
-->8
|
||||||
--player handling
|
--player handling
|
||||||
@ -815,7 +794,7 @@ function player:update()
|
|||||||
|
|
||||||
self.rope=rope:new(
|
self.rope=rope:new(
|
||||||
x+0.5-dx*0.5,y+0.5-dy*0.5,
|
x+0.5-dx*0.5,y+0.5-dy*0.5,
|
||||||
self.x+0.5,self.y+0.5,
|
self.x+0.5,self.y+0.1,
|
||||||
level:get_latch(dx,dy,x*8,y*8)
|
level:get_latch(dx,dy,x*8,y*8)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -836,7 +815,7 @@ function player:update()
|
|||||||
|
|
||||||
if self.rope then
|
if self.rope then
|
||||||
self.rope:update()
|
self.rope:update()
|
||||||
self.rope:drag_dst(self.x+0.5,self.y+0.5)
|
self.rope:drag_dst(self.x+0.5,self.y+0.1)
|
||||||
|
|
||||||
local tdx,tdy=self.rope:tug_orientxy()
|
local tdx,tdy=self.rope:tug_orientxy()
|
||||||
if (tdx!=0) self.orientx=tdx
|
if (tdx!=0) self.orientx=tdx
|
||||||
@ -853,6 +832,7 @@ function player:_vanish_if_requested()
|
|||||||
self.vanish_frame+=1
|
self.vanish_frame+=1
|
||||||
|
|
||||||
if (self.fall_frame>0 or self.vanish_frame>20) then
|
if (self.fall_frame>0 or self.vanish_frame>20) then
|
||||||
|
self.rope=nil
|
||||||
level:restart()
|
level:restart()
|
||||||
kbd:release(5)
|
kbd:release(5)
|
||||||
self.vanish_frame=20
|
self.vanish_frame=20
|
||||||
@ -975,8 +955,8 @@ function rope:update()
|
|||||||
self.latch.rec!=nil
|
self.latch.rec!=nil
|
||||||
then
|
then
|
||||||
self:drag_src(
|
self:drag_src(
|
||||||
self.latch.rec.mx+0.5+self.latch.ax_offset,
|
self.latch.rec.px/8+0.5+self.latch.ax_offset,
|
||||||
self.latch.rec.my+0.5+self.latch.ay_offset
|
self.latch.rec.py/8+0.5+self.latch.ay_offset
|
||||||
)
|
)
|
||||||
|
|
||||||
if #self.latch.rec.todo==0 then
|
if #self.latch.rec.todo==0 then
|
||||||
@ -986,6 +966,8 @@ function rope:update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if (not self:_check_sane()) self:destroy()
|
||||||
|
|
||||||
elseif self.state.name=="destroy" then -- destroy
|
elseif self.state.name=="destroy" then -- destroy
|
||||||
self.state.frame+=1
|
self.state.frame+=1
|
||||||
if (self.state.frame>=5) self.state={name="done"}
|
if (self.state.frame>=5) self.state={name="done"}
|
||||||
@ -1057,13 +1039,14 @@ function rope:draw(artificial_dx,artificial_dy)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
local n1=self.src
|
local n1=self.src
|
||||||
|
--[[
|
||||||
local sy=0
|
local sy=0
|
||||||
while true do
|
while true do
|
||||||
if (n1==nil) break
|
if (n1==nil) break
|
||||||
local x=n1.ax*8
|
local x=n1.ax*8
|
||||||
local y=n1.ay*8
|
local y=n1.ay*8
|
||||||
rectfill(x-1,y-1,x+1,y+1,12)
|
rectfill(x-1,y-1,x+1,y+1,12)
|
||||||
--print("ax="..n1.ax..",ay="..n1.ay,0,sy)
|
print("ax="..n1.ax..",ay="..n1.ay,0,sy)
|
||||||
sy+=7
|
sy+=7
|
||||||
|
|
||||||
local n0=n1.prev
|
local n0=n1.prev
|
||||||
@ -1075,7 +1058,9 @@ function rope:draw(artificial_dx,artificial_dy)
|
|||||||
assert(ady==-1 or ady==0 or ady==1)
|
assert(ady==-1 or ady==0 or ady==1)
|
||||||
--assert(not (adx==0 and ady==0))
|
--assert(not (adx==0 and ady==0))
|
||||||
|
|
||||||
rectfill(x+2,y+2,x+4,y+4,3)
|
local c=3
|
||||||
|
if (n1.associated_with.dropped) c=8
|
||||||
|
rectfill(x+2,y+2,x+4,y+4,c)
|
||||||
pset(x+adx*2,y,9)
|
pset(x+adx*2,y,9)
|
||||||
pset(x,y+ady*2,9)
|
pset(x,y+ady*2,9)
|
||||||
else
|
else
|
||||||
@ -1093,17 +1078,6 @@ function rope:draw(artificial_dx,artificial_dy)
|
|||||||
pset(p.ax*8+p.adx,p.ay*8,11)
|
pset(p.ax*8+p.adx,p.ay*8,11)
|
||||||
pset(p.ax*8,p.ay*8+p.ady,11)
|
pset(p.ax*8,p.ay*8+p.ady,11)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
|
||||||
print("dirty:"..tostr(self.dirty),32,0,9)
|
|
||||||
print("busy:"..tostr(self:busy()),32,7,9)
|
|
||||||
print("state:"..tostr(self.state.name),32,14,9)
|
|
||||||
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
|
end
|
||||||
|
|
||||||
@ -1116,13 +1090,25 @@ function rope:drag_src(x,y)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function rope:drag(n1,ax_new,ay_new)
|
function rope:drag(n1,ax_new,ay_new)
|
||||||
-- TODO: stepwise?
|
self:relax()
|
||||||
self:_relax()
|
self:_drag(n1,ax_new,n1.ay)
|
||||||
self:_drag(n1,ax_new,ay_new)
|
self:_drag(n1,ax_new,ay_new)
|
||||||
self:_relax()
|
self:relax()
|
||||||
|
end
|
||||||
|
|
||||||
|
function rope:relax()
|
||||||
|
local n=self.src
|
||||||
|
|
||||||
|
while true do
|
||||||
|
if (n==nil) break
|
||||||
|
|
||||||
|
if (n.associated_with) then
|
||||||
|
self:_drag(n,n.associated_with.ax,n.associated_with.ay)
|
||||||
|
end
|
||||||
|
|
||||||
|
n=n.next
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:_relax()
|
|
||||||
local n0=self.src
|
local n0=self.src
|
||||||
while true do
|
while true do
|
||||||
if (n0==nil) return
|
if (n0==nil) return
|
||||||
@ -1132,12 +1118,14 @@ function rope:_relax()
|
|||||||
if (n2==nil) return
|
if (n2==nil) return
|
||||||
|
|
||||||
if n1.associated_with!=nil then
|
if n1.associated_with!=nil then
|
||||||
|
|
||||||
local x0,y0=n0.ax,n0.ay
|
local x0,y0=n0.ax,n0.ay
|
||||||
local x1,y1=n1.ax,n1.ay
|
local x1,y1=n1.ax,n1.ay
|
||||||
local x2,y2=n2.ax,n2.ay
|
local x2,y2=n2.ax,n2.ay
|
||||||
|
|
||||||
local would,x1_new,y1_new=would_stick(x0,y0,n1.associated_with,x2,y2)
|
local would,x1_new,y1_new=would_stick(x0,y0,n1.associated_with,x2,y2)
|
||||||
if not would then
|
if not would and not (n1.ax==x1_new and n1.ay==y1_new) then
|
||||||
|
printh("relaxing: "..tostring(n0.associated_with).."->"..tostring(n1.associated_with).."->"..tostring(n2.associated_with))
|
||||||
self:_drag(n1,x1_new,y1_new)
|
self:_drag(n1,x1_new,y1_new)
|
||||||
n0=n1.prev
|
n0=n1.prev
|
||||||
n2=n1.next
|
n2=n1.next
|
||||||
@ -1145,11 +1133,56 @@ function rope:_relax()
|
|||||||
n2.prev=n0
|
n2.prev=n0
|
||||||
n1.next=nil
|
n1.next=nil
|
||||||
n1.prev=nil
|
n1.prev=nil
|
||||||
|
--n0=n0.next
|
||||||
else n0=n0.next end
|
else n0=n0.next end
|
||||||
else n0=n0.next end
|
else n0=n0.next end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function rope:_check_sane()
|
||||||
|
if (self.state.name!="latched") return true
|
||||||
|
if (level:busy()) return true
|
||||||
|
|
||||||
|
printh("start")
|
||||||
|
local n0=self.src
|
||||||
|
|
||||||
|
local qxs,qys={},{}
|
||||||
|
while true do
|
||||||
|
local n1=n0.next
|
||||||
|
if (n1==nil) break
|
||||||
|
|
||||||
|
for qx,qy in _rast(flr(n0.ax*2),flr(n0.ay*2),flr(n1.ax*2),flr(n1.ay*2)) do
|
||||||
|
add(qxs,qx)
|
||||||
|
add(qys,qy)
|
||||||
|
end
|
||||||
|
n0=n1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function _blocked(qx,qy)
|
||||||
|
local mx0=(qx-1)\2
|
||||||
|
local mx1=qx\2
|
||||||
|
local my0=(qy-1)\2
|
||||||
|
local my1=qy\2
|
||||||
|
|
||||||
|
return level:mcoll(mx0,my0) and level:mcoll(mx1,my1)
|
||||||
|
end
|
||||||
|
for i=1,#qxs do
|
||||||
|
if (_blocked(qxs[i],qys[i])) printh("blocked"..qxs[i]..","..qys[i]) return false
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=3,#qxs do
|
||||||
|
local qx1,qy1=qxs[i-1],qys[i-1]
|
||||||
|
if qx1%2==0 and qy1%2==0 then
|
||||||
|
local qx0,qy0=qxs[i-2],qys[i-2]
|
||||||
|
local qx2,qy2=qxs[i],qys[i]
|
||||||
|
local mx0,my0=qx0\2,qy0\2
|
||||||
|
local mx2,my2=qx2\2,qy2\2
|
||||||
|
if (level:mcoll(mx0,my2) and level:mcoll(mx2,my0)) printh("not traversable") return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
function would_stick(x0,y0,anchor,x2,y2)
|
function would_stick(x0,y0,anchor,x2,y2)
|
||||||
local x1,y1=anchor.ax,anchor.ay
|
local x1,y1=anchor.ax,anchor.ay
|
||||||
if (x0>x2) x0,y0,x2,y2=x2,y2,x0,y0
|
if (x0>x2) x0,y0,x2,y2=x2,y2,x0,y0
|
||||||
@ -1175,7 +1208,9 @@ function would_stick(x0,y0,anchor,x2,y2)
|
|||||||
if (y0<y2) ady=-adx
|
if (y0<y2) ady=-adx
|
||||||
end
|
end
|
||||||
|
|
||||||
return anchor.adx!=-adx and anchor.ady!=-ady,x1_new,y1_new,adx,ady
|
local wouldnt=anchor.dropped or (anchor.adx==-adx or anchor.ady==-ady)
|
||||||
|
|
||||||
|
return not wouldnt,x1_new,y1_new,adx,ady
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: Upon adding a point, start from there to see if we need another
|
-- TODO: Upon adding a point, start from there to see if we need another
|
||||||
@ -1193,10 +1228,11 @@ function rope:_drag(n1,ax1_new,ay1_new)
|
|||||||
|
|
||||||
ay_far_old=ay_far0
|
ay_far_old=ay_far0
|
||||||
for ay_far_new in _stepfrom(ay_far0,ay_far1) do
|
for ay_far_new in _stepfrom(ay_far0,ay_far1) do
|
||||||
for _,anchor in level:anchor_points() do
|
for anchor in level:anchor_points() do
|
||||||
if
|
if
|
||||||
not (anchor.ax==ax_pivot and anchor.ay==ay_pivot) and
|
not (anchor.ax==ax_pivot and anchor.ay==ay_pivot) and
|
||||||
not (anchor.ax==ax_new and anchor.ay==ay_new) and
|
not (anchor.ax==ax_far0 and anchor.ay==ay_far0) and
|
||||||
|
not (anchor.ax==ax_far1 and anchor.ay==ay_far1) and
|
||||||
(ax0<=anchor.ax and anchor.ax<=ax1) and
|
(ax0<=anchor.ax and anchor.ax<=ax1) and
|
||||||
would_stick(ax_pivot,ay_pivot,anchor,ax_far,ay_far_new) and
|
would_stick(ax_pivot,ay_pivot,anchor,ax_far,ay_far_new) and
|
||||||
crossed(
|
crossed(
|
||||||
@ -1215,10 +1251,11 @@ function rope:_drag(n1,ax1_new,ay1_new)
|
|||||||
|
|
||||||
ax_far_old=ax_far0
|
ax_far_old=ax_far0
|
||||||
for ax_far_new in _stepfrom(ax_far0,ax_far1) do
|
for ax_far_new in _stepfrom(ax_far0,ax_far1) do
|
||||||
for _,anchor in level:anchor_points() do
|
for anchor in level:anchor_points() do
|
||||||
if
|
if
|
||||||
not (anchor.ax==ax_pivot and anchor.ay==ay_pivot) and
|
not (anchor.ax==ax_pivot and anchor.ay==ay_pivot) and
|
||||||
not (anchor.ax==ax_new and anchor.ay==ay_new) and
|
not (anchor.ax==ax_far0 and anchor.ay==ay_far0) and
|
||||||
|
not (anchor.ax==ax_far1 and anchor.ay==ay_far1) and
|
||||||
would_stick(ax_pivot,ay_pivot,anchor,ax_far_new,ay_far) and
|
would_stick(ax_pivot,ay_pivot,anchor,ax_far_new,ay_far) and
|
||||||
(ay0<=anchor.ay and anchor.ay<=ay1) and
|
(ay0<=anchor.ay and anchor.ay<=ay1) and
|
||||||
crossed(
|
crossed(
|
||||||
@ -1245,9 +1282,8 @@ function rope:_drag(n1,ax1_new,ay1_new)
|
|||||||
if (n0==nil) break
|
if (n0==nil) break
|
||||||
local anch=_sweep_radar(n0.ax,n0.ay,ax1_old,ay1_old,ax1_new,ay1_new)
|
local anch=_sweep_radar(n0.ax,n0.ay,ax1_old,ay1_old,ax1_new,ay1_new)
|
||||||
if (anch==nil) break
|
if (anch==nil) break
|
||||||
if (anch.ax==n0.ax and anch.y==n0.ay) break
|
|
||||||
if (anch.ax==n1.ax and anch.y==n1.ay) break
|
|
||||||
local n05={ax=anch.ax,ay=anch.ay,associated_with=anch,prev=n0,next=n1}
|
local n05={ax=anch.ax,ay=anch.ay,associated_with=anch,prev=n0,next=n1}
|
||||||
|
printh("creating post: "..tostring(n0.associated_with).."->"..tostring(n05.associated_with).."->"..tostring(n1.associated_with))
|
||||||
n0.next=n05
|
n0.next=n05
|
||||||
n1.prev=n05
|
n1.prev=n05
|
||||||
n0=n05
|
n0=n05
|
||||||
@ -1258,9 +1294,8 @@ function rope:_drag(n1,ax1_new,ay1_new)
|
|||||||
if (n2==nil) break
|
if (n2==nil) break
|
||||||
local anch=_sweep_radar(n2.ax,n2.ay,ax1_old,ay1_old,ax1_new,ay1_new)
|
local anch=_sweep_radar(n2.ax,n2.ay,ax1_old,ay1_old,ax1_new,ay1_new)
|
||||||
if (anch==nil) break
|
if (anch==nil) break
|
||||||
if (anch.ax==n1.ax and anch.y==n1.ay) break
|
|
||||||
if (anch.ax==n2.ax and anch.y==n2.ay) break
|
|
||||||
local n15={ax=anch.ax,ay=anch.ay,associated_with=anch,prev=n1,next=n2}
|
local n15={ax=anch.ax,ay=anch.ay,associated_with=anch,prev=n1,next=n2}
|
||||||
|
printh("creating post: "..tostring(n1.associated_with).."->"..tostring(n15.associated_with).."->"..tostring(n2.associated_with))
|
||||||
n1.next=n15
|
n1.next=n15
|
||||||
n2.prev=n15
|
n2.prev=n15
|
||||||
n2=n15
|
n2=n15
|
||||||
@ -1276,7 +1311,9 @@ function _stepfrom(x0,x1)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local mul=1
|
local mul=0.5
|
||||||
|
x0*=2
|
||||||
|
x1*=2
|
||||||
if (x0>x1) x0,x1,mul=-x0,-x1,-mul
|
if (x0>x1) x0,x1,mul=-x0,-x1,-mul
|
||||||
local i=flr(x0)
|
local i=flr(x0)
|
||||||
local top=flr(x1)
|
local top=flr(x1)
|
||||||
@ -1320,18 +1357,33 @@ function distance(p1,p2)
|
|||||||
return sqrt(dx*dx+dy*dy)
|
return sqrt(dx*dx+dy*dy)
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:collide_rect(x1,y1,x2,y2,exclude_src,exclude_dst)
|
function rope:collide_mrect(mx0,my0,mw,mh,exclude_src,exclude_dst)
|
||||||
local a0=self.src
|
local mx1,my1=mx0+mw,my0+mh
|
||||||
|
local n0=self.src
|
||||||
|
|
||||||
|
mx0+=0.1
|
||||||
|
my0+=0.1
|
||||||
|
mx1-=0.1
|
||||||
|
my1-=0.1
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local a1=a0.next
|
local n1=n0.next
|
||||||
if (a1==nil) return false
|
if (n1==nil) return false
|
||||||
--[[
|
|
||||||
if (_line_line(a0.x,a0.y,a1.x,a1.y,x1,y1,x2,y1)) return true
|
local nd=n0
|
||||||
if (_line_line(a0.x,a0.y,a1.x,a1.y,x1,y1,x1,y2)) return true
|
for i=1,exclude_dst do
|
||||||
if (_line_line(a0.x,a0.y,a1.x,a1.y,x1,y2,x2,y2)) return true
|
nd=nd.next
|
||||||
if (_line_line(a0.x,a0.y,a1.x,a1.y,x2,y1,x2,y2)) return true
|
if (nd==nil) return false
|
||||||
]]--
|
end
|
||||||
a0=a0.next
|
|
||||||
|
if exclude_src<=0 then
|
||||||
|
if (_line_line(n0.ax,n0.ay,n1.ax,n1.ay,mx0,my0,mx1,my0)) return true
|
||||||
|
if (_line_line(n0.ax,n0.ay,n1.ax,n1.ay,mx0,my0,mx0,my1)) return true
|
||||||
|
if (_line_line(n0.ax,n0.ay,n1.ax,n1.ay,mx0,my1,mx1,my1)) return true
|
||||||
|
if (_line_line(n0.ax,n0.ay,n1.ax,n1.ay,mx1,my0,mx1,my1)) return true
|
||||||
|
end
|
||||||
|
exclude_src-=1
|
||||||
|
n0=n1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1391,12 +1443,12 @@ function rope:_tug(hypothetically)
|
|||||||
local touched={}
|
local touched={}
|
||||||
|
|
||||||
for i=#ancs-1,2,-1 do
|
for i=#ancs-1,2,-1 do
|
||||||
local ops_before_trash,hit_end1=self:_calc_push(ancs[i+1],ancs[i],ancs[i-1],ancs[i-2])
|
local ops_before_trash=self:_calc_push(ancs[i+1],ancs[i],ancs[i-1],ancs[i-2])
|
||||||
local ops_to_do,corners={}
|
local ops_to_do,corners={}
|
||||||
if #ops_before_trash>0 then
|
if #ops_before_trash>0 then
|
||||||
ops_to_do=ops_before_trash
|
ops_to_do=ops_before_trash
|
||||||
else
|
else
|
||||||
local ops_after_trash,hit_end2=self:_calc_push(ancs[i-2],ancs[i-1],ancs[i],ancs[i+1])
|
local ops_after_trash=self:_calc_push(ancs[i-2],ancs[i-1],ancs[i],ancs[i+1])
|
||||||
ops_to_do=ops_after_trash
|
ops_to_do=ops_after_trash
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1406,39 +1458,9 @@ function rope:_tug(hypothetically)
|
|||||||
if (hypothetically) return ancs,i-1
|
if (hypothetically) return ancs,i-1
|
||||||
|
|
||||||
local dmx,dmy=ops[1].dmx,ops[1].dmy
|
local dmx,dmy=ops[1].dmx,ops[1].dmy
|
||||||
local adjacent_ancs={}
|
|
||||||
for o in all(ops) do
|
for o in all(ops) do
|
||||||
add_adjacent_anchors(adjacent_ancs,o.mx,o.my)
|
|
||||||
level:tug_crate(o.mx,o.my,o.dmx,o.dmy)
|
level:tug_crate(o.mx,o.my,o.dmx,o.dmy)
|
||||||
end
|
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
|
|
||||||
end
|
|
||||||
s.dirty=true
|
|
||||||
self.dirty=true
|
|
||||||
return true
|
|
||||||
end}
|
|
||||||
end
|
|
||||||
local dmxh,dmyh=dmx,dmy
|
|
||||||
local ax,ay=level:p2a(x0,y0)
|
|
||||||
if (adjacent_ancs[_amix(ax,ay)]==nil) dmxh,dmyh=0,0
|
|
||||||
anc.todo={
|
|
||||||
{},
|
|
||||||
upd(x0+dmxh*2,y0+dmyh*2),
|
|
||||||
upd(x0+dmxh*7,y0+dmyh*7),
|
|
||||||
upd(x0+dmxh*8,y0+dmyh*8),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
for node=ancs[i-1].ix-1,ancs[i].ix+1 do
|
|
||||||
local anc=self:_anc(node)
|
|
||||||
end
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1548,7 +1570,6 @@ function rope:_calc_push(
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local hit_end=true
|
|
||||||
local ops2={}
|
local ops2={}
|
||||||
for o in all(ops) do
|
for o in all(ops) do
|
||||||
if not level:mcoll(o.mx,o.my) then
|
if not level:mcoll(o.mx,o.my) then
|
||||||
@ -1556,18 +1577,16 @@ function rope:_calc_push(
|
|||||||
else
|
else
|
||||||
local crate=level:get_crate(o.mx,o.my)
|
local crate=level:get_crate(o.mx,o.my)
|
||||||
if crate==nil then
|
if crate==nil then
|
||||||
hit_end=false
|
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
if not level:can_move(false,o.mx,o.my,o.dmx,o.dmy,0,0) then
|
if not level:can_move(false,o.mx,o.my,o.dmx,o.dmy,0,0) then
|
||||||
hit_end=false
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
add(ops2,o)
|
add(ops2,o)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return ops2,hit_end
|
return ops2
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:_anchors_simplified()
|
function rope:_anchors_simplified()
|
||||||
@ -1578,7 +1597,18 @@ function rope:_anchors_simplified()
|
|||||||
end
|
end
|
||||||
a=self.src
|
a=self.src
|
||||||
while a!=nil do
|
while a!=nil do
|
||||||
local point={x=a.ax*8,y=a.ay*8,ax=a.ax,ay=a.ay}
|
local point={
|
||||||
|
x=flr(a.ax*8+0.5),y=flr(a.ay*8+0.5),
|
||||||
|
ax=a.ax,ay=a.ay
|
||||||
|
}
|
||||||
|
if a.associated_with then
|
||||||
|
if (a.associated_with.adx==1) point.x-=1
|
||||||
|
if (a.associated_with.ady==1) point.y-=1
|
||||||
|
elseif a.prev==nil and self.latch then
|
||||||
|
if (self.latch.ax_offset<0) point.x-=1
|
||||||
|
if (self.latch.ay_offset<0) point.y-=1
|
||||||
|
end
|
||||||
|
|
||||||
if #points<=1 then
|
if #points<=1 then
|
||||||
add(points,point)
|
add(points,point)
|
||||||
elseif abs(
|
elseif abs(
|
||||||
@ -1590,7 +1620,6 @@ function rope:_anchors_simplified()
|
|||||||
add(points,point)
|
add(points,point)
|
||||||
end
|
end
|
||||||
a=a.next
|
a=a.next
|
||||||
assert(#points<100)
|
|
||||||
end
|
end
|
||||||
return points
|
return points
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user