Everything _seems_ to work
This commit is contained in:
		
							
								
								
									
										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() | ||||||
| @@ -326,16 +326,16 @@ function level:draw() | |||||||
|    spr(pit.contents,pit.px,pit.py) |    spr(pit.contents,pit.px,pit.py) | ||||||
|    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 | ||||||
|  |  | ||||||
|  |  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 | 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 | end | ||||||
|  |  | ||||||
| function rope:_relax() | 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 | ||||||
|  |  | ||||||
|  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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user