Fix cake walking through land when reaching wrap world edge
authorWuzzy <Wuzzy2@mail.ru>
Mon, 06 Aug 2018 21:35:08 +0200
changeset 13619 c9642782778b
parent 13618 d6b79a080a3e
child 13621 5fdb18e892c5
Fix cake walking through land when reaching wrap world edge But there still is some cake weirdness remaining, sadly. See code comments.
ChangeLog.txt
hedgewars/uGearsHandlers.pas
hedgewars/uGearsHandlersMess.pas
--- a/ChangeLog.txt	Mon Aug 06 19:33:46 2018 +0200
+++ b/ChangeLog.txt	Mon Aug 06 21:35:08 2018 +0200
@@ -15,7 +15,7 @@
  * Fix freezer ray not working through wrap world edge
  * Fix freezer ray going through bounce world edge
  * Fix cake walking through bounce world edge
- * Cake now stops at wrap world edge instead of walking through land (temporary fix)
+ * Fix cake walking through land when reaching wrap world edge
  * Laser sight now works properly through wrap world edge
  * Fix projectiles reacing incorrectly with land just behind the wrap world edge
  * Fix extreme amounts of droplets when shooting with minigun into ocean world edge
--- a/hedgewars/uGearsHandlers.pas	Mon Aug 06 19:33:46 2018 +0200
+++ b/hedgewars/uGearsHandlers.pas	Mon Aug 06 21:35:08 2018 +0200
@@ -97,12 +97,12 @@
 
     // Handle world wrap and bounce edge manually
     if (WorldEdge = weWrap) and
-        ((hwRound(Gear^.X) <= LongInt(leftX)) or (hwRound(Gear^.X) >= LongInt(rightX))) then
+        ((hwRound(Gear^.X) < LongInt(leftX)) or (hwRound(Gear^.X) > LongInt(rightX))) then
         begin
         LeftImpactTimer:= 150;
         RightImpactTimer:= 150;
-        Gear^.WDTimer:= 4;
-        Gear^.Karma:= 2;
+        Gear^.WDTimer:= 0;
+        Gear^.Karma:= 1;
         end
     else if (WorldEdge = weBounce) and
         (((hwRound(Gear^.X) - Gear^.Radius) < LongInt(leftX)) or ((hwRound(Gear^.X) + Gear^.Radius) > LongInt(rightX))) then
@@ -111,7 +111,7 @@
             LeftImpactTimer:= 333
         else
             RightImpactTimer:= 333;
-        Gear^.Karma:= 1;
+        Gear^.Karma:= 2;
         Gear^.WDTimer:= 0;
         if (Gear^.Radius > 2) and (Gear^.dX.QWordValue > _0_001.QWordValue) then
             AddBounceEffectForGear(Gear);
--- a/hedgewars/uGearsHandlersMess.pas	Mon Aug 06 19:33:46 2018 +0200
+++ b/hedgewars/uGearsHandlersMess.pas	Mon Aug 06 21:35:08 2018 +0200
@@ -3568,18 +3568,58 @@
 
     if not cakeStep(Gear) then Gear^.doStep:= @doStepCakeFall;
 
+    // Cake passed world edge.
     if (Gear^.Karma = 1) then
-        begin
-        // Cake hit bouncy edge, turn around
+        (* This code is not ideal, but at least not horribly broken.
+        The cake tries to reach the other side and continue to walk,
+        but there are some exceptions.
+        This code is called *after* the X coordinate have been wrapped.
+        Depending on terrain on the other side, the cake does this:
+        * Cake collides horizontally (even by 1 pixel): Turn around
+        * Cake does not see walkable ground above or below: Fall
+        * Otherwise: Walk normally
+        *)
+        begin
+        // Update coordinates
+        tdx:=Gear^.X;
+        if (hwRound(Gear^.X) < LongInt(leftX)) then
+             Gear^.X:= Gear^.X + int2hwfloat(rightX - leftX)
+        else Gear^.X:= Gear^.X - int2hwfloat(rightX - leftX);
+
+        Gear^.Tag:= 0;
+        if ((TestCollisionXwithGear(Gear, 1) <> 0) or (TestCollisionXwithGear(Gear, -1) <> 0)) then
+            // Cake collided horizontally, turn around. Prevents cake from being stuck in infinite loop.
+            // This can also happen if the terrain is just a slight slope. :-(
+            begin
+            Gear^.X := tdx;
+            Gear^.Karma := 3;
+            end
+        else
+            begin
+            // Check if cake has something to walk on the other side. If not, make it drop.
+            // There is nothing for the cake to stand on.
+            if (TestCollisionYwithGear(Gear, 1) = 0) and (TestCollisionYwithGear(Gear, -1) = 0) then
+                Gear^.doStep:= @doStepCakeFall;
+            Gear^.Karma := 4;
+            end;
+        end;
+    // Cake bounced!
+    if (Gear^.Karma = 2) or (Gear^.Karma = 3) then
+        begin
+        // Turn cake around
         Gear^.dX.isNegative := (not Gear^.dX.isNegative);
         Gear^.WDTimer := 0;
         Gear^.Angle := (LongInt(Gear^.Angle) + 2) and 3;
-        Gear^.Karma := 0;
 
         // Bounce effect
-        if (Gear^.Radius > 2) then
+        if (Gear^.Karma = 2) and (Gear^.Radius > 2) then
             AddBounceEffectForGear(Gear, 0.55);
 
+        Gear^.Tag:= 0;
+        Gear^.Karma := 4;
+        end;
+    if (Gear^.Karma = 4) then
+        begin
         // Reset CakePoints to fix cake angle
         cakeData:= PCakeData(Gear^.Data);
         with cakeData^ do
@@ -3591,15 +3631,6 @@
                 end;
                 CakeI:= 0;
             end;
-        Gear^.Tag:= 0;
-        end
-    else if (Gear^.Karma = 2) then
-        begin
-        (* Cake passed world edge.
-        Cake doesn't know yet how walk through
-        world wrap so it gives up and stops.
-        TODO: Teach cake how to deal with world wrap. *)
-        Gear^.Health := 0;
         Gear^.Karma := 0;
         end;