Compare commits

...

4 Commits

Author SHA1 Message Date
dc33b46260 Misc golf and perf improvements 2022-12-31 15:07:23 -08:00
fa5c13eb0d Golf would_stick a bit 2022-12-31 14:48:24 -08:00
bef28a8d87 Fix misc rope bugs 2022-12-31 14:44:24 -08:00
cc6efb5e61 Re-refactor 1 2022-12-31 14:05:22 -08:00

View File

@ -234,10 +234,10 @@ function level:reinit(n)
self.ix=n self.ix=n
self.todo={} self.todo={}
self.bigx,self.bigy=n%8,n\8 self.bigx,self.bigy=n%8,n\8
self.dirty=false
self:load_dynobjs() self:load_dynobjs()
self:recollide() self:recollide_reanchor()
self:reanchor(true)
self:spawn_exit() self:spawn_exit()
end end
@ -309,10 +309,12 @@ function level:update()
end end
for cix in all(remove) do for cix in all(remove) do
self._crates[cix]=nil self._crates[cix]=nil
self.dirty=true
end end
if #remove>0 then
self:recollide() if self.dirty then
self:reanchor() self:recollide_reanchor()
self.dirty=false
end end
end end
@ -344,7 +346,7 @@ function level:load_dynobjs()
end end
end end
function level:recollide() function level:recollide_reanchor()
self._coll={} self._coll={}
for mx=0,15 do for mx=0,15 do
for my=0,15 do for my=0,15 do
@ -354,9 +356,7 @@ function level:recollide()
self._crates[mxy] self._crates[mxy]
end end
end end
end
function level:reanchor()
local anch_new={} 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)
@ -389,17 +389,12 @@ function level:reanchor()
end end
end end
local anch_old=self._anch or {} local moves={}
for _,old in pairs(anch_old) do
old.dropped=true
end
for k,new in pairs(anch_new) do for k,new in pairs(anch_new) do
local old=anch_old[k] local old=(self._anch or {})[k]
if old then if old then
anch_new[k]=old anch_new[k]=new
old.ax_old,old.ay_old,old.ax,old.ay,old.adx,old.ady=old.ax,old.ay,new.ax,new.ay,new.adx,new.ady if (old.ax!=new.ax or old.ay!=new.ay) add(moves,{old.ax,old.ay,new.ax,new.ay,old,key=k})
old.dropped=nil
end end
end end
self._anch=anch_new self._anch=anch_new
@ -408,15 +403,16 @@ function level:reanchor()
add(self._anch_keys,{key=k}) add(self._anch_keys,{key=k})
end end
shellsort(self._anch_keys) shellsort(self._anch_keys)
for point in self:anchor_points() do shellsort(moves)
if point.ax_old and player.rope and (point.ax_old != point.ax or point.ay_old != point.ay) then --printh("!!STARTING!!")
-- printh("moving: "..tostring({point.ax_old,point.ay_old}).."=>"..tostring({point.ax,point.ay}))
player.rope:be_pushed_by(point,point.ax_old,point.ay_old) if player.rope then
end player.rope:experience_anchor_moves(moves)
point.ax_old,point.ay_old=nil,nil
end end
if (player.rope) player.rope:relax() for point in self:anchor_points() do
point.moved=nil
end
end end
function level:win_at(mx,my) function level:win_at(mx,my)
@ -424,13 +420,20 @@ function level:win_at(mx,my)
end end
function level:anchor_points() function level:anchor_points()
keys=all(self._anch_keys) -- TODO: Return this to using all()
local keys=all(self._anch_keys)
return function() return function()
local k=keys() local k=keys()
if (k) return self._anch[k.key] if (k) return self._anch[k.key]
end end
end end
function level:anchor_at(ax,ay)
for i in self:anchor_points() do
if (i.ax==ax and i.ay==ay) return i
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 not pit.contents) return pit if (pit and not pit.contents) return pit
@ -467,13 +470,10 @@ function level:spawn_exit()
end end
function level:mcoll(mx,my) function level:mcoll(mx,my)
if ((mx | my) & 0xFFF0!=0) return true
return self._coll[_mix(mx,my)] return self._coll[_mix(mx,my)]
end end
function level:pcoll(px,py)
return self:mcoll(px\8,py\8)
end
function level:get_crate(mx,my) function level:get_crate(mx,my)
return self._crates[_mix(mx,my)] return self._crates[_mix(mx,my)]
end end
@ -554,7 +554,6 @@ function level:can_move(
if (is_player and self:win_at(mx1,my1)) return true if (is_player and self:win_at(mx1,my1)) return true
if (is_player and self:get_open_pit(mx1,my1)) return wrongbleep:adequately_warned() if (is_player and self:get_open_pit(mx1,my1)) return wrongbleep:adequately_warned()
if ((mx1 | my1) & 0xFFF0!=0) return false
if (self:mcoll(mx1,my1) or player.x==mx1 and player.y==my1) return if (self:mcoll(mx1,my1) or player.x==mx1 and player.y==my1) return
if player.rope then if player.rope then
@ -576,8 +575,7 @@ function level:tug_crate(mx0,my0,dmx,dmy)
local px1,py1=mx1*8,my1*8 local px1,py1=mx1*8,my1*8
existing.todo={ existing.todo={
{px=px1+dmx,py=py1+dmy,mx=mx1,my=my1,update=function() {px=px1+dmx,py=py1+dmy,mx=mx1,my=my1,update=function()
self:recollide() self.dirty=true
self:reanchor()
return true return true
end}, end},
{px=px1,py=py1} {px=px1,py=py1}
@ -993,31 +991,26 @@ function rope:draw(artificial_px,artificial_py)
local sy=0 local sy=0
while true do while true do
if (n1==nil) break if (n1==nil) break
local anch=level:anchor_at(n1.ax,n1.ay)
local x=n1.ax*8 local x=n1.ax*8
local y=n1.ay*8 local y=n1.ay*8
if n1.associated_with then if anch then
if (n1.associated_with.adx>0) x-=1 if (anch.adx>0) x-=1
if (n1.associated_with.ady>0) y-=1 if (anch.ady>0) y-=1
end end
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,72,sy) print("ax="..n1.ax..",ay="..n1.ay,72,sy)
print(tostring(n1.associated_with and (not n1.associated_with.dropped and n1.associated_with.ax==n1.ax and n1.associated_with.ay==n1.ay)),76,sy+7) sy+=7
sy+=14
local n0=n1.prev local n0=n1.prev
local n2=n1.next local n2=n1.next
if n0!=nil and n2!=nil then if n0!=nil and n2!=nil then
if n1.associated_with then if anch then
local _,_,_,adx,ady=would_stick(n0.ax,n0.ay,n1.associated_with,n2.ax,n2.ay) local _,_,_=would_stick(anch,n0.ax,n0.ay,n1.ax,n1.ay,n2.ax,n2.ay)
assert(adx==-1 or adx==0 or adx==1)
assert(ady==-1 or ady==0 or ady==1)
--assert(not (adx==0 and ady==0))
local c=3 local c=3
if (n1.associated_with.dropped) c=4 if (anch.dropped) c=4
rectfill(x+2,y+2,x+4,y+4,c) rectfill(x+2,y+2,x+4,y+4,c)
pset(x+adx*2,y,9)
pset(x,y+ady*2,9)
else else
rectfill(x+2,y+2,x+4,y+4,2) rectfill(x+2,y+2,x+4,y+4,2)
end end
@ -1036,7 +1029,7 @@ function rope:draw(artificial_px,artificial_py)
pset(x+p.adx,y,11) pset(x+p.adx,y,11)
pset(x,y+p.ady,11) pset(x,y+p.ady,11)
end end
]] ]]
end end
function rope:drag_dst(x,y) function rope:drag_dst(x,y)
@ -1055,26 +1048,13 @@ function rope:drag(n1,ax_new,ay_new)
end end
function rope:relax() function rope:relax()
local n0=self.src
while n0 do
if n0.associated_with and n0.associated_with.dropped then
for i in level:anchor_points() do
if i.ax==n0.ax and i.ay==n0.ay then
n0.associated_with=i
break
end
end
end
n0=n0.next
end
local n0=self.src local n0=self.src
while true do while true do
local n1=n0.next local n1=n0.next
if (not n1) break if (not n1) break
local n2=n1.next local n2=n1.next
if n0.ax==n1.ax and n0.ay==n1.ay then if n0.ax==n1.ax and n0.ay==n1.ay then
n0.next=n2 n0.next=n2
if (n2) n2.prev=n0 if (n2) n2.prev=n0
@ -1090,29 +1070,20 @@ function rope:relax()
local n2=n1.next local n2=n1.next
if (not n2) return if (not n2) return
if n1.associated_with then local x0,y0=n0.ax,n0.ay
local x1,y1=n1.ax,n1.ay
local x2,y2=n2.ax,n2.ay
local x0,y0=n0.ax,n0.ay local anch=level:anchor_at(n1.ax,n1.ay)
local x1,y1=n1.ax,n1.ay local would,x1_new,y1_new=would_stick(anch,x0,y0,x1,y1,x2,y2)
local x2,y2=n2.ax,n2.ay if not would and not (n1.ax==x1_new and n1.ay==y1_new) then
self:_drag(n1,x1_new,y1_new,n1.ax,n1.ay)
if x1!=n1.associated_with.ax or y1!=n1.associated_with.ay then n0=n1.prev
-- printh("dragging home: "..tostring{n1.ax,n1.ay}.."->"..tostring(n1.associated_with)) n2=n1.next
self:_drag(n1,n1.associated_with.ax,n1.associated_with.ay) n0.next=n2
end n2.prev=n0
n1.next=nil
local would,x1_new,y1_new=would_stick(x0,y0,n1.associated_with,x2,y2) n1.prev=nil
if not would and not (n1.ax==x1_new and n1.ay==y1_new) then
-- printh("dragging: "..tostring{n1.associated_with, {x1_new, y1_new}})
-- printh("relaxing: "..tostring(n0.associated_with).."->"..tostring(n1.associated_with).."->"..tostring(n2.associated_with))
self:_drag(n1,x1_new,y1_new,n1.ax,n1.ay)
n0=n1.prev
n2=n1.next
n0.next=n2
n2.prev=n0
n1.next=nil
n1.prev=nil
else n0=n0.next end
else n0=n0.next end else n0=n0.next end
end end
end end
@ -1185,43 +1156,69 @@ function rope:_check_sane()
return true return true
end end
function would_stick(x0,y0,anchor,x2,y2) function would_stick(anchor,x0,y0,x1,y1,x2,y2)
local x1,y1=anchor.ax,anchor.ay x1,y1=x1 or anchor.ax,y1 or anchor.ay
local dx=x2-x0
local dy=y2-y0
local dx,dy=x2-x0,y2-y0
if (x1==x0 and y1==y0) return if (x1==x0 and y1==y0) return
if (x1==x2 and y1==y2) return if (x1==x2 and y1==y2) return
local adx,ady local function switch_ends()
local x1_new,y1_new dx,dy,x0,y0,x2,y2=-dx,-dy,x2,y2,x0,y0
if abs(dx)>abs(dy) then
if (x0>x2) dx,x0,y0,x2,y2=-dx,x2,y2,x0,y0
local dprop=(x1-x0)/dx
x1_new,y1_new=x1,y0+dprop*(y2-y0)
ady=sgn0(y1_new-y1)
adx=0
if (y0>y2) adx=ady
if (y0<y2) adx=-ady
else
if (y0>y2) dy,x0,y0,x2,y2=-dy,x2,y2,x0,y0
local dprop=(y1-y0)/dy
x1_new,y1_new=x0+dprop*(x2-x0),y1
adx=sgn0(x1_new-x1)
ady=0
if (x0>x2) ady=adx
if (x0<x2) ady=-adx
end end
local wouldnt=anchor.dropped or (anchor.adx!=adx or anchor.ady!=ady) local function signs(douter,dinner)
local adb=sgn0(dinner)
return -sgn0(douter)*adb,adb
end
return not wouldnt,x1_new,y1_new,adx,ady local adx,ady,x1_new,y1_new
if abs(dx)>abs(dy) then
if (x0>x2) switch_ends()
x1_new,y1_new=x1,y0+(x1-x0)/dx*dy
adx,ady=signs(dy,y1_new-y1)
else
if (y0>y2) switch_ends()
x1_new,y1_new=x0+(y1-y0)/dy*dx,y1
ady,adx=signs(dx,x1_new-x1)
end
return
anchor and anchor.adx==adx and anchor.ady==ady,
x1_new,y1_new
end end
function rope:be_pushed_by(anchor,ax_old,ay_old) function rope:experience_anchor_moves(moves)
self:_be_dragged_by(moves)
self:_be_pushed_by(moves)
self:relax()
end
function rope:_be_dragged_by(moves)
local n=self.src
while n do
for t in all(moves) do
local ax_old,ay_old,ax_new,ay_new=unpack(t)
if (ax_old==n.ax and ay_old==n.ay) n.dest={ax_new,ay_new} break
end
n=n.next
end
n=self.src
while n do
if (n.dest) self:_drag(n,unpack(n.dest)) n.dest=nil
n=n.next
end
end
function rope:_be_pushed_by(moves)
for i in all(moves) do
self:_be_pushed_by1(unpack(i))
end
end
function rope:_be_pushed_by1(ax_old,ay_old,ax_new,ay_new,anch)
local n0=self.src local n0=self.src
local ax_new,ay_new=anchor.ax,anchor.ay
while true do while true do
n1=n0.next n1=n0.next
if (not n1) return if (not n1) return
@ -1231,35 +1228,30 @@ function rope:be_pushed_by(anchor,ax_old,ay_old)
local nxmn,nxmx = _mnmx(nx0,nx1) local nxmn,nxmx = _mnmx(nx0,nx1)
local nymn,nymx = _mnmx(ny0,ny1) local nymn,nymx = _mnmx(ny0,ny1)
-- printh(tostring({anchor,nxmn,nxmx,nymn,nymx}))
if if
(ax_new!=ax_old or (nxmn<=anchor.ax and anchor.ax<=nxmx)) and (ax_new!=ax_old or (nxmn<ax_new and ax_new<nxmx)) and
(ay_new!=ay_old or (nymn<=anchor.ay and anchor.ay<=nymx)) and (ay_new!=ay_old or (nymn<ay_new and ay_new<nymx)) and
(_which_side(ax_old,ay_old,nx0,ny0,nx1,ny1)!= (_which_side(ax_old,ay_old,nx0,ny0,nx1,ny1)!=
_which_side(ax_new,ay_new,nx0,ny0,nx1,ny1) _which_side(ax_new,ay_new,nx0,ny0,nx1,ny1)
) and would_stick(nx0,ny0,anchor,nx1,ny1) ) and would_stick(anch,nx0,ny0,nil,nil,nx1,ny1)
then then
-- printh("found (in): "..tostring({{nx0,ny0},{nx1,ny1}, anchor}))
local nx05,ny05 local nx05,ny05
if ax_new==ax_old then if ax_new==ax_old then
nx05=anchor.ax nx05=ax_new
ny05=ny0+(nx05-nx0)/(nx1-nx0) * (ny1-ny0) ny05=ny0+(nx05-nx0)/(nx1-nx0) * (ny1-ny0)
-- printh("found (x): "..tostring({nx05,ny05}))
elseif ay_new==ay_old then elseif ay_new==ay_old then
ny05=anchor.ay ny05=ay_new
nx05=nx0+(ny05-ny0)/(ny1-ny0) * (nx1-nx0) nx05=nx0+(ny05-ny0)/(ny1-ny0) * (nx1-nx0)
-- printh("found (y): "..tostring({nx05,ny05}))
end end
local n05={ax=nx05,ay=ny05,associated_with=anchor,prev=n0,next=n1} local n05={ax=nx05,ay=ny05,prev=n0,next=n1}
--printh("adding: "..tostring({nx05,ny05,anchor}))
n0.next=n05 n0.next=n05
n1.prev=n05 n1.prev=n05
self:_drag(n05,anchor.ax,anchor.ay) -- printh("creating: "..tostring{anch,{n0.ax,n0.ay},{n05.ax,n05.ay},{n1.ax,n1.ay}})
-- printh("dragged: "..tostring({n05.ax,n05.ay,anchor})) -- printh("dragging: "..tostring{anch,{n05.ax,n05.ay},{ax_new,ay_new}})
-- printh("local: "..tostring(n0.associated_with).."->"..tostring(n05.associated_with).."->"..tostring(n1.associated_with)) self:_drag(n05,ax_new,ay_new)
else else
n0=n0.next n0=n0.next
end end
@ -1286,7 +1278,7 @@ function rope:_drag(n1,ax1_new,ay1_new,ax_removing,ay_removing)
if if
not _uncreatable(anchor) and not _uncreatable(anchor) 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(anchor,ax_pivot,ay_pivot,nil,nil,ax_far,ay_far_new) and
( (
_which_side(anchor.ax,anchor.ay,ax_pivot,ay_pivot,ax_far,ay_far_old) != _which_side(anchor.ax,anchor.ay,ax_pivot,ay_pivot,ax_far,ay_far_old) !=
_which_side(anchor.ax,anchor.ay,ax_pivot,ay_pivot,ax_far,ay_far_new) _which_side(anchor.ax,anchor.ay,ax_pivot,ay_pivot,ax_far,ay_far_new)
@ -1307,7 +1299,7 @@ function rope:_drag(n1,ax1_new,ay1_new,ax_removing,ay_removing)
if if
not _uncreatable(anchor) and not _uncreatable(anchor) and
(ay0<=anchor.ay and anchor.ay<=ay1) and (ay0<=anchor.ay and anchor.ay<=ay1) and
would_stick(ax_pivot,ay_pivot,anchor,ax_far_new,ay_far) and would_stick(anchor,ax_pivot,ay_pivot,nil,nil,ax_far_new,ay_far) and
( (
_which_side(anchor.ax,anchor.ay,ax_pivot,ay_pivot,ax_far_old,ay_far) != _which_side(anchor.ax,anchor.ay,ax_pivot,ay_pivot,ax_far_old,ay_far) !=
_which_side(anchor.ax,anchor.ay,ax_pivot,ay_pivot,ax_far_new,ay_far) _which_side(anchor.ax,anchor.ay,ax_pivot,ay_pivot,ax_far_new,ay_far)
@ -1332,8 +1324,7 @@ function rope:_drag(n1,ax1_new,ay1_new,ax_removing,ay_removing)
n0.ax,n0.ay,ax1_old,ay1_old,ax1_new,ay1_new n0.ax,n0.ay,ax1_old,ay1_old,ax1_new,ay1_new
) )
if (not anch) break if (not anch) break
local n05={ax=anch.ax,ay=anch.ay,associated_with=anch,prev=n0,next=n1} local n05={ax=anch.ax,ay=anch.ay,prev=n0,next=n1}
-- printh("creating pre: "..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
@ -1346,8 +1337,7 @@ function rope:_drag(n1,ax1_new,ay1_new,ax_removing,ay_removing)
n2.ax,n2.ay,ax1_old,ay1_old,ax1_new,ay1_new n2.ax,n2.ay,ax1_old,ay1_old,ax1_new,ay1_new
) )
if (not anch) break if (not anch) break
local n15={ax=anch.ax,ay=anch.ay,associated_with=anch,prev=n1,next=n2} local n15={ax=anch.ax,ay=anch.ay,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
@ -1633,7 +1623,7 @@ function rope:_anchors_simplified()
x=flr(a.ax*8+0.5),y=flr(a.ay*8+0.5), x=flr(a.ax*8+0.5),y=flr(a.ay*8+0.5),
ax=a.ax,ay=a.ay ax=a.ax,ay=a.ay
} }
local aw=a.associated_with local aw=level:anchor_at(a.ax,a.ay)
local l=self.latch local l=self.latch
if aw then if aw then
if (aw.adx==1) point.x-=1 if (aw.adx==1) point.x-=1