Rewrite rope #11
498
chameleonic.p8
498
chameleonic.p8
@ -415,35 +415,27 @@ function add_adjacent_anchors(tbl,mx,my)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function level:reanchor(remove)
|
function level:reanchor()
|
||||||
if remove or not self._anch then
|
self._anch={}
|
||||||
self._anch={}
|
for dxy in all{{-1,-1},{1,-1},{-1,1},{1,1}} do
|
||||||
end
|
local dx,dy=unpack(dxy)
|
||||||
|
assert(dx!=0 and dy!=0)
|
||||||
for ax0=0,31 do
|
for mx0=0,15 do
|
||||||
local ax1 = ax0-1+2*(ax0%2)
|
for my0=0,15 do
|
||||||
local mx0,mx1 = ax0\2,ax1\2
|
local mx1,my1=mx0+dx,my0+dy
|
||||||
for ay0=0,31 do
|
if (
|
||||||
local ay1=ay0-1+2*(ay0%2)
|
self:mcoll(mx0,my0) and
|
||||||
local my0,my1=ay0\2,ay1\2
|
not self:mcoll(mx0,my1) and
|
||||||
|
not self:mcoll(mx1,my0) and
|
||||||
if (
|
not self:mcoll(mx1,my1)
|
||||||
not self:mcoll(mx0,my0) and
|
) then
|
||||||
not self:mcoll(mx0,my1) and
|
add(self._anch, {
|
||||||
not self:mcoll(mx1,my0) and
|
ax=max(mx0,mx1),ay=max(my0,my1),adx=-dx,ady=-dy
|
||||||
self:mcoll(mx1,my1)
|
})
|
||||||
) then
|
end
|
||||||
local px0,py0=level:a2p(ax0,ay0)
|
|
||||||
self._anch[_amix(ax0,ay0)]={ax=ax0,ay=ay0,x=px0,y=py0}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _,cr in pairs(self._crates) do
|
|
||||||
add_adjacent_anchors(self._anch,cr.mx,cr.my)
|
|
||||||
end
|
|
||||||
|
|
||||||
if (player.rope!=nil) player.rope:make_dirty()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function level:win_at(mx,my)
|
function level:win_at(mx,my)
|
||||||
@ -453,20 +445,6 @@ function level:anchor_points()
|
|||||||
return pairs(self._anch)
|
return pairs(self._anch)
|
||||||
end
|
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
|
|
||||||
|
|
||||||
function level:get_open_pit(mx,my)
|
function level:get_open_pit(mx,my)
|
||||||
local pit=self._pits[_mix(mx,my)]
|
local pit=self._pits[_mix(mx,my)]
|
||||||
if (pit and pit.contents==nil) return pit
|
if (pit and pit.contents==nil) return pit
|
||||||
@ -574,8 +552,8 @@ function level:get_latch(dx,dy,px,py)
|
|||||||
return {
|
return {
|
||||||
el="crate",
|
el="crate",
|
||||||
dx=dx1,dy=dy1,
|
dx=dx1,dy=dy1,
|
||||||
px_offset=px-crate.px+dx1,
|
ax_offset=dx1*0.5,
|
||||||
py_offset=py-crate.py+dy1,
|
ay_offset=dy1*0.5,
|
||||||
rec=crate
|
rec=crate
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -758,7 +736,6 @@ end
|
|||||||
function player:any_busy()
|
function player:any_busy()
|
||||||
if (#self.todo>0) return true
|
if (#self.todo>0) return true
|
||||||
if (level:busy()) return true
|
if (level:busy()) return true
|
||||||
if (self.rope!=nil and self.rope:busy()) return true
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -826,10 +803,17 @@ function player:update()
|
|||||||
self.todo=f4({{orienty=1,py=2},{py=7},{y=self.y+1}})
|
self.todo=f4({{orienty=1,py=2},{py=7},{y=self.y+1}})
|
||||||
else wrongbleep:bleep() end
|
else wrongbleep:bleep() end
|
||||||
elseif self.rope==nil and kbd:btnr(4) then
|
elseif self.rope==nil and kbd:btnr(4) then
|
||||||
local rx,ry,rx2,ry2=self:_rope_pos()
|
local dx,dy=self.orientx,self.orienty
|
||||||
local dx,dy=12*self.orientx,12*self.orienty
|
|
||||||
if (dy!=0) dx=0
|
if (dy!=0) dx=0
|
||||||
self.rope=rope:new(rx,ry,rx2,ry2,dx,dy)
|
|
||||||
|
local x,y=self.x,self.y
|
||||||
|
while not level:mcoll(x,y) do x+=dx y+=dy end
|
||||||
|
|
||||||
|
self.rope=rope:new(
|
||||||
|
x+0.5-dx*0.5,y+0.5-dy*0.5,
|
||||||
|
self.x+0.5,self.y+0.5,
|
||||||
|
level:get_latch(dx,dy,x*8,y*8)
|
||||||
|
)
|
||||||
|
|
||||||
self.todo={{
|
self.todo={{
|
||||||
update=function()
|
update=function()
|
||||||
@ -848,8 +832,7 @@ function player:update()
|
|||||||
|
|
||||||
if self.rope then
|
if self.rope then
|
||||||
self.rope:update()
|
self.rope:update()
|
||||||
local rx,ry=self:_rope_pos()
|
self.rope:drag_dst(self.x+0.5,self.y+0.5)
|
||||||
self.rope:drag_dst(rx,ry)
|
|
||||||
|
|
||||||
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
|
||||||
@ -881,14 +864,6 @@ function player:_fall()
|
|||||||
if (self.fall_frame<10) self.fall_frame+=1
|
if (self.fall_frame<10) self.fall_frame+=1
|
||||||
end
|
end
|
||||||
|
|
||||||
function player:_rope_pos()
|
|
||||||
local px=self.x*8+self.px+4
|
|
||||||
local px2=px
|
|
||||||
local py=self.y*8+self.py+3
|
|
||||||
local py2=py
|
|
||||||
return px,py,px2,py2
|
|
||||||
end
|
|
||||||
|
|
||||||
function player:draw()
|
function player:draw()
|
||||||
local px=self.x*8+self.px
|
local px=self.x*8+self.px
|
||||||
local py=self.y*8+self.py
|
local py=self.y*8+self.py
|
||||||
@ -956,18 +931,21 @@ rope={}
|
|||||||
rope.__index=rope
|
rope.__index=rope
|
||||||
|
|
||||||
function rope:new(
|
function rope:new(
|
||||||
x,y,src_x,src_y,dx,dy
|
src_ax,src_ay,dst_ax,dst_ay,latch
|
||||||
)
|
)
|
||||||
local r={
|
local r={
|
||||||
id=0,
|
id=0,
|
||||||
src={x=src_x,y=src_y,todo={}},
|
anchors={
|
||||||
ancs={},
|
{ax=src_ax,ay=src_ay,prev=nil,next=nil},
|
||||||
dst={x=x,y=y,todo={}},
|
{ax=dst_ax,ay=dst_ay,prev=nil,next=nil}
|
||||||
state={name="cast",dx=dx,dy=dy},
|
},
|
||||||
dirty=true,
|
state={name="cast",frame=0},
|
||||||
latch=nil,
|
latch=latch,
|
||||||
latch_frame=0,
|
|
||||||
}
|
}
|
||||||
|
r.src=r.anchors[1]
|
||||||
|
r.dst=r.anchors[2]
|
||||||
|
r.src.next=r.dst
|
||||||
|
r.dst.prev=r.src
|
||||||
setmetatable(r,rope)
|
setmetatable(r,rope)
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
@ -980,30 +958,12 @@ function rope:done()
|
|||||||
return self.state.name=="done"
|
return self.state.name=="done"
|
||||||
end
|
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()
|
function rope:update()
|
||||||
local was_busy=self:busy()
|
|
||||||
for i=0,#self.ancs+1 do
|
|
||||||
local anc=self:_anc(i)
|
|
||||||
_apply(anc,anc.todo,i)
|
|
||||||
end
|
|
||||||
local is_busy=self:busy()
|
|
||||||
if (was_busy and not is_busy) self.dirty=true
|
|
||||||
|
|
||||||
if self.state.name=="cast" then
|
if self.state.name=="cast" then
|
||||||
self:continue_cast()
|
self.state.frame+=1
|
||||||
elseif self.state.name=="latched" then
|
if (self.state.frame>=3) self.state={name="latched"}
|
||||||
self.latch_frame+=1
|
|
||||||
if self.latch_frame>=10 then
|
|
||||||
self.latch_frame=10
|
|
||||||
end
|
|
||||||
|
|
||||||
|
elseif self.state.name=="latched" then
|
||||||
if (self.latch==nil) wrongbleep:bleep(3) self:destroy() return
|
if (self.latch==nil) wrongbleep:bleep(3) self:destroy() return
|
||||||
|
|
||||||
if
|
if
|
||||||
@ -1011,8 +971,8 @@ function rope:update()
|
|||||||
self.latch.rec!=nil
|
self.latch.rec!=nil
|
||||||
then
|
then
|
||||||
self:drag_src(
|
self:drag_src(
|
||||||
self.latch.rec.px+self.latch.px_offset,
|
self.latch.rec.mx+0.5+self.latch.ax_offset,
|
||||||
self.latch.rec.py+self.latch.py_offset
|
self.latch.rec.my+0.5+self.latch.ay_offset
|
||||||
)
|
)
|
||||||
|
|
||||||
if #self.latch.rec.todo==0 then
|
if #self.latch.rec.todo==0 then
|
||||||
@ -1022,7 +982,6 @@ function rope:update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (not is_busy) self:_tidy_up_gen()
|
|
||||||
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"}
|
||||||
@ -1036,41 +995,11 @@ function rope:destroy()
|
|||||||
self.state={name="destroy",frame=0}
|
self.state={name="destroy",frame=0}
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:continue_cast()
|
|
||||||
local dx,dy=self.state.dx,self.state.dy
|
|
||||||
local x0=self.src.x
|
|
||||||
local y0=self.src.y
|
|
||||||
local x1=x0+dx
|
|
||||||
local y1=y0+dy
|
|
||||||
|
|
||||||
for x,y in _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.state={name="latched"}
|
|
||||||
break
|
|
||||||
end
|
|
||||||
self.src={x=x,y=y,todo={},dirty=true}
|
|
||||||
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(artificial_dx,artificial_dy)
|
function rope:draw(artificial_dx,artificial_dy)
|
||||||
local points,highlight=self:_tug(true)
|
local points,highlight=self:_tug(true)
|
||||||
if (self:busy()) highlight=nil
|
|
||||||
if (self.state.name=="done") return
|
if (self.state.name=="done") return
|
||||||
local perc_to_show=1.0
|
local perc_to_show=1.0
|
||||||
|
if (self.state.name=="cast") perc_to_show=self.state.frame/2
|
||||||
if (self.state.name=="destroy") perc_to_show=(1.0-self.state.frame/5)^2
|
if (self.state.name=="destroy") perc_to_show=(1.0-self.state.frame/5)^2
|
||||||
|
|
||||||
points[#points]={x=points[#points].x+artificial_dx,y=points[#points].y+artificial_dy}
|
points[#points]={x=points[#points].x+artificial_dx,y=points[#points].y+artificial_dy}
|
||||||
@ -1123,7 +1052,13 @@ function rope:draw(artificial_dx,artificial_dy)
|
|||||||
rectfill(x,y-1,x-1,y-3,color)
|
rectfill(x,y-1,x-1,y-3,color)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
for _,p in pairs(level._anch) do
|
||||||
|
pset(p.ax*8,p.ay*8,11)
|
||||||
|
pset(p.ax*8+p.adx,p.ay*8,11)
|
||||||
|
pset(p.ax*8,p.ay*8+p.ady,11)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
for i=0,#self.ancs+1 do
|
for i=0,#self.ancs+1 do
|
||||||
p=self:_anc(i)
|
p=self:_anc(i)
|
||||||
local c=12
|
local c=12
|
||||||
@ -1131,10 +1066,6 @@ function rope:draw(artificial_dx,artificial_dy)
|
|||||||
rectfill(p.x-1,p.y-1,p.x+1,p.y+1,c)
|
rectfill(p.x-1,p.y-1,p.x+1,p.y+1,c)
|
||||||
print(tostr(p.id)..":"..p.x..","..p.y..","..#p.todo,0,i*8,12)
|
print(tostr(p.id)..":"..p.x..","..p.y..","..#p.todo,0,i*8,12)
|
||||||
end
|
end
|
||||||
--[[
|
|
||||||
for _,p in pairs(level._anch) do
|
|
||||||
pset(p.x,p.y,11)
|
|
||||||
end
|
|
||||||
print("dirty:"..tostr(self.dirty),32,0,9)
|
print("dirty:"..tostr(self.dirty),32,0,9)
|
||||||
print("busy:"..tostr(self:busy()),32,7,9)
|
print("busy:"..tostr(self:busy()),32,7,9)
|
||||||
print("state:"..tostr(self.state.name),32,14,9)
|
print("state:"..tostr(self.state.name),32,14,9)
|
||||||
@ -1147,247 +1078,72 @@ function rope:draw(artificial_dx,artificial_dy)
|
|||||||
]]--
|
]]--
|
||||||
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)
|
function rope:drag_dst(x,y)
|
||||||
self:drag(function() return #self.ancs+1 end,x,y)
|
self:drag(self.dst,x,y)
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:drag_src(x,y)
|
function rope:drag_src(x,y)
|
||||||
self:drag(function() return 0 end,x,y)
|
self:drag(self.src,x,y)
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:drag(
|
function rope:drag(
|
||||||
i,x,y
|
n1,ax_new,ay_new
|
||||||
)
|
)
|
||||||
local anc=self:_anc(i())
|
-- TODO: stepwise?
|
||||||
local busy=self:busy()
|
rope:_drag1(n1,ax_new,ay_new)
|
||||||
|
|
||||||
for x,y in _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
|
end
|
||||||
|
|
||||||
function rope:make_dirty(only_if_invalid)
|
-- TODO: Upon adding a point, start from there to see if we need another
|
||||||
local invalid=false
|
-- rather than adding at most one
|
||||||
for a=0,#self.ancs do
|
function rope:_drag1(n1,ax1_new,ay1_new)
|
||||||
local a0=self:_anc(a)
|
local ax1_old,ay1_old=n1.ax,n1.ay
|
||||||
local a1=self:_anc(a+1)
|
local n0=n1.prev
|
||||||
if not level:can_stretch(a0,a1) then
|
|
||||||
a0.dirty=true
|
|
||||||
a1.dirty=true
|
|
||||||
invalid=true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if (invalid or not only_if_invalid) self.dirty=true
|
|
||||||
end
|
|
||||||
|
|
||||||
function rope:_tidy_up_gen()
|
if n0!=nil then
|
||||||
self:make_dirty(true)
|
local ax0,ay0=n0.ax,n0.ay
|
||||||
|
for _,anchor in level:anchor_points() do
|
||||||
local busy=self:busy()
|
if
|
||||||
if (not self:latched()) return
|
(_in_box(anchor.ax,anchor.ay,ax0,ay0,ax1_old,ay1_old) or
|
||||||
if (not self.dirty) return
|
_in_box(anchor.ax,anchor.ay,ax0,ay0,ax1_new,ay1_new)) and
|
||||||
|
_which_side(anchor.ax,anchor.ay,ax0,ay0,ax1_old,ay1_old) !=
|
||||||
local settled=true
|
_which_side(anchor.ax,anchor.ay,ax0,ay0,ax1_new,ay1_new)
|
||||||
local loop=function(f)
|
then
|
||||||
local a=0
|
local n05={ax=anchor.ax,ay=anchor.ay,prev=n0,next=n1}
|
||||||
while a<=#self.ancs+1 do
|
n0.next = n05
|
||||||
local anc=self:_anc(a)
|
n1.prev = n05
|
||||||
if anc.dirty then
|
|
||||||
anc.seen=true
|
|
||||||
if self[f](self,a,busy) then
|
|
||||||
settled=false anc.changed=true
|
|
||||||
a=0
|
|
||||||
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
while true do
|
local n2=n1.next
|
||||||
settled=true
|
if n2!=nil then
|
||||||
|
local ax2,ay2=n2.ax,n2.ay
|
||||||
mark_unseen()
|
for _,anchor in level:anchor_points() do
|
||||||
propagate_dirty()
|
if
|
||||||
|
(_in_box(anchor.ax,anchor.ay,ax1_old,ay1_old,ax2,ay2) or
|
||||||
loop("_find_needed_anchors")
|
_in_box(anchor.ax,anchor.ay,ax1_new,ay1_new,ax2,ay2)) and
|
||||||
loop("_find_touched_anchors")
|
_which_side(anchor.ax,anchor.ay,ax1_old,ay1_old,ax2,ay2) !=
|
||||||
loop("_elide_point")
|
_which_side(anchor.ax,anchor.ay,ax1_new,ay1_new,ax2,ay2)
|
||||||
|
then
|
||||||
for a=0,#self.ancs+1,1 do
|
local n15={ax=anchor.ax,ay=anchor.ay,prev=n1,next=n2}
|
||||||
local anc=self:_anc(a)
|
n1.next = n15
|
||||||
if (anc.seen) anc.dirty=anc.changed
|
n2.prev = n15
|
||||||
if (anc.dirty) settled=false
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if (settled) break
|
|
||||||
end
|
|
||||||
|
|
||||||
if (self:busy()) return
|
|
||||||
|
|
||||||
for i=0,#self.ancs do
|
|
||||||
local a0=self:_anc(i)
|
|
||||||
local a1=self:_anc(i+1)
|
|
||||||
if not level:can_stretch(a0,a1) then
|
|
||||||
self:destroy()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.dirty=false
|
n1.ax=ax1_new
|
||||||
|
n1.ay=ay1_new
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:_find_needed_anchors(i,busy)
|
function _in_box(x,y,x0,y0,x1,y1)
|
||||||
if (i<=0) return false
|
x0,x1=_mnmx(x0,x1)
|
||||||
if (#self.ancs+1<i) return false
|
y0,y1=_mnmx(y0,y1)
|
||||||
|
return x0<=x and y0<=y and x<=x1 and y<=y1
|
||||||
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 (level: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)})
|
|
||||||
end
|
|
||||||
shellsort(anchors_bydist)
|
|
||||||
|
|
||||||
for a1 in all(anchors_bydist) do
|
|
||||||
a1=a1.el
|
|
||||||
if level:can_stretch(a0,a1) and
|
|
||||||
level: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
|
end
|
||||||
|
|
||||||
local ELIDE_POINT=0.01
|
function _which_side(x,y,x0,y0,x1,y1)
|
||||||
function rope:_find_touched_anchors(i)
|
return sgn0((x1-x0)*(y-y0) - (y1-y0)*(x-x0))
|
||||||
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 _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)<ELIDE_POINT
|
|
||||||
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,busy)
|
|
||||||
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 (not busy and level_anc==nil) then
|
|
||||||
-- do it unconditionally
|
|
||||||
else
|
|
||||||
if _linedist(a0,a1,a2) < ELIDE_POINT then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
if not level: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)
|
|
||||||
a0.dirty=true a0.changed=true
|
|
||||||
a2.dirty=true a2.changed=true
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function rope:_can_move_midpoint(a0,a1_0,a1_1,a2)
|
|
||||||
if not level:can_stretch(a1_0, a1_1) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
if not level:can_stretch(a0,a1_1) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
if not level:can_stretch(a1_1,a2) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
for x,y in _rastn(a1_0.x,a1_0.y,a1_1.x,a1_1.y,8,8) do
|
|
||||||
local tm={x=x,y=y}
|
|
||||||
if not level:can_stretch(a0,tm) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
if not level:can_stretch(tm,a2) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function _linedist(x0,v,x1)
|
function _linedist(x0,v,x1)
|
||||||
@ -1409,16 +1165,18 @@ function distance(p1,p2)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function rope:collide_rect(x1,y1,x2,y2,exclude_src,exclude_dst)
|
function rope:collide_rect(x1,y1,x2,y2,exclude_src,exclude_dst)
|
||||||
local last=#self.ancs-exclude_dst
|
local a0=self.src
|
||||||
for i=exclude_src,last,1 do
|
while true do
|
||||||
local a0=self:_anc(i)
|
local a1=a0.next
|
||||||
local a1=self:_anc(i+1)
|
if (a1==nil) return false
|
||||||
|
--[[
|
||||||
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,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,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,x1,y2,x2,y2)) return true
|
||||||
if (_line_line(a0.x,a0.y,a1.x,a1.y,x2,y1,x2,y2)) return true
|
if (_line_line(a0.x,a0.y,a1.x,a1.y,x2,y1,x2,y2)) return true
|
||||||
|
]]--
|
||||||
|
a0=a0.next
|
||||||
end
|
end
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function _line_line(x1,y1,x2,y2,x3,y3,x4,y4)
|
function _line_line(x1,y1,x2,y2,x3,y3,x4,y4)
|
||||||
@ -1451,28 +1209,25 @@ end
|
|||||||
-- moved here because it's complicated
|
-- moved here because it's complicated
|
||||||
|
|
||||||
function rope:tug_orientxy()
|
function rope:tug_orientxy()
|
||||||
local a1=self:_anc(#self.ancs+1)
|
local a1=self.dst
|
||||||
local a0=self:_anc(#self.ancs)
|
local a0=self.dst.prev
|
||||||
local dx=a0.x-a1.x
|
local dx=a0.ax-a1.ax
|
||||||
local tdx=0
|
local tdx=0
|
||||||
if (dx>3) tdx=1
|
if (dx>3/8) tdx=1
|
||||||
if (dx<-3) tdx=-1
|
if (dx<-3/8) tdx=-1
|
||||||
|
|
||||||
local dy=a0.y-a1.y
|
local dy=a0.ay-a1.ay
|
||||||
local tdy=0
|
local tdy=0
|
||||||
if abs(dy)>abs(dx)/2 then
|
if abs(dy)>abs(dx)/2 then
|
||||||
if (dy>3) tdy=1
|
if (dy>3/8) tdy=1
|
||||||
if (dy<-3) tdy=-1
|
if (dy<-3/8) tdy=-1
|
||||||
end
|
end
|
||||||
return tdx,tdy
|
return tdx,tdy
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:tug()
|
function rope:tug()
|
||||||
self:_tidy_up_gen()
|
|
||||||
if (not self:latched()) return
|
if (not self:latched()) return
|
||||||
local rc=self:_tug()
|
return self:_tug()
|
||||||
self:_tidy_up_gen()
|
|
||||||
return rc
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:_tug(hypothetically)
|
function rope:_tug(hypothetically)
|
||||||
@ -1568,12 +1323,7 @@ function rope:_tug(hypothetically)
|
|||||||
then
|
then
|
||||||
if (hypothetically) return ancs,0
|
if (hypothetically) return ancs,0
|
||||||
|
|
||||||
level:tug_crate(
|
level:tug_crate(mx0,my0,dmx,dmy)
|
||||||
mx0,my0,
|
|
||||||
dmx,dmy
|
|
||||||
)
|
|
||||||
-- be busy for 4 ticks while the crate moves
|
|
||||||
self:_anc(0).todo={{},{},{},{},{}}
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1666,26 +1416,26 @@ end
|
|||||||
|
|
||||||
function rope:_anchors_simplified()
|
function rope:_anchors_simplified()
|
||||||
-- todo: cache this
|
-- todo: cache this
|
||||||
self:_reindex()
|
|
||||||
|
|
||||||
local points={}
|
local points={}
|
||||||
local _slope = function(p0,p1)
|
local _slope = function(p0,p1)
|
||||||
return atan2(p1.y-p0.y,p1.x-p0.x)
|
return atan2(p1.y-p0.y,p1.x-p0.x)
|
||||||
end
|
end
|
||||||
for i=0,#self.ancs+1,1 do
|
a=self.src
|
||||||
local anc=self:_anc(i)
|
while a!=nil do
|
||||||
|
local point={x=a.ax*8,y=a.ay*8,ax=a.ax,ay=a.ay}
|
||||||
if #points<=1 then
|
if #points<=1 then
|
||||||
add(points,anc)
|
add(points,point)
|
||||||
elseif abs(
|
elseif abs(
|
||||||
_slope(points[#points-1],points[#points])-
|
_slope(points[#points-1],points[#points])-
|
||||||
_slope(points[#points],anc)
|
_slope(points[#points],point)
|
||||||
)==0 then -- epsilon?
|
)==0 then -- epsilon?
|
||||||
points[#points]=anc
|
points[#points]=point
|
||||||
else
|
else
|
||||||
add(points,anc)
|
add(points,point)
|
||||||
end
|
end
|
||||||
|
a=a.next
|
||||||
|
assert(#points<100)
|
||||||
end
|
end
|
||||||
|
|
||||||
return points
|
return points
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user