hedgewars/GSHandlers.inc
changeset 3428 46a2694867bc
parent 3424 5543340db663
child 3431 e36dffdf7b82
--- a/hedgewars/GSHandlers.inc	Wed May 05 22:03:10 2010 +0000
+++ b/hedgewars/GSHandlers.inc	Thu May 06 01:41:07 2010 +0000
@@ -3044,16 +3044,52 @@
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
+procedure doPortalColorSwitch();
+var flags: LongWord;
+begin
+   if (CurrentHedgehog <> nil)
+        and (CurrentHedgehog^.Gear <> nil)
+            and ((CurrentHedgehog^.Gear^.Message and gm_Switch) <> 0) then
+            With CurrentHedgehog^ do
+                if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
+                    begin
+                    CurrentHedgehog^.Gear^.Message:= CurrentHedgehog^.Gear^.Message and not gm_Switch;
+
+                    flags:= Ammo^[CurSlot, CurAmmo].Timer and not 2;
+                    if (flags and 1) = 0 then
+                        Ammo^[CurSlot, CurAmmo].Timer:= flags or 1
+                    else
+                        Ammo^[CurSlot, CurAmmo].Timer:= flags and not 1;
+                    end;
+end;
+
 procedure doStepPortal(Gear: PGear);
 var iterator, conPortal: PGear;
-    s, acptRadius: hwFloat;
+    s, acptRadius, cdxy: hwFloat;
     noTrap, hasdxy: Boolean;
 begin
+    doPortalColorSwitch();
+
     // destroy portal if ground it was attached too is gone
-    if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0 then deleteGear(Gear);
+    if ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0)
+    or (Gear^.Timer < 1)
+    or (hwRound(Gear^.Y) > cWaterLine) then
+        begin
+        deleteGear(Gear);
+        EXIT;
+        end;
+
+    if (TurnTimeLeft < 1)
+    or (Gear^.Health < 1) then
+        dec(Gear^.Timer);
+
+    if Gear^.Timer < 10000 then
+        gear^.RenderTimer:= true;
 
     // abort if there is no other portal connected to this one
-    if Gear^.IntersectGear = nil then
+    if (Gear^.IntersectGear = nil) then 
+        exit;
+    if ((Gear^.IntersectGear^.Tag and 1) = 0) then // or if it's still moving;
         exit;
 
     conPortal:= Gear^.IntersectGear;
@@ -3073,15 +3109,14 @@
 
         // don't port portals or other gear that wouldn't make sense
         if (iterator^.Kind = gtPortal)
+        or (iterator^.Kind = gtRope)
         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 //...
+        
+        // don't port hogs on rope
+        if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
+            and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtRope) then
                 continue;
-}
 
         if (iterator^.Radius > Gear^.Radius) then
             continue; // sorry, you're too fat!
@@ -3105,45 +3140,79 @@
             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;
- 
+            or ((conPortal^.dY.isNegative and not (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
+        // prevent getting stuck in a ground portal loop       
+        if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then
             continue;
-        
+
         iterator^.Active:= true;
         iterator^.State:= iterator^.State or gstMoving;
         DeleteCI(iterator);
 
-        s:= (_1+(Int2hwFloat(Gear^.Radius))) / Distance(conPortal^.dX, conPortal^.dY);
+// TODO: more accurate porting
+        cdxy:= Distance(conPortal^.dX, conPortal^.dY);
+        s:= (Int2hwFloat(Gear^.Radius)) / cdxy;
+
         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);
+
+        s:= Distance(iterator^.dX, iterator^.dY) / cdxy;
+
         iterator^.dX:= s * conPortal^.dX;
         iterator^.dY:= s * conPortal^.dY;
+
+        FollowGear:= iterator;
+
+        s:= _0_2 + _0_008 * Gear^.Health;
+        iterator^.dX:= s * iterator^.dX;
+        iterator^.dY:= s * iterator^.dY;
         
-        if iterator^.dY.isNegative and (iterator^.dY.QWordValue <> 0) then
-            iterator^.dY:= iterator^.dY + hwAbs(Int2hwFloat(iterator^.Radius) / iterator^.dY) * cGravity;
+        if Gear^.Health > 1 then
+            begin
+            dec(Gear^.Health);
+            dec(iterator^.Health);
+            end;
 
         // breaks (some) loops
         if Distance(iterator^.dX, iterator^.dY) > _0_96 then
             begin
             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);
+            s:= _0_96 / Distance(iterator^.dX, iterator^.dY);
             iterator^.dX:= s * iterator^.dX;
             iterator^.dY:= s * iterator^.dX;
             end;
-
-        iterator:= iterator^.NextGear;
         end;
 end;
 
 procedure doStepMovingPortal(Gear: PGear);
 var x, y, tx, ty: LongInt;//, bx, by, tangle: LongInt;
     s, dx, dy: hwFloat;
+
+procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
+var flags: LongWord;
 begin
+if CurrentHedgehog <> nil then
+    With CurrentHedgehog^ do
+        if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
+            begin
+            flags:= Ammo^[CurSlot, CurAmmo].Timer;
+
+            if destroyGear xor ((oldPortal^.Tag and 2) = 0) then
+                flags:= flags or 1
+            else
+                flags:= flags and not 1;
+
+            Ammo^[CurSlot, CurAmmo].Timer:= flags and not 2; // make the ball visible
+            end;
+
+if destroyGear then deleteGear(oldPortal);
+end;
+
+begin
+doPortalColorSwitch();
+
 Gear^.X:= Gear^.X + Gear^.dX;
 Gear^.Y:= Gear^.Y + Gear^.dY;
 x:= hwRound(Gear^.X);
@@ -3152,30 +3221,24 @@
 
 if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
     begin
-    if not calcSlopeTangent(Gear, x, y, tx, ty, 255) then
-        begin
-        deleteGear(Gear);
-        EXIT;
-        end;
-
-    // reject shots at too irregular terrain
-    if DistanceI(tx,ty) < _12 then
-        begin
-        deleteGear(Gear);
-        EXIT;
-    end;
+    if not calcSlopeTangent(Gear, x, y, tx, ty, 255)
+        or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
+            begin
+            loadNewPortalBall(Gear, true);
+            EXIT;
+            end;
     
-    // making a normal, normalized vector
+    // making a normalized normal vector
     s:= _1/DistanceI(tx,ty);
     dx:= -s * ty;
     dy:=  s * tx;
 
     // make sure the vector is pointing outwards
     if not (Gear^.dX*dx + Gear^.dY*dy).isNegative then
-    begin
+        begin
         dx:= -dx;
         dy:= -dy;
-    end;
+        end;
 
     Gear^.dX:= dx;
     Gear^.dY:= dy;
@@ -3183,33 +3246,60 @@
     Gear^.DirAngle:= DxDy2Angle(-dy,dx);
     if not Gear^.dX.isNegative then Gear^.DirAngle:= 180-Gear^.DirAngle;
 
-    if ((Gear^.IntersectGear <> nil) and (hwRound(Distance(Gear^.X - Gear^.IntersectGear^.X,Gear^.Y-Gear^.IntersectGear^.Y)) < Gear^.Radius*2)) 
+    if ((Gear^.IntersectGear = nil)
+    or (hwRound(Distance(Gear^.X - Gear^.IntersectGear^.X,Gear^.Y-Gear^.IntersectGear^.Y)) >= Gear^.Radius*2)) 
     then
         begin
-        if CurrentHedgehog <> nil then
-            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)
+        loadNewPortalBall(Gear, false);
+        inc(Gear^.Tag);
+        Gear^.doStep:= @doStepPortal;
         end
     else
-        begin
-        if CurrentHedgehog <> nil then
-            if Gear^.Tag = 2 then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1
-            else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2;
-        inc(Gear^.Tag);
-        Gear^.doStep:= @doStepPortal;
-        if Gear^.IntersectGear <> nil then Gear^.IntersectGear^.IntersectGear:= Gear;
-        end
+        loadNewPortalBall(Gear, true);
     end
-else if (y > cWaterLine + cVisibleWater + Gear^.Radius) or (y < -LAND_WIDTH) or (x > LAND_WIDTH + LAND_WIDTH) or (x < -LAND_WIDTH) then
+else if (y > cWaterLine) or (y < -LAND_WIDTH)
+     or (x > 2*LAND_WIDTH) or (x < -LAND_WIDTH) then
+        loadNewPortalBall(Gear, true);
+end;
+
+procedure doStepPortalShot(newPortal: PGear);
+var iterator: PGear;
+begin
+newPortal^.IntersectGear:= nil;
+
+if CurrentHedgehog <> nil then
+    With CurrentHedgehog^ do
     begin
-    if CurrentHedgehog <> nil then
-        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);
+    // make portal gun look unloaded
+    Ammo^[CurSlot, CurAmmo].Timer:= Ammo^[CurSlot, CurAmmo].Timer or 2;
+
+    // set portal to the currently chosen color
+    if ((Ammo^[CurSlot, CurAmmo].Timer and 1) <> 0) then
+        newPortal^.Tag:= newPortal^.Tag or 2;
+
+    iterator:= GearsList;
+    while iterator <> nil do
+        begin
+        if (iterator^.Kind = gtPortal) then
+            if (iterator <> newPortal) then
+                begin
+                if (iterator^.Tag and 2) = (newPortal^.Tag and 2) then
+                    begin
+                    iterator:= iterator^.PrevGear;
+                    deleteGear(iterator^.NextGear);
+                    continue;
+                    end
+                else
+                    begin // link portals with each other
+                    newPortal^.IntersectGear:= iterator;
+                    iterator^.IntersectGear:= newPortal;
+                    iterator^.Health:= newPortal^.Health;
+                    end;
+                end;
+        iterator:= iterator^.NextGear
+        end;
     end;
+newPortal^.doStep:= @doStepMovingPortal;
 end;
 
 procedure doStepPiano(Gear: PGear);