hedgewars/uCollisions.pas
changeset 7754 e81dc9bef8b8
parent 7489 43a998fbacfe
child 7756 b89bd0ffb8aa
--- a/hedgewars/uCollisions.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uCollisions.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -56,6 +56,7 @@
 
 // returns: negative sign if going downhill to left, value is steepness (noslope/error = _0, 45° = _0_5)
 function  CalcSlopeBelowGear(Gear: PGear): hwFloat;
+function  CalcSlopeNearGear(Gear: PGear; dirX, dirY: LongInt): hwFloat;
 function  CalcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): Boolean;
 
 implementation
@@ -139,8 +140,8 @@
 begin
 // Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap
 if (Gear^.CollisionMask = $FF7F) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
-    ((hwRound(Gear^.Hedgehog^.Gear^.X) + Gear^.Hedgehog^.Gear^.Radius + 4 < hwRound(Gear^.X) - Gear^.Radius) or
-     (hwRound(Gear^.Hedgehog^.Gear^.X) - Gear^.Hedgehog^.Gear^.Radius - 4 > hwRound(Gear^.X) + Gear^.Radius)) then
+    ((hwRound(Gear^.Hedgehog^.Gear^.X) + Gear^.Hedgehog^.Gear^.Radius + 16 < hwRound(Gear^.X) - Gear^.Radius) or
+     (hwRound(Gear^.Hedgehog^.Gear^.X) - Gear^.Hedgehog^.Gear^.Radius - 16 > hwRound(Gear^.X) + Gear^.Radius)) then
     Gear^.CollisionMask:= $FFFF;
 
 x:= hwRound(Gear^.X);
@@ -169,8 +170,8 @@
 begin
 // Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap
 if (Gear^.CollisionMask = $FF7F) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
-    ((hwRound(Gear^.Hedgehog^.Gear^.Y) + Gear^.Hedgehog^.Gear^.Radius + 4 < hwRound(Gear^.Y) - Gear^.Radius) or
-     (hwRound(Gear^.Hedgehog^.Gear^.Y) - Gear^.Hedgehog^.Gear^.Radius - 4 > hwRound(Gear^.Y) + Gear^.Radius)) then
+    ((hwRound(Gear^.Hedgehog^.Gear^.Y) + Gear^.Hedgehog^.Gear^.Radius + 16 < hwRound(Gear^.Y) - Gear^.Radius) or
+     (hwRound(Gear^.Hedgehog^.Gear^.Y) - Gear^.Hedgehog^.Gear^.Radius - 16 > hwRound(Gear^.Y) + Gear^.Radius)) then
     Gear^.CollisionMask:= $FFFF;
 
 y:= hwRound(Gear^.Y);
@@ -238,7 +239,7 @@
         with cinfos[i] do
             if (Gear <> cGear) and (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2))
             and ((mx > x) xor (Dir > 0)) then
-                if ((cGear^.Kind in [gtHedgehog, gtMine]) and ((Gear^.State and gstNotKickable) = 0)) or
+                if ((cGear^.Kind in [gtHedgehog, gtMine, gtKnife]) and ((Gear^.State and gstNotKickable) = 0)) or
                 // only apply X kick if the barrel is knocked over
                 ((cGear^.Kind = gtExplosives) and ((cGear^.State and gsttmpflag) <> 0)) then
                     begin
@@ -247,6 +248,7 @@
                         dX:= Gear^.dX;
                         dY:= Gear^.dY * _0_5;
                         State:= State or gstMoving;
+                        if Kind = gtKnife then State:= State and not gstCollision;
                         Active:= true
                         end;
                     DeleteCI(cGear);
@@ -298,7 +300,7 @@
         with cinfos[i] do
             if (Gear <> cGear) and (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2))
             and ((my > y) xor (Dir > 0)) then
-                if (cGear^.Kind in [gtHedgehog, gtMine, gtExplosives]) and ((Gear^.State and gstNotKickable) = 0) then
+                if (cGear^.Kind in [gtHedgehog, gtMine, gtKnife, gtExplosives]) and ((Gear^.State and gstNotKickable) = 0) then
                     begin
                     with cGear^ do
                         begin
@@ -306,6 +308,7 @@
                             dX:= Gear^.dX * _0_5;
                         dY:= Gear^.dY;
                         State:= State or gstMoving;
+                        if Kind = gtKnife then State:= State and not gstCollision;
                         Active:= true
                         end;
                     DeleteCI(cGear);
@@ -576,6 +579,99 @@
 CalcSlopeTangent:= true;
 end;
 
+function CalcSlopeNearGear(Gear: PGear; dirX, dirY: LongInt): hwFloat;
+var dx, dy: hwFloat;
+    collX, collY, i, y, x, gx, gy, sdx, sdy: LongInt;
+    isColl, bSucc: Boolean;
+begin
+
+if dirY <> 0 then 
+    begin
+    y:= hwRound(Gear^.Y) + Gear^.Radius * dirY;
+    gx:= hwRound(Gear^.X);
+    collX := gx;
+    isColl:= false;
+
+    if (y and LAND_HEIGHT_MASK) = 0 then
+        begin
+        x:= hwRound(Gear^.X) - Gear^.Radius + 1;
+        i:= x + Gear^.Radius * 2 - 2;
+        repeat
+        if (x and LAND_WIDTH_MASK) = 0 then
+            if Land[y, x] <> 0 then
+                if not isColl or (abs(x-gx) < abs(collX-gx)) then
+                    begin
+                    isColl:= true;
+                    collX := x;
+                    end;
+        inc(x)
+        until (x > i);
+        end;
+    end
+else
+    begin
+    x:= hwRound(Gear^.X) + Gear^.Radius * dirX;
+    gy:= hwRound(Gear^.Y);
+    collY := gy;
+    isColl:= false;
+
+    if (x and LAND_WIDTH_MASK) = 0 then
+        begin
+        y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
+        i:= y + Gear^.Radius * 2 - 2;
+        repeat
+        if (y and LAND_HEIGHT_MASK) = 0 then
+            if Land[y, x] <> 0 then
+                if not isColl or (abs(y-gy) < abs(collY-gy)) then
+                    begin
+                    isColl:= true;
+                    collY := y;
+                    end;
+        inc(y)
+        until (y > i);
+        end;
+    end;
+
+if isColl then
+    begin
+    // save original dx/dy
+    dx := Gear^.dX;
+    dy := Gear^.dY;
+
+    if dirY <> 0 then
+        begin
+        Gear^.dX.QWordValue:= 0;
+        Gear^.dX.isNegative:= (collX >= gx);
+        Gear^.dY:= _1*dirY
+        end
+    else
+        begin
+        Gear^.dY.QWordValue:= 0;
+        Gear^.dY.isNegative:= (collY >= gy);
+        Gear^.dX:= _1*dirX
+        end;
+
+    sdx:= 0;
+    sdy:= 0;
+    if dirY <> 0 then
+         bSucc := CalcSlopeTangent(Gear, collX, y, sdx, sdy, 0)
+    else bSucc := CalcSlopeTangent(Gear, x, collY, sdx, sdy, 0);
+
+    // restore original dx/dy
+    Gear^.dX := dx;
+    Gear^.dY := dy;
+
+    if bSucc and ((sdx <> 0) or (sdy <> 0)) then
+        begin
+        dx := int2hwFloat(sdy) / (abs(sdx) + abs(sdy));
+        dx.isNegative := (sdx * sdy) < 0;
+        exit (dx);
+        end
+    end;
+
+CalcSlopeNearGear := _0;
+end;
+
 function CalcSlopeBelowGear(Gear: PGear): hwFloat;
 var dx, dy: hwFloat;
     collX, i, y, x, gx, sdx, sdy: LongInt;