hedgewars/GSHandlers.inc
changeset 4092 bf13068194b3
parent 4076 7ca17cb94992
child 4103 aa932f2e6349
--- a/hedgewars/GSHandlers.inc	Mon Nov 01 19:13:00 2010 -0400
+++ b/hedgewars/GSHandlers.inc	Tue Nov 02 13:17:01 2010 +0100
@@ -3343,7 +3343,7 @@
 var 
     iterator, conPortal: PGear;
     s, r, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat;
-    hasdxy, isbullet: Boolean;
+    hasdxy, isbullet, iscake: Boolean;
 begin
     doPortalColorSwitch();
 
@@ -3389,10 +3389,12 @@
 
         // don't port portals or other gear that wouldn't make sense
         if (iterator^.Kind in [gtPortal, gtRope, gtRCPlane])
-            or (iterator^.PortalCounter > 20) then
+            or (iterator^.PortalCounter > 32) then
              continue;
 
         // don't port hogs on rope
+        // TODO: this will also prevent hogs while falling after rope use from
+        //       falling through portals... fix that!
         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
            and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind =
            gtRope) then
@@ -3412,11 +3414,14 @@
            or (iterator^.Y > Gear^.Y + r) then
             continue;
 
-        hasdxy := ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0));
-
-        // in case the object is not moving, let's asume it's moving towards the portal
+        hasdxy := (((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0))
+                    or ((iterator^.State or gstMoving) = 0));
+
+        // in case the object is not moving, let's asume it's falling towards the portal
         if not hasdxy then
         begin
+            if Gear^.Y < iterator^.Y then
+                continue;
             ox:= Gear^.X - iterator^.X;
             oy:= Gear^.Y - iterator^.Y;
         end
@@ -3426,15 +3431,24 @@
             oy:= iterator^.dY;
         end;
 
+        // cake will need extra treatment... it's so delicious and moist!
+        iscake:= (iterator^.Kind = gtCake);
+
         // won't port stuff that does not move towards the front/portal entrance
-        if not (Gear^.dX*ox + Gear^.dY*oy).isNegative then
+        if iscake then
+        begin
+            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
                 continue;
 
         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]);
 
         r:= int2hwFloat(iterator^.Radius);
 
-        if not isbullet and (iterator^.Kind <> gtCake) 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
@@ -3453,16 +3467,6 @@
                 continue;
         end;
 
-(*
-        noTrap := ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0))
-                  // can't be entered from above
-                  or ((conPortal^.dY.isNegative and not (conPortal^.dY.QWordValue = 0))));
-        // can't be left downwards; 
-
-        // prevent getting stuck in a ground portal loop       
-        if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then
-            continue; *)
-
         // calc gear offset in portal vector direction
         ox := (iterator^.X - Gear^.X);
         oy := (iterator^.Y - Gear^.Y);
@@ -3475,9 +3479,6 @@
         // gears that make it till here will definately be ported
         //
 
-        if isbullet then
-            poffs:= _1_5;
-
         // create a normal of the portal vector, but ...
         nx := Gear^.dY;
         ny := Gear^.dX;
@@ -3490,24 +3491,26 @@
         // calc gear offset in portal normal vector direction
         noffs:= (nx * ox + ny * oy);
 
-        // move stuff with high normal offset close to the portal's center
-        if not isbullet then
-        begin
-            s := hwAbs(noffs) + r - int2hwFloat(Gear^.Radius);
-            if s > _0 then
-                noffs:= noffs - SignAs(s,noffs)
-        end;
-
-        iterator^.Active := true;
-        iterator^.State := iterator^.State or gstMoving;
-        DeleteCI(iterator);
+        // avoid gravity related loops of not really moving gear
+        if not iscake and (Gear^.dY.isNegative) and (conPortal^.dY.isNegative)
+            and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue)
+            and (iterator^.PortalCounter > 0) then
+             continue;
 
         // Until loops are reliably broken
         inc(iterator^.PortalCounter);
 
         // calc gear speed along to the vector and the normal vector of the portal
-        pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY);
-        nspeed:= (nx * iterator^.dX + ny * iterator^.dY);
+        if hasdxy then
+        begin
+            pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY);
+            nspeed:= (nx * iterator^.dX + ny * iterator^.dY);
+        end
+        else
+        begin
+            pspeed:= hwAbs(cGravity * oy);
+            nspeed:= _0;
+        end;
 
         // creating normal vector of connected (exit) portal
         nx := conPortal^.dY;
@@ -3517,17 +3520,45 @@
         else
             ny.isNegative := not ny.isNegative;
 
+        // inverse cake's normal movement direction,
+        // as if it just walked through a hole
+        if iscake then
+            nspeed.isNegative:= not nspeed.isNegative;
+
 //AddFileLog('poffs:'+cstr(poffs)+' noffs:'+cstr(noffs)+' pspeed:'+cstr(pspeed)+' nspeed:'+cstr(nspeed));
         iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx;
         iterator^.dY := -pspeed * conPortal^.dY + nspeed * ny;
-        if iterator^.Kind = gtCake then
-            poffs := poffs * _0_5
-        else
-        if poffs < r + _1_5 then
-            poffs := r + _1_5;
+
+        // make the gear's exit position close to the portal while
+        // still respecting the movement direction
+
+         // determine the distance (in exit vector direction)
+         // that we want the gear at
+         if iscake then
+             ox:= (r - _0_7)
+         else
+             ox:= (r + _1_9);
+         s:= ox / poffs;
+         poffs:= ox;
+         if (nspeed.QWordValue <> 0) and (pspeed > _0) then
+             noffs:= noffs * s * (nspeed / pspeed);
+
+        // move stuff with high normal offset closer to the portal's center
+        if not isbullet then
+        begin
+            s := hwAbs(noffs) + r - int2hwFloat(Gear^.Radius);
+            if s > _0 then
+                noffs:= noffs - SignAs(s,noffs)
+        end;
+
         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
+        begin
+            iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y))
+        end;
+
         if not isbullet then
             FollowGear := iterator;
 //AddFileLog('portal''d');
@@ -3547,7 +3578,7 @@
                 if iterator^.dY.QWordValue = _0.QWordValue then iterator^.dY.isNegative:= false;
                 iterator^.State:= iterator^.State or gstMoving;
                 DeleteCI(iterator);
-                inc(iterator^.dY.QWordValue,10);
+                //inc(iterator^.dY.QWordValue,10);
                 end;
             iterator:= iterator^.NextGear
             end;