hedgewars/uGearsHandlersMess.pas
branchwebgl
changeset 9950 2759212a27de
parent 9521 8054d9d775fd
parent 9885 34e8880f1f0a
child 9954 bf51bc7e2808
--- a/hedgewars/uGearsHandlersMess.pas	Fri Oct 11 17:43:13 2013 +0200
+++ b/hedgewars/uGearsHandlersMess.pas	Sat Jan 04 23:55:54 2014 +0400
@@ -208,7 +208,7 @@
         if (gi^.Kind = gtHedgehog) then
             begin
             d := r - hwRound(Distance(gi^.X - x, gi^.Y - y));
-            if (d > 1) and (not gi^.Invulnerable) and (GetRandom(2) = 0) then
+            if (d > 1) and ((gi^.Hedgehog^.Effects[heInvulnerable] = 0)) and (GetRandom(2) = 0) then
                 begin
                 if (CurrentHedgehog^.Gear = gi) then
                     PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack)
@@ -263,13 +263,13 @@
     Gear^.Y := Gear^.Y + cDrownSpeed;
     Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed;
     // Create some bubbles (0.5% might be better but causes too few bubbles sometimes)
-    if (((not SuddenDeathDmg) and (WaterOpacity < $FF))
+    if ((not SuddenDeathDmg and (WaterOpacity < $FF))
     or (SuddenDeathDmg and (SDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then
         if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
             AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble)
     else if Random(12) = 0 then
              AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble);
-    if ((not SuddenDeathDmg) and (WaterOpacity > $FE))
+    if (not SuddenDeathDmg and (WaterOpacity > $FE))
     or (SuddenDeathDmg and (SDWaterOpacity > $FE))
     or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then
         DeleteGear(Gear);
@@ -280,30 +280,33 @@
 var
     isFalling: boolean;
     //tmp: QWord;
-    tdX, tdY: hwFloat;
-    collV, collH: LongInt;
-    land: word;
+    tX, tdX, tdY: hwFloat;
+    collV, collH, gX, gY: LongInt;
+    land, xland: word;
+    boing: PVisualGear;
 begin
-    WorldWrap(Gear);
+    tX:= Gear^.X;
+    gX:= hwRound(Gear^.X);
+    gY:= hwRound(Gear^.Y);
+    if (Gear^.Kind <> gtGenericFaller) and WorldWrap(Gear) and (WorldEdge = weWrap) and (Gear^.AdvBounce <> 0) and
+      ((TestCollisionXwithGear(Gear, 1) <> 0) or (TestCollisionXwithGear(Gear, -1) <> 0))  then
+        begin
+        Gear^.X:= tX;
+        Gear^.dX.isNegative:= (gX > LongInt(leftX) + Gear^.Radius*2)
+        end;
 
     // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems.
-{$IFNDEF WEBGL}
     if Gear^.dX.Round > 2 then
         Gear^.dX.QWordValue:= 8589934592;
     if Gear^.dY.Round > 2 then
         Gear^.dY.QWordValue:= 8589934592;
-{$ELSE}
-    if Gear^.dX.Round > 2 then
-        begin
-        Gear^.dX.Round:= 2;
-        Gear^.dX.Frac:= 0
+
+    if (Gear^.State and gstSubmersible <> 0) and (gY > cWaterLine) then
+        begin
+        Gear^.dX:= Gear^.dX * _0_999;
+        Gear^.dY:= Gear^.dY * _0_999
         end;
-    if Gear^.dY.QWordValue > 2 then
-        begin
-        Gear^.dY.Round:= 2;
-        Gear^.dY.Frac:= 0
-        end;
-{$ENDIF}
+
     Gear^.State := Gear^.State and (not gstCollision);
     collV := 0;
     collH := 0;
@@ -311,27 +314,32 @@
     tdY := Gear^.dY;
 
 // might need some testing/adjustments - just to avoid projectiles to fly forever (accelerated by wind/skips)
-    if (hwRound(Gear^.X) < min(LAND_WIDTH div -2, -2048))
-    or (hwRound(Gear^.X) > max(LAND_WIDTH * 3 div 2, 6144)) then
+    if (gX < min(LAND_WIDTH div -2, -2048))
+    or (gX > max(LAND_WIDTH * 3 div 2, 6144)) then
         Gear^.State := Gear^.State or gstCollision;
 
     if Gear^.dY.isNegative then
         begin
-        isFalling := true;
         land:= TestCollisionYwithGear(Gear, -1);
+        isFalling := land = 0;
         if land <> 0 then
             begin
             collV := -1;
             if land and lfIce <> 0 then
-                Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
-            else
-                Gear^.dX := Gear^.dX * Gear^.Friction;
-
-            Gear^.dY := - Gear^.dY * Gear^.Elasticity;
-            Gear^.State := Gear^.State or gstCollision
+                 Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
+            else Gear^.dX := Gear^.dX * Gear^.Friction;
+            if (Gear^.AdvBounce = 0) or (land and lfBouncy = 0) then
+                 begin
+                 Gear^.dY := - Gear^.dY * Gear^.Elasticity;
+                 Gear^.State := Gear^.State or gstCollision
+                 end
+            else Gear^.dY := - Gear^.dY * cElastic
             end
-        else if (Gear^.AdvBounce=1) and (TestCollisionYwithGear(Gear, 1) <> 0) then
-            collV := 1;
+        else if Gear^.AdvBounce = 1 then
+            begin
+            land:= TestCollisionYwithGear(Gear, 1);
+            if land <> 0 then collV := 1
+            end
         end
     else
         begin // Gear^.dY.isNegative is false
@@ -345,35 +353,64 @@
             else
                 Gear^.dX := Gear^.dX * Gear^.Friction;
 
-            Gear^.dY := - Gear^.dY * Gear^.Elasticity;
-            Gear^.State := Gear^.State or gstCollision
+            if (Gear^.AdvBounce = 0) or (land and lfBouncy = 0) then
+                 begin
+                 Gear^.dY := - Gear^.dY * Gear^.Elasticity;
+                 Gear^.State := Gear^.State or gstCollision
+                 end
+            else Gear^.dY := - Gear^.dY * cElastic
             end
         else
             begin
             isFalling := true;
-            if (Gear^.AdvBounce=1) and (TestCollisionYwithGear(Gear, -1) <> 0) then
-                collV := -1
+            if Gear^.AdvBounce = 1 then
+                begin
+                land:= TestCollisionYwithGear(Gear, -1);
+                if land <> 0 then collV := -1
+                end
             end
         end;
 
 
-    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
+    xland:= TestCollisionXwithGear(Gear, hwSign(Gear^.dX));
+    if xland <> 0 then
         begin
         collH := hwSign(Gear^.dX);
-        Gear^.dX := - Gear^.dX * Gear^.Elasticity;
-        Gear^.dY :=   Gear^.dY * Gear^.Elasticity;
-        Gear^.State := Gear^.State or gstCollision
+        if (Gear^.AdvBounce = 0) or (xland and lfBouncy = 0) then
+            begin
+            Gear^.dX := - Gear^.dX * Gear^.Elasticity;
+            Gear^.dY :=   Gear^.dY * Gear^.Elasticity;
+            Gear^.State := Gear^.State or gstCollision
+            end
+        else
+            begin
+            Gear^.dX := - Gear^.dX * cElastic;
+            Gear^.dY :=   Gear^.dY * cElastic
+            end
         end
-    else if (Gear^.AdvBounce=1) and TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)) then
-        collH := -hwSign(Gear^.dX);
+    else if Gear^.AdvBounce = 1 then
+        begin
+        xland:= TestCollisionXwithGear(Gear, -hwSign(Gear^.dX));
+        if xland <> 0 then collH := -hwSign(Gear^.dX)
+        end;
     //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
-    if (Gear^.AdvBounce=1) and (collV <>0) and (collH <> 0) and ((collV=-1)
-    or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)) then
-        begin
-        Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
-        Gear^.dY := tdX*Gear^.Elasticity;
-        //*Gear^.Friction;
-        Gear^.dY.isNegative := (not tdY.isNegative);
+    if (collV <> 0) and (collH <> 0) and 
+       (((Gear^.AdvBounce=1) and ((collV=-1) or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)))) then
+ //or ((xland or land) and lfBouncy <> 0)) then
+        begin
+        if (xland or land) and lfBouncy = 0 then
+            begin
+            Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
+            Gear^.dY := tdX*Gear^.Elasticity;
+            Gear^.State := Gear^.State or gstCollision
+            end
+        else
+            begin
+            Gear^.dX := tdY*cElastic*Gear^.Friction;
+            Gear^.dY := tdX*cElastic
+            end;
+
+        Gear^.dY.isNegative := not tdY.isNegative;
         isFalling := false;
         Gear^.AdvBounce := 10;
         end;
@@ -386,7 +423,7 @@
         Gear^.dY := Gear^.dY + cGravity;
         if (GameFlags and gfMoreWind) <> 0 then
             Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
-            end;
+        end;
 
     Gear^.X := Gear^.X + Gear^.dX;
     Gear^.Y := Gear^.Y + Gear^.dY;
@@ -397,7 +434,28 @@
     else
         Gear^.State := Gear^.State or gstMoving;
 
-    if (Gear^.nImpactSounds > 0) and
+    if ((xland or land) and lfBouncy <> 0) and (Gear^.dX.QWordValue < _0_15.QWordValue) and (Gear^.dY.QWordValue < _0_15.QWordValue) then
+        Gear^.State := Gear^.State or gstCollision;
+    
+    if ((xland or land) and lfBouncy <> 0) and (Gear^.Radius >= 3) and
+       ((Gear^.dX.QWordValue > _0_15.QWordValue) or (Gear^.dY.QWordValue > _0_15.QWordValue)) then
+        begin
+        boing:= AddVisualGear(gX, gY, vgtStraightShot, 0, false, 1);
+        if boing <> nil then
+            with boing^ do
+                begin
+                Angle:= random(360);
+                dx:= 0;
+                dy:= 0;
+                FrameTicks:= 200;
+                tX:= _0;
+                tX.QWordValue:= Gear^.dY.QWordValue + Gear^.dX.QWordValue;
+                Scale:= hwFloat2Float(Gear^.Density * tX) / 1.5;
+                State:= ord(sprBoing)
+                end;
+        PlaySound(sndMelonImpact, true)
+        end
+    else if (Gear^.nImpactSounds > 0) and
         (Gear^.State and gstCollision <> 0) and
         (((Gear^.Kind <> gtMine) and (Gear^.Damage <> 0)) or (Gear^.State and gstMoving <> 0)) and
         (((Gear^.Radius < 3) and (Gear^.dY < -_0_1)) or
@@ -700,6 +758,13 @@
         draw:= true;
     xx:= hwRound(Gear^.X);
     yy:= hwRound(Gear^.Y);
+    if draw and (WorldEdge = weWrap) and ((xx < LongInt(leftX) + 3) or (xx > LongInt(rightX) - 3)) then
+        begin
+        if xx < LongInt(leftX) + 3 then 
+             xx:= rightX-3
+        else xx:= leftX+3;
+        Gear^.X:= int2hwFloat(xx)
+        end
     end
 else if GameTicks and $7 = 0 then
     begin
@@ -864,21 +929,21 @@
     AllInactive := false;
 
     if Gear^.dY.isNegative then
-        if TestCollisionY(Gear, -1) then
+        if TestCollisionY(Gear, -1) <> 0 then
             Gear^.dY := _0;
 
-    if (not Gear^.dY.isNegative) then
-        if TestCollisionY(Gear, 1) then
-        begin
+    if not Gear^.dY.isNegative then
+        if TestCollisionY(Gear, 1) <> 0 then
+            begin
             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
             if Gear^.dY > - _1div1024 then
-            begin
+                begin
                 Gear^.Active := false;
                 exit
-            end
+                end
             else if Gear^.dY < - _0_03 then
                 PlaySound(Gear^.ImpactSound)
-        end;
+            end;
 
     Gear^.Y := Gear^.Y + Gear^.dY;
     CheckGearDrowning(Gear);
@@ -924,13 +989,24 @@
 
 
     if Gear^.Timer = 0 then
-        Gear^.RenderTimer:= false
+        begin
+        // no "fuel"? just fall
+        doStepFallingGear(Gear);
+        // if drowning, stop bee sound
+        if (Gear^.State and gstDrowning) <> 0 then
+            StopSoundChan(Gear^.SoundChannel);
+        end
     else
         begin
         if (GameTicks and $F) = 0 then
             begin
             if (GameTicks and $30) = 0 then
-                AddVisualGear(gX, gY, vgtBeeTrace);
+                begin
+                if nuw then
+                    AddVisualGear(gX, gY, vgtBubble)
+                else
+                    AddVisualGear(gX, gY, vgtBeeTrace);
+                end;
             Gear^.dX := Gear^.Elasticity * (Gear^.dX + _0_000064 * (Gear^.Target.X - gX));
             Gear^.dY := Gear^.Elasticity * (Gear^.dY + _0_000064 * (Gear^.Target.Y - gY));
             // make sure new speed isn't higher than original one (which we stored in Friction variable)
@@ -971,17 +1047,15 @@
     end;
 
     if (Gear^.Timer > 0) then
-        dec(Gear^.Timer)
-    else
-        begin
-        Gear^.State:= Gear^.State and (not gstSubmersible);
-        if nuw then
-           begin
-            StopSoundChan(Gear^.SoundChannel);
-            CheckGearDrowning(Gear);
-            end
-        else
-            doStepFallingGear(Gear);
+        begin
+        dec(Gear^.Timer);
+        if Gear^.Timer = 0 then
+            begin
+            // no need to display remaining time anymore
+            Gear^.RenderTimer:= false;
+            // bee can drown when timer reached 0
+            Gear^.State:= Gear^.State and not gstSubmersible;
+            end;
         end;
 end;
 
@@ -1141,7 +1215,7 @@
         Gear^.Y := Gear^.Y + Gear^.dY;
         tX:= Gear^.X;
         tY:= Gear^.Y;
-        if WorldWrap(Gear) then
+        if (Gear^.PortalCounter < 30) and WorldWrap(Gear) then
             begin
             cX:= Gear^.X;
             cY:= Gear^.Y;
@@ -1161,7 +1235,7 @@
         if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then
             inc(Gear^.Damage);
         // let's interrupt before a collision to give portals a chance to catch the bullet
-        if (Gear^.Damage = 1) and (Gear^.Tag = 0) and (not(CheckLandValue(x, y, lfLandMask))) then
+        if (Gear^.Damage = 1) and (Gear^.Tag = 0) and not(CheckLandValue(x, y, lfLandMask)) then
             begin
             Gear^.Tag := 1;
             Gear^.Damage := 0;
@@ -1188,7 +1262,7 @@
         dec(Gear^.Health, Gear^.Damage);
         Gear^.Damage := 0
         end;
-    if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and (((not SuddenDeathDmg) and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) then
+    if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and ((not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) then
         begin
         for i:=(Gear^.Health - Gear^.Damage) * 4 downto 0 do
             begin
@@ -1374,7 +1448,7 @@
             Gear^.X := Gear^.X + Gear^.dX;
             Gear^.Y := Gear^.Y + _1_9;
             end;
-        SetAllHHToActive(true);
+        SetAllHHToActive;
         end;
     if TestCollisionYwithGear(Gear, 1) <> 0 then
         begin
@@ -1649,12 +1723,14 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepSMine(Gear: PGear);
+    var land: Word;
 begin
     // TODO: do real calculation?
-    if TestCollisionXwithGear(Gear, 2)
-    or (TestCollisionYwithGear(Gear, -2) <> 0)
-    or TestCollisionXwithGear(Gear, -2)
-    or (TestCollisionYwithGear(Gear, 2) <> 0) then
+    land:= TestCollisionXwithGear(Gear, 2);
+    if land = 0 then land:= TestCollisionYwithGear(Gear,-2);
+    if land = 0 then land:= TestCollisionXwithGear(Gear,-2);
+    if land = 0 then land:= TestCollisionYwithGear(Gear, 2);
+    if (land <> 0) and (land and lfBouncy = 0) then
         begin
         if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
             begin
@@ -1681,24 +1757,23 @@
                     Gear^.State := Gear^.State or gstAttacking
             end
         else // gstAttacking <> 0
-        begin
+            begin
             AllInactive := false;
             if Gear^.Timer = 0 then
                 begin
                 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
                 DeleteGear(Gear);
                 exit
-            end else
+                end
+            else
                 if (Gear^.Timer and $FF) = 0 then
                     PlaySound(sndMineTick);
-
-            dec(Gear^.Timer);
+                dec(Gear^.Timer);
                 end
-        end
+            end
     else // gsttmpFlag = 0
-        if (TurnTimeLeft = 0)
-        or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime))
-        or (Gear^.Hedgehog^.Gear = nil) then
+        if ((GameFlags and gfInfAttack = 0) and ((TurnTimeLeft = 0) or (Gear^.Hedgehog^.Gear = nil))) 
+        or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime)) then
             Gear^.State := Gear^.State or gsttmpFlag;
 end;
 
@@ -1731,7 +1806,7 @@
     if (Gear^.dY.QWordValue = 0) and (Gear^.dY.QWordValue = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then
         SetLittle(Gear^.dY);
     Gear^.State := Gear^.State or gstAnimation;
-    if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and (not gstFrozen);
+    if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and not gstFrozen;
 
     if ((Gear^.dX.QWordValue <> 0)
     or (Gear^.dY.QWordValue <> 0))  then
@@ -1779,7 +1854,7 @@
     if Gear^.dX.QWordValue = 0 then AddCI(Gear)
     end; *)
 
-    if (not Gear^.dY.isNegative) and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then
+    if not Gear^.dY.isNegative and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then
         Gear^.dY := _0;
     if hwAbs(Gear^.dX) < _0_001 then
         Gear^.dX := _0;
@@ -1817,7 +1892,7 @@
                 Gear^.Message := Gear^.Message and (not (gmLJump or gmHJump));
         exit
         end;
-    if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and (not gstFrozen);
+    if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and not gstFrozen;
 
     if ((k <> gtExplosives) and (Gear^.Damage > 0)) or ((k = gtExplosives) and (Gear^.Health<=0)) then
         begin
@@ -1924,10 +1999,10 @@
 
         Gear^.dY := Gear^.dY + cGravity;
 
-        if (Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, -1) <> 0) then
-            Gear^.dY := _0;
-
-        Gear^.Y := Gear^.Y + Gear^.dY;
+        if ((not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0)) or
+           (Gear^.dY.isNegative and (TestCollisionYwithGear(Gear, -1) <> 0)) then
+             Gear^.dY := _0
+        else Gear^.Y := Gear^.Y + Gear^.dY;
 
         if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then
             SetAllHHToActive(false);
@@ -1962,7 +2037,11 @@
 procedure doStepTarget(Gear: PGear);
 begin
     if (Gear^.Timer = 0) and (Gear^.Tag = 0) then
+        begin
         PlaySound(sndWarp);
+        // workaround: save spawn Y for doStepCase (which is a mess atm)
+        Gear^.Angle:= hwRound(Gear^.Y);
+        end;
 
     if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then
         inc(Gear^.Timer)
@@ -2020,6 +2099,7 @@
 
     for i:= 0 to 3 do
         begin
+        AddVisualGear(hwRound(Gear^.X) + hwSign(Gear^.dX) * (10 + 6 * i), hwRound(Gear^.Y) + 12 + Random(6), vgtDust);
         AmmoShove(Gear, 30, 25);
         Gear^.X := Gear^.X + Gear^.dX * 5
         end;
@@ -2041,7 +2121,7 @@
 begin
     WorldWrap(Gear);
     sticky:= (Gear^.State and gsttmpFlag) <> 0;
-    if (not sticky) then AllInactive := false;
+    if not sticky then AllInactive := false;
 
     landPixel:= TestCollisionYwithGear(Gear, 1);
     if landPixel = 0 then
@@ -2124,7 +2204,7 @@
             gX := hwRound(Gear^.X);
             gY := hwRound(Gear^.Y);
             // Standard fire
-            if (not sticky) then
+            if not sticky then
                 begin
                 if ((GameTicks and $1) = 0) then
                     begin
@@ -2150,7 +2230,7 @@
 
                 if Gear^.Health > 0 then
                     dec(Gear^.Health);
-                Gear^.Timer := 450 - Gear^.Tag * 8 + GetRandom(2)
+                Gear^.Timer := 450 - Gear^.Tag * 8 + LongInt(GetRandom(2))
                 end
             else
                 begin
@@ -2164,7 +2244,7 @@
                     end;
 
 // This one is interesting.  I think I understand the purpose, but I wonder if a bit more fuzzy of kicking could be done with getrandom.
-                Gear^.Timer := 100 - Gear^.Tag * 3 + GetRandom(2);
+                Gear^.Timer := 100 - Gear^.Tag * 3 + LongInt(GetRandom(2));
                 if (Gear^.Damage > 3000+Gear^.Tag*1500) then
                     Gear^.Health := 0
                 end
@@ -2174,7 +2254,7 @@
         begin
         gX := hwRound(Gear^.X);
         gY := hwRound(Gear^.Y);
-        if (not sticky) then
+        if not sticky then
             begin
             if ((GameTicks and $3) = 0) and (Random(1) = 0) then
                 for i:= Random(2) downto 0 do
@@ -2213,7 +2293,8 @@
         end;
 
     HHGear^.dY := HHGear^.dY + cGravity;
-    if (not HHGear^.dY.isNegative) then
+    if Gear^.Timer > 0 then dec(Gear^.Timer);
+    if not (HHGear^.dY.isNegative) or (Gear^.Timer = 0) then
         begin
         HHGear^.State := HHGear^.State or gstMoving;
         DeleteGear(Gear);
@@ -2290,7 +2371,7 @@
         HHGear^.Y := HHGear^.Y + cGravity * 40;
 
     // don't drift into obstacles
-    if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
+    if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) <> 0 then
         HHGear^.X := HHGear^.X - int2hwFloat(hwSign(HHGear^.dX));
     HHGear^.Y := HHGear^.Y + cGravity * 100;
     Gear^.X := HHGear^.X;
@@ -2322,7 +2403,7 @@
     AllInactive := false;
     Gear^.X := Gear^.X + cAirPlaneSpeed * Gear^.Tag;
 
-    if (Gear^.Health > 0) and (not (Gear^.X < Gear^.dX)) and (Gear^.X < Gear^.dX + cAirPlaneSpeed) then
+    if (Gear^.Health > 0)and(not (Gear^.X < Gear^.dX))and(Gear^.X < Gear^.dX + cAirPlaneSpeed) then
         begin
         dec(Gear^.Health);
             case Gear^.State of
@@ -2390,11 +2471,9 @@
         begin
         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
         DeleteGear(Gear);
-        {$IFNDEF PAS2C}
         with mobileRecord do
             if (performRumble <> nil) and (not fastUntilLag) then
                 performRumble(kSystemSoundID_Vibrate);
-        {$ENDIF}
         exit
         end;
     if (GameTicks and $3F) = 0 then
@@ -2408,6 +2487,7 @@
     HHGear: PGear;
     x, y, tx, ty: hwFloat;
     rx: LongInt;
+    LandFlags: Word;
 begin
     AllInactive := false;
 
@@ -2418,12 +2498,16 @@
     y := HHGear^.Y;
     rx:= hwRound(x);
 
+    LandFlags:= 0;
+    if Gear^.AmmoType = amRubber then LandFlags:= lfBouncy
+    else if cIce then LandFlags:= lfIce;
+
     if ((Distance(tx - x, ty - y) > _256) and ((WorldEdge <> weWrap) or 
             (
             (Distance(tx - int2hwFloat(rightX+(rx-leftX)), ty - y) > _256) and
             (Distance(tx - int2hwFloat(leftX-(rightX-rx)), ty - y) > _256)
             )))
-    or (not TryPlaceOnLand(Gear^.Target.X - SpritesData[sprAmGirder].Width div 2, Gear^.Target.Y - SpritesData[sprAmGirder].Height div 2, sprAmGirder, Gear^.State, true, false)) then
+    or (not TryPlaceOnLand(Gear^.Target.X - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Width div 2, Gear^.Target.Y - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Height div 2, Ammoz[Gear^.AmmoType].PosSprite, Gear^.State, true, false, LandFlags)) then
         begin
         PlaySound(sndDenied);
         HHGear^.Message := HHGear^.Message and (not gmAttack);
@@ -2485,9 +2569,9 @@
     AllInactive := false;
 
     HHGear := Gear^.Hedgehog^.Gear;
-    if (not (TryPlaceOnLand(Gear^.Target.X - SpritesData[sprHHTelepMask].Width div 2,
+    if not TryPlaceOnLand(Gear^.Target.X - SpritesData[sprHHTelepMask].Width div 2,
         Gear^.Target.Y - SpritesData[sprHHTelepMask].Height div 2,
-        sprHHTelepMask, 0, false, false))) then
+        sprHHTelepMask, 0, false, false) then
         begin
         HHGear^.Message := HHGear^.Message and (not gmAttack);
         HHGear^.State := HHGear^.State and (not gstAttacking);
@@ -2499,7 +2583,7 @@
     else
         begin
         DeleteCI(HHGear);
-        SetAllHHToActive(true);
+        SetAllHHToActive;
         Gear^.doStep := @doStepTeleportAnim;
 
   // copy old HH position and direction to Gear (because we need them for drawing the vanishing hog)
@@ -2821,7 +2905,7 @@
                     dmg:= dmgBase - max(hwRound(Distance(tdX, tdY)),gi^.Radius);
                 if (dmg > 1) then dmg:= ModifyDamage(min(dmg div 2, cakeDmg), gi);
                 if (dmg > 1) then
-                    if (CurrentHedgehog^.Gear = gi) and (not gi^.Invulnerable) then
+                    if (CurrentHedgehog^.Gear = gi) and ((gi^.Hedgehog^.Effects[heInvulnerable] = 0)) then
                         gi^.State := gi^.State or gstLoser
                     else
                         gi^.State := gi^.State or gstWinner;
@@ -3072,16 +3156,16 @@
 
     tempColl:= Gear^.CollisionMask;
     Gear^.CollisionMask:= $007F;
-    if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) or (GameTicks > Gear^.FlightTime) then
+    if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) <> 0) or (GameTicks > Gear^.FlightTime) then
         t := CheckGearsCollision(Gear)
     else t := nil;
     Gear^.CollisionMask:= tempColl;
     //fixes drill not exploding when touching HH bug
 
     if (Gear^.Timer = 0) or ((t <> nil) and (t^.Count <> 0))
-    or ( ((Gear^.State and gsttmpFlag) = 0) and (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not TestCollisionXWithGear(Gear, hwSign(Gear^.dX))))
+    or ( ((Gear^.State and gsttmpFlag) = 0) and (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) = 0))
 // CheckLandValue returns true if the type isn't matched
-    or (not (CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible))) then
+    or (not CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible)) then
         begin
         //out of time or exited ground
         StopSoundChan(Gear^.SoundChannel);
@@ -3093,7 +3177,7 @@
         exit
         end
 
-    else if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))) then
+    else if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) = 0) then
         begin
         StopSoundChan(Gear^.SoundChannel);
         Gear^.Tag := 1;
@@ -3251,7 +3335,7 @@
         dec(Gear^.Timer);
 
     fChanged := false;
-    if ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then
+    if (HHGear = nil) or ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then
         begin
         fChanged := true;
         if Gear^.Angle > 2048 then
@@ -3296,7 +3380,7 @@
     else
         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
 
-    if ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
+    if (HHGear <> nil) and ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
         begin
         HHGear^.Message := HHGear^.Message and (not gmAttack);
         AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
@@ -3304,7 +3388,7 @@
         dec(Gear^.Health)
         end;
 
-    if ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
+    if (HHGear <> nil) and ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
         begin
         Gear^.State := Gear^.State or gsttmpFlag;
         PauseMusic;
@@ -3471,7 +3555,7 @@
     Gear^.X := HHGear^.X;
     Gear^.Y := HHGear^.Y;
 
-    if (not isUnderWater) and hasBorder and ((HHGear^.X < _0)
+    if not isUnderWater and hasBorder and ((HHGear^.X < _0)
     or (hwRound(HHGear^.X) > LAND_WIDTH)) then
         HHGear^.dY.isNegative:= false;
 
@@ -3550,7 +3634,13 @@
     HHGear := Gear^.Hedgehog^.Gear;
     if HHGear = nil then
         begin
-        DeleteGear(Gear);
+        Gear^.Timer := 0;
+        Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
+        Gear^.Timer := 0;
+        Gear^.doStep := @doStepBirdyDisappear;
+        CurAmmoGear := nil;
+        isCursorVisible := false;
+        AfterAttack;
         exit
         end;
 
@@ -3652,14 +3742,21 @@
     HHGear: PGear;
 begin
     if Gear^.Timer > 0 then
-        dec(Gear^.Timer, 1)
-    else if Gear^.Hedgehog^.Gear = nil then
-        begin
-        DeleteGear(Gear);
+        dec(Gear^.Timer, 1);
+
+    HHGear := Gear^.Hedgehog^.Gear;
+    if HHGear = nil then
+        begin
+        Gear^.Timer := 0;
+        Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
+        Gear^.Timer := 0;
+        Gear^.doStep := @doStepBirdyDisappear;
+        CurAmmoGear := nil;
+        isCursorVisible := false;
         AfterAttack;
         exit
         end;
-    HHGear := Gear^.Hedgehog^.Gear;
+
     HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight));
     if abs(hwRound(HHGear^.Y - Gear^.Y)) > 32 then
         begin
@@ -3724,9 +3821,7 @@
     i: LongInt;
 begin
     AllInactive := false;
-    {$IFNDEF PAS2C}
     Gear^.dX := Gear^.dX;
-    {$ENDIF}
     doStepFallingGear(Gear);
     //    CheckGearDrowning(Gear); // already checked for in doStepFallingGear
     CalcRotationDirAngle(Gear);
@@ -3867,18 +3962,18 @@
         // won't port stuff that does not move towards the front/portal entrance
         if iscake then
             begin
-            if (not (((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative)) then
+            if not (((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative) then
                 continue;
             end
         else
-            if (not ((Gear^.dX*ox + Gear^.dY*oy).isNegative)) then
+            if not ((Gear^.dX*ox + Gear^.dY*oy).isNegative) then
                 continue;
 
         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]);
 
         r:= int2hwFloat(iterator^.Radius);
 
-        if (not (isbullet or iscake)) then
+        if not (isbullet or iscake) then
             begin
             // wow! good candidate there, let's see if the distance and direction is okay!
             if hasdxy then
@@ -3910,7 +4005,7 @@
         oy := (iterator^.Y - Gear^.Y);
         poffs:= (Gear^.dX * ox + Gear^.dY * oy);
 
-        if (not isBullet) and poffs.isNegative then
+        if not isBullet and poffs.isNegative then
             continue;
 
         // only port bullets close to the portal
@@ -3937,7 +4032,7 @@
         if Gear^.Elasticity.isNegative then
             nx.isNegative := (not nx.isNegative)
         else
-            ny.isNegative := (not ny.isNegative);
+            ny.isNegative := not ny.isNegative;
 
         // calc gear offset in portal normal vector direction
         noffs:= (nx * ox + ny * oy);
@@ -3946,7 +4041,7 @@
             continue;
 
         // avoid gravity related loops of not really moving gear
-        if (not (iscake or isbullet))
+        if not (iscake or isbullet)
         and (Gear^.dY.isNegative)
         and (conPortal^.dY.isNegative)
         and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue)
@@ -3971,7 +4066,7 @@
         if conPortal^.Elasticity.isNegative then
             nx.isNegative := (not nx.isNegative)
         else
-            ny.isNegative := (not ny.isNegative);
+            ny.isNegative := not ny.isNegative;
 
         // inverse cake's normal movement direction,
         // as if it just walked through a hole
@@ -4007,14 +4102,14 @@
         iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx;
         iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny;
 
-        if (not hasdxy) and (not (conPortal^.dY.isNegative)) then
+        if not hasdxy and (not (conPortal^.dY.isNegative)) then
             begin
             iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y))
             end;
 
         // see if the space on the exit side actually is enough
 
-        if (not (isBullet or isCake)) then
+        if not (isBullet or isCake) then
             begin
             // TestCollisionXwithXYShift requires a hwFloat for xShift
             ox.QWordValue := _1.QWordValue;
@@ -4027,17 +4122,16 @@
                 iterator^.Radius := iterator^.Radius - 1;
 
             // check front
-            isCollision := TestCollisionY(iterator, sy)
-                        or TestCollisionX(iterator, sx);
-
-            if (not isCollision) then
+            isCollision := (TestCollisionY(iterator, sy) <> 0) or (TestCollisionX(iterator, sx) <> 0);
+
+            if not isCollision then
                 begin
                 // check center area (with half the radius so that the
                 // the square check won't check more pixels than we want to)
                 iterator^.Radius := 1 + resetr div 2;
                 rh := resetr div 4;
-                isCollision := TestCollisionYwithXYShift(iterator,       0, -sy * rh, sy, false)
-                            or TestCollisionXwithXYShift(iterator, ox * rh,        0, sx, false);
+                isCollision := (TestCollisionYwithXYShift(iterator,       0, -sy * rh, sy, false) <> 0)
+                            or (TestCollisionXwithXYShift(iterator, ox * rh,        0, sx, false) <> 0);
                 end;
 
             iterator^.Radius := resetr;
@@ -4082,7 +4176,7 @@
             resetdy:=hwAbs(iterator^.dX*4);
             resetdy:= resetdy + hwPow(resetdy,3)/_6 + _3 * hwPow(resetdy,5) / _40 + _5 * hwPow(resetdy,7) / resety + resetx * hwPow(resetdy,9) / resetdx;
             iterator^.Angle:= hwRound(resetdy*_2048 / _PI);
-            if (not iterator^.dY.isNegative) then iterator^.Angle:= 2048-iterator^.Angle;
+            if not iterator^.dY.isNegative then iterator^.Angle:= 2048-iterator^.Angle;
             if iterator^.dX.isNegative then iterator^.Angle:= 4096-iterator^.Angle;
             end
         // VISUAL USE OF ANGLE ONLY
@@ -4096,10 +4190,11 @@
         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
         and (iterator = CurrentHedgehog^.Gear)
         and (CurAmmoGear <> nil)
-        and (CurAmmoGear^.Kind =gtRope) then
+        and (CurAmmoGear^.Kind = gtRope)
+        and (CurAmmoGear^.Elasticity <> _0) then
                CurAmmoGear^.PortalCounter:= 1;
 
-        if (not isbullet) and (iterator^.State and gstInvisible = 0)
+        if not isbullet and (iterator^.State and gstInvisible = 0)
         and (iterator^.Kind <> gtFlake) then
             FollowGear := iterator;
 
@@ -4162,7 +4257,7 @@
         Gear^.State := Gear^.State and (not gstMoving);
 
         if (Land[y, x] and lfBouncy <> 0)
-        or (not (CalcSlopeTangent(Gear, x, y, tx, ty, 255)))
+        or (not CalcSlopeTangent(Gear, x, y, tx, ty, 255))
         or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
             begin
             loadNewPortalBall(Gear, true);
@@ -4175,7 +4270,7 @@
         Gear^.dY := -s * tx;
 
         Gear^.DirAngle := DxDy2Angle(-Gear^.dY,Gear^.dX);
-        if (not Gear^.dX.isNegative) then
+        if not Gear^.dX.isNegative then
             Gear^.DirAngle := 180-Gear^.DirAngle;
 
         if ((Gear^.LinkedGear = nil)
@@ -4265,7 +4360,7 @@
                 iterator:= GearsList;
                 while iterator <> nil do
                     begin
-                    if (not (iterator^.Kind in [gtPortal, gtAirAttack, gtKnife])) and ((iterator^.Hedgehog <> CurrentHedgehog)
+                    if not (iterator^.Kind in [gtPortal, gtAirAttack, gtKnife]) and ((iterator^.Hedgehog <> CurrentHedgehog)
                     or ((iterator^.Message and gmAllStoppable) = 0)) then
                             begin
                             iterator^.Active:= true;
@@ -4520,11 +4615,9 @@
     Gear^.dY.isNegative := not Gear^.dY.isNegative;
 
     Gear^.doStep := @doStepSineGunShotWork;
-    {$IFNDEF PAS2C}
     with mobileRecord do
         if (performRumble <> nil) and (not fastUntilLag) then
             performRumble(kSystemSoundID_Vibrate);
-    {$ENDIF}
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -4705,7 +4798,8 @@
     Gear^.dY := Gear^.dY + cGravity / 100;
     if (GameTicks and $FF) = 0 then
         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx or EXPLNoDamage or EXPLDoNotTouchAny or EXPLPoisoned);
-    AllInactive:= false;
+    if Gear^.State and gstTmpFlag = 0 then
+        AllInactive:= false;
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -4732,7 +4826,7 @@
         if (tmp^.Kind = gtHedgehog) or (tmp^.Kind = gtMine) or (tmp^.Kind = gtExplosives) then
             begin
             //tmp^.State:= tmp^.State or gstFlatened;
-            if not tmp^.Invulnerable then
+            if (tmp^.Hedgehog^.Effects[heInvulnerable] = 0) then
                 ApplyDamage(tmp, CurrentHedgehog, tmp^.Health div 3, dsUnknown);
             //DrawTunnel(tmp^.X, tmp^.Y - _1, _0, _0_5, cHHRadius * 6, cHHRadius * 3);
             tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0);
@@ -5073,7 +5167,7 @@
             while t <> nil do
                 begin
                 if (t^.Kind = gtHedgehog) and (t^.Hedgehog^.Team^.Clan = HH^.Team^.Clan) then
-                    t^.Invulnerable:= true;
+                    t^.Hedgehog^.Effects[heInvulnerable]:= 1;
                 t:= t^.NextGear;
                 end;
             end;
@@ -5387,7 +5481,7 @@
 
                 if (Timer = iceCollideWithGround) and ((GameTicks - Power) > groundFreezingTime) then
                     begin
-                    FillRoundInLand2(target.x, target.y, iceRadius, icePixel);
+                    FillRoundInLandFT(target.x, target.y, iceRadius, icePixel);
                     landRect.x := min(max(target.x - iceRadius, 0), LAND_WIDTH - 1);
                     landRect.y := min(max(target.y - iceRadius, 0), LAND_HEIGHT - 1);
                     landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1);
@@ -5400,7 +5494,7 @@
                         begin
                         if (iter^.State and gstFrozen = 0) and
                            ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine)) and 
-                           (Distance(iter^.X-int2hwFloat(target.x),iter^.Y-int2hwFloat(target.y))<int2hwFloat(iceRadius*2)) then
+                           (abs(iter^.X.Round-target.x)+abs(iter^.Y.Round-target.y)+2<2*iceRadius) and (Distance(iter^.X-int2hwFloat(target.x),iter^.Y-int2hwFloat(target.y))<int2hwFloat(iceRadius*2)) then
                             begin
                             for t:= 0 to 5 do
                                 begin
@@ -5442,7 +5536,7 @@
                         end;
 
                     // FillRoundInLandWithIce(Target.X, Target.Y, iceRadius);
-                    SetAllHHToActive(true);
+                    SetAllHHToActive;
                     Timer := iceWaitCollision;
                     end;
 
@@ -5450,7 +5544,7 @@
                     begin
                     PlaySound(sndHogFreeze);
                     DrawIceBreak(Target.X, cWaterLine - iceHeight, iceRadius, iceHeight);
-                    SetAllHHToActive(true);
+                    SetAllHHToActive;
                     Timer := iceWaitCollision;
                     end;
 (*
@@ -5527,7 +5621,7 @@
         begin
         with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac;
         AddRandomness(CheckSum);
-        if gi^.Kind = gtGenericFaller then gi^.State:= gi^.State and (not gstTmpFlag);
+        if gi^.Kind = gtGenericFaller then gi^.State:= gi^.State and not gstTmpFlag;
         gi := gi^.NextGear
         end;
     AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y));
@@ -5593,7 +5687,8 @@
 
 // Search out a new target, as target seek time has expired, target is dead, target is out of range, or we did not have a target
 if (HHGear = nil) or (Gear^.Timer = 0) or
-   (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle))
+   (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) >  Gear^.Angle) and
+        (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle)))
     then
     begin
     hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Angle);
@@ -5626,9 +5721,9 @@
         begin
         tdX:= HHGear^.X-Gear^.X;
         dir:= hwSign(tdX);
-        if (not TestCollisionX(Gear, dir)) then
+        if TestCollisionX(Gear, dir) = 0 then
             Gear^.X:= Gear^.X + signAs(_1,tdX);
-        if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) then
+        if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) <> 0 then
             begin
             Gear^.dX:= SignAs(_0_15, tdX);
             Gear^.dY:= -_0_3;
@@ -5667,9 +5762,9 @@
         begin
         (*ox:= 0; oy:= 0;
         if TestCollisionYwithGear(Gear, -1) <> 0 then oy:= -1;
-        if TestCollisionXwithGear(Gear, 1)       then ox:=  1;
-        if TestCollisionXwithGear(Gear, -1)      then ox:= -1;
-        if TestCollisionYwithGear(Gear, 1) <> 0  then oy:=  1;
+        if TestCollisionXwithGear(Gear, 1)  <> 0 then ox:=  1;
+        if TestCollisionXwithGear(Gear, -1) <> 0 then ox:= -1;
+        if TestCollisionYwithGear(Gear, 1)  <> 0 then oy:=  1;
         if Gear^.Health > 0 then
             PlaySound(sndRopeAttach);
 
@@ -5698,9 +5793,9 @@
         end
     else if GameTicks and $3F = 0 then
         begin
-        if  (TestCollisionYwithGear(Gear, -1) = 0)
-        and (not (TestCollisionXwithGear(Gear, 1)))
-        and (not (TestCollisionXwithGear(Gear, -1)))
+        if  (TestCollisionYwithGear(Gear,-1) = 0)
+        and (TestCollisionXwithGear(Gear, 1) = 0)
+        and (TestCollisionXwithGear(Gear,-1) = 0)
         and (TestCollisionYwithGear(Gear, 1) = 0) then Gear^.State:= Gear^.State and (not gstCollision) or gstMoving;
         end
 end;