hedgewars/GSHandlers.inc
changeset 3422 41ae3c48faa0
parent 3419 b66a1b597f88
child 3423 39e3c8f2e52a
--- a/hedgewars/GSHandlers.inc	Tue May 04 17:03:38 2010 +0000
+++ b/hedgewars/GSHandlers.inc	Tue May 04 19:40:57 2010 +0000
@@ -3042,40 +3042,99 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepPortal(Gear: PGear);
-var iterator: PGear;
-    s: hwFloat;
+var iterator, conPortal: PGear;
+    s, acptRadius: hwFloat;
+    noTrap, hasdxy: Boolean;
 begin
-    if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0 then
+    // destroy portal if ground it was attached too is gone
+    if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0 then deleteGear(Gear);
+
+    // abort if there is no other portal connected to this one
+    if Gear^.IntersectGear = nil then
+        exit;
+
+    conPortal:= Gear^.IntersectGear;
+
+    // check all gears for stuff to port through
+    iterator:= nil;
+    while true do
         begin
-        if Gear^.IntersectGear <> nil then Gear^.IntersectGear^.IntersectGear:= nil;
-        DeleteGear(Gear);
-        EXIT;
-        end;
+
+        if iterator = nil then
+            iterator:= GearsList // start
+        else
+            iterator:= iterator^.NextGear; // iterate through GearsList
         
-    if Gear^.IntersectGear <> nil then
-    //if (Gear^.IntersectGear <> nil) then
-        begin
-        iterator:= GearsList;
-        while iterator <> nil do
+        if iterator = nil then
+            break; // end of list
+
+        // don't port portals or other gear that wouldn't make sense
+        if (iterator^.Kind = gtPortal)
+        or (iterator^.Kind = gtHealthTag) then
+            continue;
+
+{
+        if (((iterator^.State and gstMoving) = 0) // we don't port non-moving stuff IF the portal entry...
+            and (iterator^.Active = false)
+            and ) then //...
+                continue;
+}
+
+        if (iterator^.Radius > Gear^.Radius) then
+            continue; // sorry, you're too fat!
+
+        // this is the range we accept incoming gears in
+        acptRadius:= Int2hwFloat(iterator^.Radius+Gear^.Radius);
+
+        if (iterator^.X < Gear^.X - acptRadius)
+        or (iterator^.X > Gear^.X + acptRadius)
+        or (iterator^.Y < Gear^.Y - acptRadius)
+        or (iterator^.Y > Gear^.Y + acptRadius) then
+            continue; // too far away!
+
+        hasdxy:= ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0));
+
+        if hasdxy and not (Gear^.dX*iterator^.dX + Gear^.dY*iterator^.dY).isNegative then
+            continue; // won't port stuff that moves away from me!
+
+        // wow! good candidate there, let's see if the distance really is small enough!
+        if (Distance(Gear^.X-iterator^.X,Gear^.Y-iterator^.Y) > acptRadius) then
+            continue;
+
+        noTrap:= ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0)) // can't be entered from above
+            or ((conPortal^.dY.isNegative or (conPortal^.dY.QWordValue = 0)))); // can't be left downwards;
+ 
+ 
+        // lets see if this one is just stuck in a stuck-loop       
+        if noTrap and (iterator^.dY.QWordValue < _0_1.QWordValue) then
+            continue;
+        
+        iterator^.Active:= true;
+        iterator^.State:= iterator^.State or gstMoving;
+        DeleteCI(iterator);
+
+        s:= (_1+(Int2hwFloat(Gear^.Radius))) / Distance(conPortal^.dX, conPortal^.dY);
+        iterator^.X:= conPortal^.X + s * conPortal^.dX;
+        iterator^.Y:= conPortal^.Y + s * conPortal^.dY;
+        s:= Distance(iterator^.dX, iterator^.dY) / Distance(conPortal^.dX, conPortal^.dY);
+        iterator^.dX:= s * conPortal^.dX;
+        iterator^.dY:= s * conPortal^.dY;
+        
+        if iterator^.dY.isNegative and (iterator^.dY.QWordValue <> 0) then
+            iterator^.dY:= iterator^.dY + hwAbs(Int2hwFloat(iterator^.Radius) / iterator^.dY) * cGravity;
+
+        // breaks (some) loops
+        if Distance(iterator^.dX, iterator^.dY) > _0_96 then
             begin
-            if (iterator^.Kind <> gtPortal) and (iterator^.PortedCounter < 20) then
-                if (((iterator^.State and gstMoving) <> 0) or (Gear^.IntersectGear^.dY.isNegative and not Gear^.dY.isNegative))
-                    and (hwRound(Distance(Gear^.X-iterator^.X,Gear^.Y-iterator^.Y)) < iterator^.Radius+Gear^.Radius) then // Let's check this one more closely
-                        if (Gear^.dX*iterator^.dX + Gear^.dY*iterator^.dY).isNegative then // make sure object moves towards the portal
-                            begin
-                            inc(iterator^.PortedCounter);
-                            s:= (_1+(Int2hwFloat(Gear^.Radius))) / Distance(Gear^.IntersectGear^.dX, Gear^.IntersectGear^.dY);
-                            iterator^.X:= Gear^.IntersectGear^.X + s * Gear^.IntersectGear^.dX;
-                            iterator^.Y:= Gear^.IntersectGear^.Y + s * Gear^.IntersectGear^.dY;
-                            s:= Distance(iterator^.dX, iterator^.dY) / Distance(Gear^.IntersectGear^.dX, Gear^.IntersectGear^.dY);
-                            iterator^.dX:= s * Gear^.IntersectGear^.dX;
-                            iterator^.dY:= s * Gear^.IntersectGear^.dY;
-                            end;    
-
-            iterator:= iterator^.NextGear;
+            iterator^.dX:= iterator^.dX + signAs(cGravity * getRandom(1000),iterator^.dX);
+            iterator^.dY:= iterator^.dY + signAs(cGravity * getRandom(1000),iterator^.dY);
+            s:= _0_995 / Distance(iterator^.dX, iterator^.dY);
+            iterator^.dX:= s * iterator^.dX;
+            iterator^.dY:= s * iterator^.dX;
             end;
-// do portal stuff
-        end
+
+        iterator:= iterator^.NextGear;
+        end;
 
 (*
 
@@ -3086,7 +3145,6 @@
 
 procedure doStepMovingPortal(Gear: PGear);
 var x, y, tx, ty: LongInt;//, bx, by, tangle: LongInt;
-    iterator: PGear;
     s, dx, dy: hwFloat;
 begin
 Gear^.X:= Gear^.X + Gear^.dX;
@@ -3099,14 +3157,14 @@
     begin
     if not calcSlopeTangent(Gear, x, y, tx, ty, 255) then
         begin
-        DeleteGear(Gear);
+        deleteGear(Gear);
         EXIT;
         end;
 
     // reject shots at too irregular terrain
-    if DistanceI(tx,ty) < _10 then
+    if DistanceI(tx,ty) < _12 then
         begin
-        DeleteGear(Gear);
+        deleteGear(Gear);
         EXIT;
     end;
     
@@ -3151,7 +3209,7 @@
             if Gear^.IntersectGear = nil then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1
             else if Gear^.Tag = 2 then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2
             else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1;
-        DeleteGear(Gear)
+        deleteGear(Gear)
         end
     else
         begin
@@ -3160,27 +3218,7 @@
             else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2;
         inc(Gear^.Tag);
         Gear^.doStep:= @doStepPortal;
-        if Gear^.IntersectGear <> nil then
-            begin
-            Gear^.IntersectGear^.IntersectGear:= Gear;
-            AllInactive:= false;
-            // This jiggles gears, to ensure a portal connection just placed under a gear takes effect.
-            iterator:= GearsList;
-            while iterator <> nil do
-                begin
-                if iterator^.Kind <> gtPortal then
-                    begin
-                    iterator^.Active:= true;
-                    if iterator^.dY.QWordValue = _0.QWordValue then iterator^.dY.isNegative:= false;
-                    iterator^.State:= iterator^.State or gstMoving;
-                    DeleteCI(iterator);
-                    inc(iterator^.dY.QWordValue,10);
-                    end;
-                iterator:= iterator^.NextGear
-                end;
-            doStepPortal(Gear);
-            if Gear^.IntersectGear <> nil then Gear^.IntersectGear^.doStep(Gear^.IntersectGear);
-            end
+        if Gear^.IntersectGear <> nil then Gear^.IntersectGear^.IntersectGear:= Gear;
         end
     end
 else if (y > cWaterLine + cVisibleWater + Gear^.Radius) or (y < -LAND_WIDTH) or (x > LAND_WIDTH + LAND_WIDTH) or (x < -LAND_WIDTH) then
@@ -3189,7 +3227,7 @@
         if Gear^.IntersectGear = nil then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1
         else if Gear^.Tag = 2 then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2
         else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1;
-    DeleteGear(Gear);
+    deleteGear(Gear);
     end;
 end;