WIP: weSea tweaks, functional and visual
authorsheepluva
Sat, 05 Jul 2014 20:15:56 +0200
changeset 10354 56bd029245fc
parent 10352 2af2309207b0
child 10355 334b5f513703
WIP: weSea tweaks, functional and visual
hedgewars/uAIMisc.pas
hedgewars/uCollisions.pas
hedgewars/uConsts.pas
hedgewars/uGearsHandlersMess.pas
hedgewars/uGearsHedgehog.pas
hedgewars/uGearsList.pas
hedgewars/uGearsUtils.pas
hedgewars/uRender.pas
hedgewars/uVisualGears.pas
hedgewars/uVisualGearsHandlers.pas
hedgewars/uVisualGearsList.pas
--- a/hedgewars/uAIMisc.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uAIMisc.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -445,7 +445,7 @@
                     end;
             exit(0)
             end;
-        if (y > cWaterLine) or (x > rightX) or (x < leftX) then exit(-1)
+        if CheckCoordInWater(round(x), round(y)) then exit(-1)
         end
 end;
 
@@ -497,7 +497,7 @@
                     end;
             exit(0)
         end;
-        if (y > cWaterLine) or (x > rightX) or (x < leftX) then
+        if CheckCoordInWater(round(x), round(y)) then
             // returning -1 for drowning so it can be considered in the Rate routine
             exit(-1)
     end;
@@ -876,7 +876,7 @@
             UpdateLandTexture(hwRound(Gear^.X), 1, hwRound(Gear^.Y), 1, true);
             end;}
 
-    if not (hwRound(Gear^.Y) + cHHRadius < cWaterLine) then
+    if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + cHHRadius) then
         exit(false);
     if (Gear^.State and gstMoving) <> 0 then
     begin
@@ -941,7 +941,7 @@
 
     pX:= hwRound(Gear^.X);
     pY:= hwRound(Gear^.Y);
-    if pY + cHHRadius >= cWaterLine then
+    if CheckCoordInWater(pX, pY + cHHRadius) then
         begin
         if AltGear^.Hedgehog^.BotLevel < 4 then
             AddWalkBonus(pX, tY, 250, -40);
--- a/hedgewars/uCollisions.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uCollisions.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -54,6 +54,8 @@
 
 function  TestRectancleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean;
 
+function  CheckCoordInWater(X, Y: LongInt): boolean; inline;
+
 // returns: negative sign if going downhill to left, value is steepness (noslope/error = _0, 45 = _0_5)
 function  CalcSlopeBelowGear(Gear: PGear): hwFloat;
 function  CalcSlopeNearGear(Gear: PGear; dirX, dirY: LongInt): hwFloat;
@@ -112,6 +114,12 @@
     end;
 end;
 
+function CheckCoordInWater(X, Y: LongInt): boolean; inline;
+begin
+    CheckCoordInWater:= (Y > cWaterLine)
+        or ((WorldEdge = weSea) and ((X < leftX) or (X > rightX)));
+end;
+
 function CheckGearsCollision(Gear: PGear): PGearArray;
 var mx, my, tr: LongInt;
     i: Longword;
--- a/hedgewars/uConsts.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uConsts.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -314,6 +314,8 @@
 
     kSystemSoundID_Vibrate = $00000FFF;
 
+    cMinPlayWidth = 200;
+
 implementation
 
 end.
--- a/hedgewars/uGearsHandlersMess.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uGearsHandlersMess.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -259,9 +259,33 @@
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepDrowningGear(Gear: PGear);
     begin
-    AllInactive := false;
+    if Gear^.Timer = 0 then
+        begin
+        if (FollowGear = Gear) and (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) then
+            FollowGear:= CurrentHedgehog^.Gear;
+        end
+    else if Gear^.Timer > 0 then
+        begin
+        AllInactive := false;
+        dec(Gear^.Timer);
+        end;
+
     Gear^.Y := Gear^.Y + cDrownSpeed;
-    Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed;
+
+    if cWaterLine > hwRound(Gear^.Y) + Gear^.Radius then
+        begin
+        if leftX > hwRound(Gear^.X) - Gear^.Radius then
+            Gear^.X := Gear^.X - cDrownSpeed
+        else
+            Gear^.X := Gear^.X + cDrownSpeed;
+        end
+    else
+        Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed;
+
+    if cWaterLine < hwRound(Gear^.Y) + Gear^.Radius then
+    else
+        Gear^.Y := Gear^.Y + Gear^.dY * cDrownSpeed;
+
     // Create some bubbles (0.5% might be better but causes too few bubbles sometimes)
     if ((not SuddenDeathDmg and (WaterOpacity < $FF))
     or (SuddenDeathDmg and (SDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then
@@ -301,7 +325,7 @@
     if Gear^.dY.Round > 1 then
         Gear^.dY.QWordValue:= 8589934592;
 
-    if (Gear^.State and gstSubmersible <> 0) and (gY > cWaterLine) then
+    if (Gear^.State and gstSubmersible <> 0) and CheckCoordInWater(gX, gY) then
         begin
         Gear^.dX:= Gear^.dX * _0_999;
         Gear^.dY:= Gear^.dY * _0_999
@@ -787,7 +811,7 @@
             end;
 *)
     // move back to cloud layer
-        if yy > cWaterLine then
+        if CheckCoordInWater(xx, yy) then
             move:= true
         else if (xx > snowRight) or (xx < snowLeft) then
             move:=true
@@ -956,16 +980,19 @@
     gX := hwRound(Gear^.X);
     gY := hwRound(Gear^.Y);
     uw := (Gear^.Tag <> 0); // was bee underwater last tick?
-    nuw := (cWaterLine < gy + Gear^.Radius); // is bee underwater now?
+    nuw := CheckCoordInWater(gx, gy + Gear^.Radius); // is bee underwater now?
 
     // if water entered or left
     if nuw <> uw then
         begin
-        AddVisualGear(gX, cWaterLine, vgtSplash);
-        AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
-        AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
-        AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
-        AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
+        if (gX > leftX) and (gY < rightX) then
+            begin
+            AddVisualGear(gX, cWaterLine, vgtSplash);
+            AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
+            AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
+            AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
+            AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
+            end;
         StopSoundChan(Gear^.SoundChannel);
         if nuw then
             begin
@@ -1178,7 +1205,7 @@
             if (hwRound(Bullet^.X) and LAND_WIDTH_MASK <> 0)
             or (hwRound(Bullet^.Y) and LAND_HEIGHT_MASK <> 0) then
                     // only extend if not under water
-                    if hwRound(Bullet^.Y) < cWaterLine then
+                    if not CheckCoordInWater(hwRound(Bullet^.X), hwRound(Bullet^.Y)) then
                         begin
                         VGear^.dX := VGear^.dX + max(LAND_WIDTH,4096) * (VGear^.dX - VGear^.X);
                         VGear^.dY := VGear^.dY + max(LAND_WIDTH,4096) * (VGear^.dY - VGear^.Y);
@@ -2153,11 +2180,13 @@
         Gear^.X := Gear^.X + Gear^.dX + cWindSpeed * 640;
         Gear^.Y := Gear^.Y + Gear^.dY;
 
-        if (hwRound(Gear^.Y) > cWaterLine) then
+        gX := hwRound(Gear^.X);
+        gY := hwRound(Gear^.Y);
+
+        if CheckCoordInWater(gX, gY) then
             begin
-            gX := hwRound(Gear^.X);
             for i:= 0 to 3 do
-                AddVisualGear(gX - 16 + Random(32), cWaterLine - 16 + Random(16), vgtSteam);
+                AddVisualGear(gX - 8 + Random(16), gY - 8 + Random(16), vgtSteam);
             PlaySound(sndVaporize);
             DeleteGear(Gear);
             exit
@@ -2170,8 +2199,7 @@
             Gear^.Y:= Gear^.Y+_6;
             if (landPixel and lfIce <> 0) or (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
                 begin
-                gX := hwRound(Gear^.X);
-                gY := hwRound(Gear^.Y)-6;
+                gY := gy-6;
                 DrawExplosion(gX, gY, 4);
                 PlaySound(sndVaporize);
                 AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSteam);
@@ -2201,8 +2229,6 @@
             end
         else
             begin
-            gX := hwRound(Gear^.X);
-            gY := hwRound(Gear^.Y);
             // Standard fire
             if not sticky then
                 begin
@@ -2252,8 +2278,6 @@
         end;
     if Gear^.Health = 0 then
         begin
-        gX := hwRound(Gear^.X);
-        gY := hwRound(Gear^.Y);
         if not sticky then
             begin
             if ((GameTicks and $3) = 0) and (Random(1) = 0) then
@@ -2799,6 +2823,14 @@
         HHGear^.X := Gear^.X;
         HHGear^.Y := Gear^.Y;
 
+        // check for drowning
+        if CheckGearDrowning(HHGear) then
+            begin
+            AfterAttack;
+            DeleteGear(Gear);
+            exit;
+            end;
+
         inc(Gear^.Damage, 2);
 
         //  if TestCollisionXwithGear(HHGear, hwSign(Gear^.dX))
@@ -3167,6 +3199,18 @@
     else
         exit;
 
+    if playWidth > cMinPlayWidth then
+        begin
+        inc(leftX);
+        dec(rightX);
+        dec(playWidth, 2);
+        for i:= 0 to LAND_HEIGHT - 1 do
+            begin
+            Land[i, leftX] := 0;
+            Land[i, rightX] := 0;
+            end;
+        end;
+
     if cWaterLine > 0 then
         begin
         dec(cWaterLine);
@@ -3508,7 +3552,7 @@
     isUnderwater: Boolean;
     bubble: PVisualGear;
 begin
-    isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
+    isUnderwater:= CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + Gear^.Radius);
     if Gear^.Pos > 0 then
         dec(Gear^.Pos);
     AllInactive := false;
@@ -3614,6 +3658,7 @@
     if // (Gear^.Health = 0)
         (HHGear^.Damage <> 0)
         //or CheckGearDrowning(HHGear)
+        // drown if too deep under water
         or (cWaterLine + cVisibleWater * 4 < hwRound(HHGear^.Y))
         or (TurnTimeLeft = 0)
         // allow brief ground touches - to be fair on this, might need another counter
@@ -3929,7 +3974,7 @@
     if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] <= lfAllObjMask)
     or (Gear^.Timer < 1)
     or (Gear^.Hedgehog^.Team <> CurrentHedgehog^.Team)
-    or (hwRound(Gear^.Y) > cWaterLine) then
+    or CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then
         begin
         deleteGear(Gear);
         EXIT;
@@ -4318,7 +4363,7 @@
             loadNewPortalBall(Gear, true);
     end
 
-    else if (y > cWaterLine)
+    else if CheckCoordInWater(x, y)
     or (y < -max(LAND_WIDTH,4096))
     or (x > 2*max(LAND_WIDTH,4096))
     or (x < -max(LAND_WIDTH,4096)) then
@@ -4558,7 +4603,7 @@
             end
         else
             begin
-            if (rY <= cWaterLine) or (y <= cWaterLine) then
+            if CheckCoordInWater(rX, rY) or CheckCoordInWater(x, y) then
                 begin
                 if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0)
                     and (Land[y, x] <> 0) then
@@ -4945,7 +4990,7 @@
         begin
         //Gear^.dY := Gear^.dY + cGravity;
         //Gear^.Y := Gear^.Y + Gear^.dY;
-        if hwRound(Gear^.Y) > cWaterLine then
+        if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then
             Gear^.Timer := 1
         end;
 
--- a/hedgewars/uGearsHedgehog.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uGearsHedgehog.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -423,7 +423,7 @@
                newGear^.dY:= newDY / newGear^.Density
                end;
             if (CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amJetpack) and
-               (Gear^.Message and gmPrecise <> 0) and (hwRound(Y) > cWaterLine) then
+               (Gear^.Message and gmPrecise <> 0) and CheckCoordInWater(hwRound(X), hwRound(Y)) then
                 newGear^.State:= newGear^.State or gstSubmersible;
 
             case CurAmmoType of
@@ -548,7 +548,7 @@
                 begin
                 if TagTurnTimeLeft = 0 then
                     TagTurnTimeLeft:= TurnTimeLeft;
-                if (CurAmmoGear <> nil) and (CurAmmoGear^.State and gstSubmersible <> 0) and (hwRound(CurAmmoGear^.Y) > cWaterLine) then
+                if (CurAmmoGear <> nil) and (CurAmmoGear^.State and gstSubmersible <> 0) and CheckCoordInWater(hwRound(CurAmmoGear^.X), hwRound(CurAmmoGear^.Y)) then
                      TurnTimeLeft:=(Ammoz[a].TimeAfterTurn * cGetAwayTime) div 25
                 else TurnTimeLeft:=(Ammoz[a].TimeAfterTurn * cGetAwayTime) div 100;
                 end;
@@ -864,7 +864,7 @@
     land: Word;
 begin
 land:= 0;
-isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
+isUnderwater:= CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + Gear^.Radius);
 if Gear^.dX.QWordValue > 8160437862 then
     Gear^.dX.QWordValue:= 8160437862;
 if Gear^.dY.QWordValue > 8160437862 then
--- a/hedgewars/uGearsList.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uGearsList.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -649,12 +649,11 @@
         begin
         if (Gear <> CurrentHedgehog^.Gear) or (CurAmmoGear = nil) or (CurAmmoGear^.Kind <> gtKamikaze) then
             Gear^.Hedgehog^.Team^.Clan^.Flawless:= false;
-        if (hwRound(Gear^.Y) >= cWaterLine) then
+        if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then
             begin
             t:= max(Gear^.Damage, Gear^.Health);
             Gear^.Damage:= t;
-            if (((not SuddenDeathDmg) and (WaterOpacity < $FF)) or (SuddenDeathDmg and (WaterOpacity < $FF)))
-            and (hwRound(Gear^.Y) < cWaterLine + 256) then
+            if (((not SuddenDeathDmg) and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) then
                 spawnHealthTagForHH(Gear, t);
             end;
 
--- a/hedgewars/uGearsUtils.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uGearsUtils.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -357,19 +357,40 @@
         Gear^.DirAngle := Gear^.DirAngle - 360
 end;
 
+procedure DrownGear(Gear: PGear);
+begin
+Gear^.doStep := @doStepDrowningGear;
+
+Gear^.Timer := 5000; // how long game should wait
+end;
+
 function CheckGearDrowning(var Gear: PGear): boolean;
 var
-    skipSpeed, skipAngle, skipDecay: hwFloat;
-    i, maxDrops, X, Y: LongInt;
-    vdX, vdY: real;
+    skipSpeed, skipAngle, skipDecay, hwTmp: hwFloat;
+    i, maxDrops, X, Y, dist2Water: LongInt;
+    vdX, vdY, tmp: real;
     particle, splash: PVisualGear;
-    isSubmersible: boolean;
+    isSubmersible, isImpactH, isImpactRight, isLeaving: boolean;
     s: ansistring;
 begin
     // probably needs tweaking. might need to be in a case statement based upon gear type
+    X:= hwRound(Gear^.X);
     Y:= hwRound(Gear^.Y);
-    if cWaterLine < Y + Gear^.Radius then
+
+    dist2Water:= cWaterLine - (Y + Gear^.Radius);
+    isImpactH:= false;
+
+    if WorldEdge = weSea then
         begin
+        i:= dist2Water;
+        dist2Water:= min(dist2Water, min(X - Gear^.Radius - leftX, rightX - (X + Gear^.Radius)));
+        isImpactH:= i <> dist2Water;
+        end;
+
+    if dist2Water < 0 then
+        begin
+        // invisible gears will just be deleted
+        // unless they are generic fallers, then they will be "respawned"
         if Gear^.State and gstInvisible <> 0 then
             begin
             if Gear^.Kind = gtGenericFaller then
@@ -386,20 +407,33 @@
         skipSpeed := _0_25;
         skipAngle := _1_9;
         skipDecay := _0_87;
-        X:= hwRound(Gear^.X);
-        vdX:= hwFloat2Float(Gear^.dX);
-        vdY:= hwFloat2Float(Gear^.dY);
-        // this could perhaps be a tiny bit higher.
-        if  (cWaterLine + 64 + Gear^.Radius > Y) and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed)
-        and (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)) then
+        vdX:= abs(hwFloat2Float(Gear^.dX));
+        vdY:= abs(hwFloat2Float(Gear^.dY));
+
+        // skipping
+
+        // check for -1 depth because if deeper, then it already had its chance of skipping
+        if  (dist2Water = -1) and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed)
+        and ( ((not isImpactH) and (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)))
+          or (isImpactH and (hwAbs(Gear^.dY) > skipAngle * hwAbs(Gear^.dX))) ) then
             begin
-            Gear^.dY.isNegative := true;
+            // if skipping we move the gear out of water
+            if isImpactH then
+                begin
+                Gear^.dX.isNegative := (not Gear^.dX.isNegative);
+                Gear^.X:= Gear^.X + Gear^.dX;
+                end
+            else
+                begin
+                Gear^.dY.isNegative := (not Gear^.dY.isNegative);
+                Gear^.Y:= Gear^.Y + Gear^.dY;
+                end;
             Gear^.dY := Gear^.dY * skipDecay;
             Gear^.dX := Gear^.dX * skipDecay;
             CheckGearDrowning := false;
             PlaySound(sndSkip)
             end
-        else
+        else // not skipping
             begin
             if not isSubmersible then
                 begin
@@ -418,58 +452,110 @@
                             end
                         else
                             begin
-                            Gear^.doStep := @doStepDrowningGear;
+                            DrownGear(Gear);
                             Gear^.State := Gear^.State and (not gstHHDriven);
                             s:= ansistring(Gear^.Hedgehog^.Name);
                             AddCaption(FormatA(GetEventString(eidDrowned), s), cWhiteColor, capgrpMessage);
                             end
                         end
                     else
-                        Gear^.doStep := @doStepDrowningGear;
-                        if Gear^.Kind = gtFlake then
-                            exit(true) // skip splashes
+                        DrownGear(Gear);
+                    if Gear^.Kind = gtFlake then
+                        exit(true); // skip splashes
                 end
+            // drown submersible grears if far below map
             else if (Y > cWaterLine + cVisibleWater*4) and
                     ((Gear <> CurrentHedgehog^.Gear) or (CurAmmoGear = nil) or (CurAmmoGear^.State and gstSubmersible = 0)) then
-                Gear^.doStep:= @doStepDrowningGear;
-            if ((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius))
-            or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and (Gear = CurAmmoGear) and ((CurAmmoGear^.Pos = 0)
-            and (CurAmmoGear^.dY < _0_01))) then
-                if Gear^.Density * Gear^.dY > _1 then
+                DrownGear(Gear);
+
+            isImpactRight:= isImpactH and (abs(X - leftX) > abs(rightX - X));
+            isLeaving:= (isSubmersible and (dist2Water = -2 * Gear^.Radius) and (Gear = CurAmmoGear) and (CurAmmoGear^.Pos = 0)
+            and (((not isImpactH) and CurAmmoGear^.dY.isNegative) or (isImpactH and (isImpactRight = CurAmmoGear^.dX.isNegative))));
+
+            // splash sound
+
+            if ((not isSubmersible) and (dist2Water = -1))
+            or isLeaving then
+                begin
+                // adjust water impact sound on gear speed and density
+                if isImpactH then
+                    hwTmp:= hwAbs(Gear^.Density * Gear^.dX)
+                else
+                    hwTmp:= hwAbs(Gear^.Density * Gear^.dY);
+
+                if hwTmp > _1 then
                     PlaySound(sndSplash)
-                else if Gear^.Density * Gear^.dY > _0_5 then
+                else if hwTmp > _0_5 then
                     PlaySound(sndSkip)
                 else
                     PlaySound(sndDroplet2);
+                end;
             end;
 
+        // splash animation
+
         if ((cReducedQuality and rqPlainSplash) = 0)
-        and (((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius))
-        or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and (Gear = CurAmmoGear) and ((CurAmmoGear^.Pos = 0)
-        and (CurAmmoGear^.dY < _0_01)))) then
+        and (((not isSubmersible) and (dist2Water = -1))
+        or isLeaving) then
             begin
-            splash:= AddVisualGear(X, cWaterLine, vgtSplash);
+            splash:= AddVisualGear(X, Y, vgtSplash);
             if splash <> nil then
-                with splash^ do
                 begin
-                Scale:= hwFloat2Float(Gear^.Density / _3 * Gear^.dY);
-                if Scale > 1 then Scale:= power(Scale,0.3333)
-                else Scale:= Scale + ((1-Scale) / 2);
-                if Scale > 1 then Timer:= round(min(Scale*0.0005/cGravityf,4))
-                else Timer:= 1;
-                // Low Gravity
-                FrameTicks:= FrameTicks*Timer;
+                if isImpactH then
+                    begin
+                    splash^.Scale:= abs(hwFloat2Float((Gear^.Density / _3) * Gear^.dX));
+                    if isImpactRight then
+                        splash^.Angle:= -90
+                    else
+                        splash^.Angle:=  90;
+                    end
+                else
+                    splash^.Scale:= abs(hwFloat2Float(Gear^.Density / _3 * Gear^.dY));
+                with splash^ do
+                    begin
+                    if Scale > 1 then Scale:= power(Scale,0.3333)
+                    else Scale:= Scale + ((1-Scale) / 2);
+                    if Scale > 1 then Timer:= round(min(Scale*0.0005/cGravityf,4))
+                    else Timer:= 1;
+                    // Low Gravity
+                    FrameTicks:= FrameTicks*Timer;
+                    end;
                 end;
 
+            // eject water drops
+
             maxDrops := (hwRound(Gear^.Density) * 3) div 2 + round(vdX * hwRound(Gear^.Density) * 6) + round(vdY * hwRound(Gear^.Density) * 6);
             for i:= max(maxDrops div 3, min(32, Random(maxDrops))) downto 0 do
                 begin
-                particle := AddVisualGear(X - 3 + Random(7), cWaterLine, vgtDroplet);
+                if isImpactH then
+                    begin
+                    if isImpactRight then
+                        particle := AddVisualGear(RightX, Y - 3 + Random(7), vgtDroplet)
+                    else
+                        particle := AddVisualGear(LeftX, Y - 3 + Random(7), vgtDroplet)
+                    end
+                else
+                    particle := AddVisualGear(X - 3 + Random(7), cWaterLine, vgtDroplet);
+
                 if particle <> nil then
                     with particle^ do
                         begin
-                        dX := dX - vdX / 10;
-                        dY := dY - vdY / 5;
+                        // dX and dY were initialized to have a random value on creation (see uVisualGearsList)
+                        if isImpactH then
+                            begin
+                            tmp:= dX;
+                            if isImpactRight then
+                                dX:=  dY - vdX / 5
+                            else
+                                dX:= -dy + vdX / 5;
+                            dY:= tmp * (1 + vdY / 10);
+                            end
+                        else
+                            begin
+                            dX:= dX * (1 + vdX / 10);
+                            dY:= dY - vdY / 5;
+                            end;
+
                         if splash <> nil then
                             begin
                             if splash^.Scale > 1 then
@@ -482,7 +568,7 @@
                                 dX:= dX * splash^.Scale;
                                 dY:= dY * splash^.Scale
                                 end
-                            end
+                            end;
                         end
                 end
             end;
@@ -1250,7 +1336,7 @@
 Trying to make the checks a little broader than on first pass to catch things that don't move normally.
 *)
 function WorldWrap(var Gear: PGear): boolean;
-var tdx: hwFloat;
+//var tdx: hwFloat;
 begin
 WorldWrap:= false;
 if WorldEdge = weNone then exit(false);
@@ -1281,7 +1367,7 @@
             end;
         if (Gear^.Radius > 2) and (Gear^.dX.QWordValue > _0_001.QWordValue) then
             PlaySound(sndMelonImpact)
-        end
+        end{
     else if WorldEdge = weSea then
         begin
         if (hwRound(Gear^.Y) > cWaterLine) and (Gear^.State and gstSubmersible <> 0) then
@@ -1296,7 +1382,7 @@
             Gear^.dY:= tdx;
             Gear^.dY.isNegative:= true
             end
-        end;
+        end};
 (*
 * Window in the sky (Gear moved high into the sky, Y is used to determine X) [unfortunately, not a safe thing to do. shame, I thought aerial bombardment would be kinda neat
 This one would be really easy to freeze game unless it was flagged unfortunately.
--- a/hedgewars/uRender.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uRender.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -847,7 +847,6 @@
 procedure DrawTextureRotatedF(Texture: PTexture; Scale, OffsetX, OffsetY: GLfloat; X, Y, Frame, Dir, w, h: LongInt; Angle: real);
 var ft, fb, fl, fr: GLfloat;
     hw, hh, nx, ny: LongInt;
-    VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
 begin
 
 // note: not taking scale into account
@@ -1520,7 +1519,6 @@
     lw, nWaves, shift: GLfloat;
     sprite: TSprite;
 begin
-
 // note: spriteHeight is the Height of the wave sprite while
 //       cWaveHeight describes how many pixels of it will be above waterline
 
--- a/hedgewars/uVisualGears.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uVisualGears.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -205,11 +205,25 @@
                            else
                                DrawTextureF(SpritesData[sprFlame].Texture, Gear^.FrameTicks / 900, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, (RealTicks shr 7 + Gear^.Frame) mod 8, 1, 16, 16);
                   vgtSplash: if SuddenDeathDmg then
+                                begin
+                                if Gear^.Angle <> 0 then
+                                    begin
+                                    DrawTextureRotatedF(SpritesData[sprSDSplash].Texture, Gear^.scale, 0, 0, round(Gear^.X + WorldDx + (((SpritesData[sprSDSplash].Height+8)*Gear^.Scale)/2) * (Gear^.Angle / abs(Gear^.Angle))), round(Gear^.Y + WorldDy), 19 - (Gear^.FrameTicks div Gear^.Timer div 37), 1, SpritesData[sprSDSplash].Width, SpritesData[sprSDSplash].Height, Gear^.Angle);
+                                    end
+                                else
                                  //DrawSprite(sprSDSplash, round(Gear^.X) + WorldDx - 40, round(Gear^.Y) + WorldDy - 58, 19 - (Gear^.FrameTicks div 37))
-                                 DrawTextureF(SpritesData[sprSDSplash].Texture, Gear^.scale, round(Gear^.X + WorldDx), round(Gear^.Y + WorldDy - ((SpritesData[sprSDSplash].Height+8)*Gear^.Scale)/2), 19 - (Gear^.FrameTicks div Gear^.Timer div 37), 1, SpritesData[sprSDSplash].Width, SpritesData[sprSDSplash].Height)
+                                    DrawTextureF(SpritesData[sprSDSplash].Texture, Gear^.scale, round(Gear^.X + WorldDx), round(Gear^.Y + WorldDy - ((SpritesData[sprSDSplash].Height+8)*Gear^.Scale)/2), 19 - (Gear^.FrameTicks div Gear^.Timer div 37), 1, SpritesData[sprSDSplash].Width, SpritesData[sprSDSplash].Height);
+                                end
                              else
+                                begin
+                                if Gear^.Angle <> 0 then
+                                    begin
+                                    DrawTextureRotatedF(SpritesData[sprSplash].Texture, Gear^.scale, 0, 0, round(Gear^.X + WorldDx + (((SpritesData[sprSplash].Height+8)*Gear^.Scale)/2) * (Gear^.Angle / abs(Gear^.Angle))), round(Gear^.Y + WorldDy), 19 - (Gear^.FrameTicks div Gear^.Timer div 37), 1, SpritesData[sprSplash].Width, SpritesData[sprSplash].Height, Gear^.Angle);
+                                    end
+                                else
                                  //DrawSprite(sprSplash, round(Gear^.X) + WorldDx - 40, round(Gear^.Y) + WorldDy - 58, 19 - (Gear^.FrameTicks div 37));
-                                 DrawTextureF(SpritesData[sprSplash].Texture, Gear^.scale, round(Gear^.X + WorldDx), round(Gear^.Y + WorldDy - ((SpritesData[sprSplash].Height+8)*Gear^.Scale)/2), 19 - (Gear^.FrameTicks div Gear^.Timer div 37), 1, SpritesData[sprSplash].Width, SpritesData[sprSplash].Height);
+                                    DrawTextureF(SpritesData[sprSplash].Texture, Gear^.scale, round(Gear^.X + WorldDx), round(Gear^.Y + WorldDy - ((SpritesData[sprSplash].Height+8)*Gear^.Scale)/2), 19 - (Gear^.FrameTicks div Gear^.Timer div 37), 1, SpritesData[sprSplash].Width, SpritesData[sprSplash].Height);
+                                 end;
                   vgtDroplet: if SuddenDeathDmg then
                                   DrawSprite(sprSDDroplet, round(Gear^.X) + WorldDx - 8, round(Gear^.Y) + WorldDy - 8, Gear^.Frame)
                               else
--- a/hedgewars/uVisualGearsHandlers.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uVisualGearsHandlers.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -75,7 +75,7 @@
 procedure initModule;
 
 implementation
-uses uVariables, Math, uConsts, uVisualGearsList, uFloat, uSound, uRenderUtils, uWorld;
+uses uCollisions, uVariables, Math, uConsts, uVisualGearsList, uFloat, uSound, uRenderUtils, uWorld;
 
 procedure doStepFlake(Gear: PVisualGear; Steps: Longword);
 var sign: real;
@@ -345,7 +345,7 @@
 Gear^.dX := Gear^.dX / (1.001 * Steps);
 Gear^.dY := Gear^.dY / (1.001 * Steps);
 
-if (Gear^.FrameTicks <= Steps) or (round(Gear^.Y) < cWaterLine) then
+if (Gear^.FrameTicks <= Steps) or not CheckCoordInWater(round(Gear^.X), round(Gear^.Y)) then
     DeleteVisualGear(Gear)
 else
     dec(Gear^.FrameTicks, Steps)
@@ -354,7 +354,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepSteam(Gear: PVisualGear; Steps: Longword);
 begin
-Gear^.X:= Gear^.X + (cWindSpeedf * 100 + Gear^.dX) * Steps;
+if ((cWindSpeedf > 0) and ( leftX > Gear^.X))
+or ((cWindSpeedf < 0) and (rightX < Gear^.X)) then
+    Gear^.X:= Gear^.X + (cWindSpeedf * 100 + Gear^.dX) * Steps;
 Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
 
 if Gear^.FrameTicks <= Steps then
--- a/hedgewars/uVisualGearsList.pas	Sat Jul 05 18:51:45 2014 +0200
+++ b/hedgewars/uVisualGearsList.pas	Sat Jul 05 20:15:56 2014 +0200
@@ -36,12 +36,12 @@
     VisualGearLayers: array[0..6] of PVisualGear;
 
 implementation
-uses uFloat, uVariables, uConsts, uTextures, uVisualGearsHandlers;
+uses uCollisions, uFloat, uVariables, uConsts, uTextures, uVisualGearsHandlers;
 
 function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
 begin
     // adjust some visual gear types if underwater
-    if (Y > cWaterLine) and ((Kind = vgtBeeTrace) or (Kind = vgtSmokeTrace) or (Kind = vgtEvilTrace)) then
+    if CheckCoordInWater(X, Y) and ((Kind = vgtBeeTrace) or (Kind = vgtSmokeTrace) or (Kind = vgtEvilTrace)) then
         Kind:= vgtBubble;
 
     AddVisualGear:= AddVisualGear(X, Y, Kind, 0, false, -1);