forked from pyrex/chameleonic
		
	catch up to latest developments #10
							
								
								
									
										280
									
								
								chameleonic.p8
									
									
									
									
									
								
							
							
						
						
									
										280
									
								
								chameleonic.p8
									
									
									
									
									
								
							| @@ -112,6 +112,73 @@ function _mnmx(x,y) | ||||
|  return x,y | ||||
| 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( | ||||
|  x0,y0,x1,y1 | ||||
| ) | ||||
|  local dx=abs(x1-x0) | ||||
|  local dy=abs(y1-y0) | ||||
|  local x=x0 | ||||
|  local y=y0 | ||||
|  | ||||
|  local sx=-1 | ||||
|  local sy=-1 | ||||
|  if (x0<x1) sx=1 | ||||
|  if (y0<y1) sy=1 | ||||
| 	 | ||||
|  local done=false,err | ||||
|  if dx>dy then | ||||
|   err=dx/2.0 | ||||
|   return function() | ||||
|    if (done) return  | ||||
|    if (x==x1) done=true return x1,y1 | ||||
|    local oldx,oldy=x,y | ||||
|    err-=dy | ||||
|    if (err<0) y+=sy err+=dx+dy return oldx,y | ||||
|    x+=sx | ||||
|    return oldx,oldy | ||||
|   end | ||||
|  else | ||||
|   err=dy/2.0 | ||||
|   return function() | ||||
|    if (done) return | ||||
|    if (y==y1) done=true return x1,y1 | ||||
|    local oldx,oldy=x,y | ||||
|    err-=dx | ||||
|    if (err<0) x+=sx err+=dy+dx return x,oldy | ||||
|    y+=sy | ||||
|    return oldx,oldy | ||||
|   end | ||||
|  end | ||||
| end | ||||
|  | ||||
| function _point_eq(p1,p2) | ||||
|  return p1.x==p2.x and p1.y==p2.y | ||||
| end | ||||
|  | ||||
| -->8 | ||||
| -- input | ||||
| kbd={} | ||||
| @@ -222,6 +289,7 @@ function level:reinit(n) | ||||
|  self.todo={} | ||||
|  self.bigx=(n%8) | ||||
|  self.bigy=(n\8) | ||||
|  self.cache_can_stretch=dcache:new() | ||||
|  | ||||
|  self:load_dynobjs() | ||||
|  self:recollide() | ||||
| @@ -335,6 +403,7 @@ function level:recollide() | ||||
|     self._crates[mxy]!=nil | ||||
|   end | ||||
|  end | ||||
|  self.cache_can_stretch:clear() | ||||
| end | ||||
|  | ||||
| function add_adjacent_anchors(tbl,mx,my) | ||||
| @@ -588,6 +657,75 @@ function level:tug_crate(mx0,my0,dmx,dmy) | ||||
|  self:recollide() | ||||
|  self:reanchor(false) | ||||
| 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 | ||||
| --player handling | ||||
| player={} | ||||
| @@ -905,7 +1043,7 @@ function rope:continue_cast() | ||||
|  local x1=x0+dx | ||||
|  local y1=y0+dy | ||||
|   | ||||
|  for x,y in self:_rast( | ||||
|  for x,y in _rast( | ||||
|   x0,y0,x1,y1 | ||||
|  ) do | ||||
|   local latch= | ||||
| @@ -986,14 +1124,14 @@ function rope:draw(artificial_dx,artificial_dy) | ||||
|   end | ||||
|  end | ||||
|  | ||||
|  --[[ | ||||
|  for i=0,#self.ancs+1 do | ||||
|   p=self:_anc(i) | ||||
|   local c=12 | ||||
|   if (p.dirty) c=13 | ||||
|   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,9) | ||||
|   print(tostr(p.id)..":"..p.x..","..p.y..","..#p.todo,0,i*8,12) | ||||
|  end | ||||
|  --[[ | ||||
|  for _,p in pairs(level._anch) do | ||||
| 	 pset(p.x,p.y,11) | ||||
| 	end | ||||
| @@ -1029,7 +1167,7 @@ function rope:drag( | ||||
|  local anc=self:_anc(i()) | ||||
|  local busy=self:busy() | ||||
|  | ||||
|  for x,y in self:_rast( | ||||
|  for x,y in _rast( | ||||
|   anc.x,anc.y,x,y | ||||
|  ) do | ||||
|   local a=self:_anc(i()) | ||||
| @@ -1038,8 +1176,6 @@ function rope:drag( | ||||
|    a.y=y | ||||
|    a.dirty=true | ||||
|    self.dirty=true | ||||
|    --self:_find_needed_anchors(i()) | ||||
|    --self:_find_needed_anchors(i()+1) | ||||
|    if (not busy) self:_tidy_up_gen() | ||||
|   end | ||||
|  end | ||||
| @@ -1050,7 +1186,7 @@ function rope:make_dirty(only_if_invalid) | ||||
|  for a=0,#self.ancs do | ||||
|   local a0=self:_anc(a) | ||||
|   local a1=self:_anc(a+1) | ||||
|   if not self:_can_stretch(a0,a1) then | ||||
|   if not level:can_stretch(a0,a1) then | ||||
|    a0.dirty=true | ||||
|    a1.dirty=true | ||||
|    invalid=true | ||||
| @@ -1075,6 +1211,7 @@ function rope:_tidy_up_gen() | ||||
|     anc.seen=true | ||||
|     if self[f](self,a,busy) then | ||||
|      settled=false anc.changed=true  | ||||
|      a=0 | ||||
|     end | ||||
|    end | ||||
|    a+=1 | ||||
| @@ -1127,7 +1264,7 @@ function rope:_tidy_up_gen() | ||||
|  for i=0,#self.ancs do | ||||
|   local a0=self:_anc(i) | ||||
|   local a1=self:_anc(i+1) | ||||
|   if not self:_can_stretch(a0,a1) then | ||||
|   if not level:can_stretch(a0,a1) then | ||||
|    self:destroy() | ||||
|   end | ||||
|  end | ||||
| @@ -1144,7 +1281,7 @@ function rope:_find_needed_anchors(i,busy) | ||||
|  | ||||
|  if (level:pcoll(a2.x,a2.y)) return false | ||||
|  if (level:pcoll(a0.x,a0.y)) return false  | ||||
|  if (self:_can_stretch(a0,a2)) return false | ||||
|  if (level:can_stretch(a0,a2)) return false | ||||
|  | ||||
|  local anchors_bydist={} | ||||
|  local x0,x2=_mnmx(a0.x,a2.x) | ||||
| @@ -1156,8 +1293,8 @@ function rope:_find_needed_anchors(i,busy) | ||||
|  | ||||
|  for a1 in all(anchors_bydist) do | ||||
|   a1=a1.el | ||||
|   if self:_can_stretch(a0,a1) and | ||||
|    self:_can_stretch(a1,a2) | ||||
|   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) | ||||
| @@ -1179,12 +1316,11 @@ function rope:_find_touched_anchors(i) | ||||
|  if (level:pcoll(a0.x,a0.y)) return false | ||||
|  if (level:pcoll(a2.x,a2.y)) return false | ||||
|  | ||||
|  for bx,by in self:_rast(a0.x,a0.y,a2.x,a2.y) do | ||||
|  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 | ||||
|    -- and self:_can_stretch(p,a2) | ||||
|   then | ||||
|    local id=self.id | ||||
|    add(self.ancs,{id=id,x=a1.x,y=a1.y,dirty=true,todo={}},i) | ||||
| @@ -1212,7 +1348,7 @@ function rope:_elide_point(i,busy) | ||||
|    return false | ||||
|   end | ||||
|  | ||||
|   if not self:_can_stretch(a0,a2) then | ||||
|   if not level:can_stretch(a0,a2) then | ||||
|    return false | ||||
|   end | ||||
|    | ||||
| @@ -1233,26 +1369,21 @@ function rope:_elide_point(i,busy) | ||||
| end | ||||
|  | ||||
| function rope:_can_move_midpoint(a0,a1_0,a1_1,a2) | ||||
|  if (level:pcoll(a0.x,a0.y)) return false | ||||
|  if (level:pcoll(a2.x,a2.y)) return false | ||||
|  if (level:pcoll(a1_0.x,a1_0.y)) return false | ||||
|  if (level:pcoll(a1_1.x,a1_1.y)) return false | ||||
|  | ||||
|  if not self:_can_stretch(a1_0, a1_1) then | ||||
|  if not level:can_stretch(a1_0, a1_1) then | ||||
|   return false | ||||
|  end | ||||
|  if not self:_can_stretch(a0,a1_1) then | ||||
|  if not level:can_stretch(a0,a1_1) then | ||||
|   return false | ||||
|  end | ||||
|  if not self:_can_stretch(a1_1,a2) then | ||||
|  if not level:can_stretch(a1_1,a2) then | ||||
|   return false | ||||
|  end | ||||
|  for x,y in self:_rastn(a1_0.x,a1_0.y,a1_1.x,a1_1.y,8,8) do | ||||
|  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 self:_can_stretch(a0,tm) then | ||||
|   if not level:can_stretch(a0,tm) then | ||||
|    return false | ||||
|   end | ||||
|   if not self:_can_stretch(tm,a2) then | ||||
|   if not level:can_stretch(tm,a2) then | ||||
|    return false | ||||
|   end | ||||
|  end | ||||
| @@ -1304,105 +1435,6 @@ function _line_line(x1,y1,x2,y2,x3,y3,x4,y4) | ||||
|  return true | ||||
| end | ||||
|  | ||||
| function rope:_can_stretch( | ||||
|  p1,p2 | ||||
| ) | ||||
|  -- faster implementation for straight lines | ||||
|  if p1.y\8==p2.y\8 then | ||||
|   local my=p2.y\8 | ||||
|   for mx=p1.x\8,p2.x\8 do | ||||
|    if (level:mcoll(mx,my)) return false | ||||
|   end | ||||
|  end | ||||
|  | ||||
|  if p1.x\8==p2.x\8 then | ||||
|   local mx=p2.x\8 | ||||
|   for my=p1.y\8,p2.y\8 do | ||||
|    if (level:mcoll(mx,my)) return false | ||||
|   end | ||||
|  end | ||||
|  | ||||
|  if (level:pcoll(p1.x,p1.y)) return false | ||||
|  if (level:pcoll(p2.x,p2.y)) return false | ||||
|  | ||||
|  local res=true | ||||
|  for x,y in self:_rastn(p1.x,p1.y,p2.x,p2.y,8,8) do | ||||
|   if level:pcoll(x,y) then | ||||
|    res=false | ||||
|    break | ||||
|   end | ||||
|  end | ||||
|   | ||||
|  return res | ||||
| end | ||||
|  | ||||
| function rope:_rastn( | ||||
|  x0,y0,x1,y1,dx,dy | ||||
| ) | ||||
|  -- todo: more optimized implementation? | ||||
|  local iter=self:_rast(x0,y0,x1,y1) | ||||
|  local prevx,prevy=nil,nil | ||||
|  | ||||
|  local done=false | ||||
|  return function()  | ||||
|   while not done do | ||||
|    local x,y=iter() | ||||
|  | ||||
|    if (x==nil) done=true return x1, y1 | ||||
|  | ||||
|    local x8 = x\dx | ||||
|    local y8 = y\dy | ||||
|    if not (x8==prevx and y8==prevy) then  | ||||
|     prevx,prevy=x8,y8 | ||||
|     return x,y | ||||
|    end | ||||
|   end | ||||
|  end | ||||
| end | ||||
|  | ||||
| function rope:_rast( | ||||
|  x0,y0,x1,y1 | ||||
| ) | ||||
|  local dx=abs(x1-x0) | ||||
|  local dy=abs(y1-y0) | ||||
|  local x=x0 | ||||
|  local y=y0 | ||||
|  | ||||
|  local sx=-1 | ||||
|  local sy=-1 | ||||
|  if (x0<x1) sx=1 | ||||
|  if (y0<y1) sy=1 | ||||
| 	 | ||||
|  local done=false,err | ||||
|  if dx>dy then | ||||
|   err=dx/2.0 | ||||
|   return function() | ||||
|    if (done) return  | ||||
|    if (x==x1) done=true return x1,y1 | ||||
|    local oldx,oldy=x,y | ||||
|    err-=dy | ||||
|    if (err<0) y+=sy err+=dx+dy return oldx,y | ||||
|    x+=sx | ||||
|    return oldx,oldy | ||||
|   end | ||||
|  else | ||||
|   err=dy/2.0 | ||||
|   return function() | ||||
|    if (done) return | ||||
|    if (y==y1) done=true return x1,y1 | ||||
|    local oldx,oldy=x,y | ||||
|    err-=dx | ||||
|    if (err<0) x+=sx err+=dy+dx return x,oldy | ||||
|    y+=sy | ||||
|    return oldx,oldy | ||||
|   end | ||||
|  end | ||||
| end | ||||
|  | ||||
| function _point_eq(p1,p2) | ||||
|  return p1.x==p2.x and p1.y==p2.y | ||||
| end | ||||
|  | ||||
| function neighbors(p) | ||||
|  local r={} | ||||
|  for dx=-1,1,1 do | ||||
|   | ||||
		Reference in New Issue
	
	Block a user