diff -r 5230c063214a -r 5ac181cb2396 hedgewars/uGearsUtils.pas --- a/hedgewars/uGearsUtils.pas Thu Jan 03 17:57:31 2019 +0100 +++ b/hedgewars/uGearsUtils.pas Thu Jan 03 19:46:48 2019 +0100 @@ -64,6 +64,7 @@ function GetUtility(Hedgehog: PHedgehog): TAmmoType; function WorldWrap(var Gear: PGear): boolean; +function HomingWrap(var Gear: PGear): boolean; function IsHogLocal(HH: PHedgehog): boolean; @@ -1809,6 +1810,47 @@ end; end; +(* +Applies wrap-around logic for the target of homing gears. + +In wrap-around world edge, the shortest way may to the target might +be across the border, so the X value of the target would lead the +gear to the wrong direction across the whole map. This procedure +changes the target X in this case. +This function must be called after the gear passed through +the wrap-around world edge (WorldWrap returned true). + +No-op for other world edges. + +Returns true if target has been changed. +*) +function HomingWrap(var Gear: PGear): boolean; +var dist_center, dist_right, dist_left: hwFloat; +begin + if WorldEdge = weWrap then + begin + HomingWrap:= false; + // We just check the same target 3 times: + // 1) in current section (no change) + // 2) clone in the right section + // 3) clone in the left section + // The gear will go for the target with the shortest distance to the gear. + // For simplicity, we only check distance on the X axis. + dist_center:= hwAbs(Gear^.X - int2hwFloat(Gear^.Target.X)); + dist_right:= hwAbs(Gear^.X - int2hwFloat(Gear^.Target.X + (RightX-LeftX))); + dist_left:= hwAbs(Gear^.X - int2hwFloat(Gear^.Target.X - (RightX-LeftX))); + if (dist_left < dist_right) and (dist_left < dist_center) then + begin + dec(Gear^.Target.X, RightX-LeftX); + HomingWrap:= true; + end + else if (dist_right < dist_left) and (dist_right < dist_center) then + begin + inc(Gear^.Target.X, RightX-LeftX); + HomingWrap:= true; + end; + end; +end; // Add an audiovisual bounce effect for gear after it bounced from bouncy material. // Graphical effect is based on speed.