Hard math to fix
issue #571. Well, not really hard math,
just checking if vector is in opposite direction and trait
that as a special case when removing rope dividing point
(this could only happens when rope sticks to land outline,
so this basically fixes a bug in another bug).
--- 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;
--- a/hedgewars/uGearsRender.pas Fri Mar 15 11:55:41 2013 -0400
+++ b/hedgewars/uGearsRender.pas Sun Mar 17 00:18:38 2013 +0400
@@ -32,6 +32,7 @@
X, Y: hwFloat;
dLen: hwFloat;
b: boolean;
+ sx, sy, sb: boolean;
end;
rounded: array[0..MAXROPEPOINTS + 2] of TVertex2f;
end;