# HG changeset patch # User Wuzzy # Date 1685027115 -7200 # Node ID 7125918637e91d66a02b574c1eb78c968d577bb3 # Parent a4630009e7330582baf75587739ddb76263be186 Make tardis avoid water during Sudden Death diff -r a4630009e733 -r 7125918637e9 hedgewars/uGearsHandlersMess.pas --- a/hedgewars/uGearsHandlersMess.pas Wed May 24 23:58:28 2023 +0200 +++ b/hedgewars/uGearsHandlersMess.pas Thu May 25 17:05:15 2023 +0200 @@ -6410,6 +6410,7 @@ procedure doStepTardisWarp(Gear: PGear); var HH: PHedgehog; i,j,cnt: LongWord; + restoreBottomY: LongInt; s: ansistring; begin HH:= Gear^.Hedgehog; @@ -6506,8 +6507,37 @@ inc(cnt); if (cnt = 0) or SuddenDeathDmg or (Gear^.Timer = 0) then begin + // Place tardis if HH^.GearHidden <> nil then - FindPlace(HH^.GearHidden, false, 0, LAND_WIDTH, true, false); + begin + restoreBottomY:= cWaterLine; + // Place tardis at a random safe position + FindPlace(HH^.GearHidden, false, 0, LAND_WIDTH, restoreBottomY, true, false); + + // If in Sudden Death, rise the minimum possible spawn position to make + // it less likely for the hog to drown before its turn + if SuddenDeathActive and (cWaterRise > 0) then + begin + // Enough space to survive the water rise of 1 round. + // Also limit the highest spawn height to topY plus a small buffer zone + restoreBottomY:= max(topY + cHHRadius * 5, cWaterLine - cWaterRise * (TeamsCount + 1)); + // If gear is below the safe spawn height, place it again, + // but this time with the height limit in place + if (HH^.GearHidden <> nil) and (hwRound(HH^.GearHidden^.Y) > restoreBottomY) then + // Due to the reduced Y range, this one might fail for very aggressive SD water rise + begin + FindPlace(HH^.GearHidden, false, 0, LAND_WIDTH, restoreBottomY, true, false); + end; + // Still unsafe? Relax the height limit to a third of the map height above cWaterLine + if (HH^.GearHidden <> nil) and (hwRound(HH^.GearHidden^.Y) > restoreBottomY) then + begin + restoreBottomY:= cWaterLine - ((cWaterLine - topY) div 3); + // Even this might fail, but it's much less likely. If it fails, we still have the + // position of the first FindPlace as a fallback. + FindPlace(HH^.GearHidden, false, 0, LAND_WIDTH, restoreBottomY, true, false); + end; + end; + end; if HH^.GearHidden <> nil then begin diff -r a4630009e733 -r 7125918637e9 hedgewars/uGearsUtils.pas --- a/hedgewars/uGearsUtils.pas Wed May 24 23:58:28 2023 +0200 +++ b/hedgewars/uGearsUtils.pas Thu May 25 17:05:15 2023 +0200 @@ -42,6 +42,7 @@ procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); inline; procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean); procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity, deleteOnFail: boolean); +procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right, Bottom: LongInt; skipProximity, deleteOnFail: boolean); function CountLand(x, y, r, c: LongInt; mask, antimask: LongWord): LongInt; function CheckGearNear(Kind: TGearType; X, Y: hwFloat; rX, rY: LongInt): PGear; @@ -934,7 +935,12 @@ FindPlace(Gear, withFall, Left, Right, skipProximity, true); end; -procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity, deleteOnFail: boolean); +procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity, deleteOnFail: boolean); inline; +begin + FindPlace(Gear, withFall, Left, Right, cWaterLine, skipProximity, deleteOnFail); +end; + +procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right, Bottom: LongInt; skipProximity, deleteOnFail: boolean); var x: LongInt; y, sy, dir: LongInt; ar: array[0..1023] of TPoint; @@ -963,11 +969,11 @@ repeat cnt:= 0; y:= min(1024, topY) - Gear^.Radius shl 1; - while y < cWaterLine do + while y < Bottom do begin repeat inc(y, 2); - until (y >= cWaterLine) or + until (y >= Bottom) or (ignoreOverLap and (CountLand(x, y, Gear^.Radius - 1, 1, lfLandMask, 0) = 0)) or (not ignoreOverLap and (CountLand(x, y, Gear^.Radius - 1, 1, lfAll, 0) = 0)); @@ -975,13 +981,13 @@ repeat inc(y); - until (y >= cWaterLine) or + until (y >= Bottom) or (ignoreOverlap and (CountLand(x, y, Gear^.Radius - 1, 1, lfAll, 0) <> 0)) or (not ignoreOverlap and (CountLand(x, y, Gear^.Radius - 1, 1, lfLandMask, 0) <> 0)); - if (y - sy > Gear^.Radius * 2) and (y < cWaterLine) + if (y - sy > Gear^.Radius * 2) and (y < Bottom) and (((Gear^.Kind = gtExplosives) and (ignoreNearObjects or NoGearsToAvoid(x, y - Gear^.Radius, 60, 60)) and (isSteadyPosition(x, y+1, Gear^.Radius - 1, 3, lfAll)