hedgewars/uGearsHandlersRope.pas
changeset 8733 b6002f1956d5
parent 8680 5fe344cc8610
child 8744 6c87486fd89b
--- a/hedgewars/uGearsHandlersRope.pas	Fri Mar 15 11:55:41 2013 -0400
+++ b/hedgewars/uGearsHandlersRope.pas	Sun Mar 17 00:18:38 2013 +0400
@@ -110,7 +110,7 @@
     lx, ly, cd: LongInt;
     haveCollision,
     haveDivided: boolean;
-
+    wrongSide: boolean;
 begin
     if GameTicks mod 4 <> 0 then exit;
 
@@ -216,6 +216,9 @@
                 if RopePoints.Count = 0 then
                     RopePoints.HookAngle := DxDy2Angle(Gear^.dY, Gear^.dX);
                 b := (nx * HHGear^.dY) > (ny * HHGear^.dX);
+                sx:= Gear^.dX.isNegative;
+                sy:= Gear^.dY.isNegative;
+                sb:= Gear^.dX.QWordValue < Gear^.dY.QWordValue;
                 dLen := len
                 end;
 
@@ -248,21 +251,45 @@
             ty := RopePoints.ar[Pred(RopePoints.Count)].Y;
             mdX := tx - Gear^.X;
             mdY := ty - Gear^.Y;
-            if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * (ty - HHGear^.Y) > (tx - HHGear^.X) * mdY) then
+            ropeDx:= tx - HHGear^.X;
+            ropeDy:= ty - HHGear^.Y;
+            if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * ropeDy > ropeDx * mdY) then
                 begin
                 dec(RopePoints.Count);
-                Gear^.X := RopePoints.ar[RopePoints.Count].X;
-                Gear^.Y := RopePoints.ar[RopePoints.Count].Y;
-                Gear^.Elasticity := Gear^.Elasticity + RopePoints.ar[RopePoints.Count].dLen;
-                Gear^.Friction := Gear^.Friction + RopePoints.ar[RopePoints.Count].dLen;
+                Gear^.X := tx;
+                Gear^.Y := ty;
+
+                // oops, opposite quadrant, don't restore hog position in such case, just remove the point
+                wrongSide:= (ropeDx.isNegative = RopePoints.ar[RopePoints.Count].sx)
+                    and (ropeDy.isNegative = RopePoints.ar[RopePoints.Count].sy);
+
+                // previous check could be inaccurate in vertical/horizontal rope positions,
+                // so perform this check also, even though odds are 1 to 415927 to hit this
+                if (not wrongSide)
+                    and ((ropeDx.isNegative = RopePoints.ar[RopePoints.Count].sx)
+                      <> (ropeDy.isNegative = RopePoints.ar[RopePoints.Count].sy)) then
+                    if RopePoints.ar[RopePoints.Count].sb then
+                        wrongSide:= ropeDy.isNegative = RopePoints.ar[RopePoints.Count].sy
+                        else
+                        wrongSide:= ropeDx.isNegative = RopePoints.ar[RopePoints.Count].sx;
 
-                // restore hog position
-                len := _1 / Distance(mdX, mdY);
-                mdX := mdX * len;
-                mdY := mdY * len;
+                if wrongSide then
+                    begin
+                    Gear^.Elasticity := Gear^.Elasticity - RopePoints.ar[RopePoints.Count].dLen;
+                    Gear^.Friction := Gear^.Friction - RopePoints.ar[RopePoints.Count].dLen;
+                    end else
+                    begin
+                    Gear^.Elasticity := Gear^.Elasticity + RopePoints.ar[RopePoints.Count].dLen;
+                    Gear^.Friction := Gear^.Friction + RopePoints.ar[RopePoints.Count].dLen;
 
-                HHGear^.X := Gear^.X - mdX * Gear^.Elasticity;
-                HHGear^.Y := Gear^.Y - mdY * Gear^.Elasticity;
+                    // restore hog position
+                    len := _1 / Distance(mdX, mdY);
+                    mdX := mdX * len;
+                    mdY := mdY * len;
+
+                    HHGear^.X := Gear^.X - mdX * Gear^.Elasticity;
+                    HHGear^.Y := Gear^.Y - mdY * Gear^.Elasticity;
+                    end;
                 end
             end;