hedgewars/GSHandlers.inc
changeset 7439 0a494f951dcf
parent 7426 55b49cc1f33a
child 7468 1333ca7554dc
--- a/hedgewars/GSHandlers.inc	Thu Jul 26 11:01:32 2012 +0200
+++ b/hedgewars/GSHandlers.inc	Thu Jul 26 11:10:56 2012 +0200
@@ -116,12 +116,12 @@
         
     if lastGearByUID = HH^.Gear then
         lastGearByUID := nil;
-        
-    RemoveGearFromList(HH^.Gear);
+    
+    HH^.Gear^.Message:= HH^.Gear^.Message or gmRemoveFromList;
     with HH^.Gear^ do
         begin
         Z := cHHZ;
-        Active := false;
+        HH^.Gear^.Active:= false;
         State:= State and (not (gstHHDriven or gstAttacking or gstAttacked));
         Message := Message and (not gmAttack);
     end;
@@ -733,7 +733,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepGrave(Gear: PGear);
 begin
+    if (Gear^.Message and gmDestroy) <> 0 then
+        begin
+        DeleteGear(Gear);
+        exit
+        end;
+
     AllInactive := false;
+
     if Gear^.dY.isNegative then
         if TestCollisionY(Gear, -1) then
             Gear^.dY := _0;
@@ -2080,6 +2087,7 @@
     dX, dY: HWFloat;
     hog: PHedgehog;
     sparkles: PVisualGear;
+    gi: PGear;
 begin
     k := Gear^.Kind;
     exBoom := false;
@@ -2114,21 +2122,37 @@
         end
     else
         begin 
+        if (Gear^.Pos <> posCaseHealth) and (GameTicks and $3FF = 0) then // stir it up every second or so
+            begin
+            gi := GearsList;
+            while gi <> nil do
+                begin
+                if gi^.Kind = gtGenericFaller then
+                    begin
+                    gi^.Active:= true;
+                    gi^.X:=  int2hwFloat(GetRandom(rightX-leftX)+leftX);
+                    gi^.Y:=  int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
+                    gi^.dX:= _90-(GetRandomf*_360);
+                    gi^.dY:= _90-(GetRandomf*_360)
+                    end;
+                gi := gi^.NextGear
+                end
+            end;
+
         if Gear^.Timer = 500 then
             begin
 (* Can't make sparkles team coloured without working out what the next team is going to be. This should be solved, really, since it also screws up
    voices. Reinforcements voices is heard for active team, not team-to-be.  Either that or change crate spawn from end of turn to start, although that
    has its own complexities. *)
             // Abuse a couple of gear values to track origin
-            Gear^.Angle:= hwRound(Gear^.X);
-            Gear^.Power:= hwRound(Gear^.Y);
+            Gear^.Angle:= hwRound(Gear^.Y);
             Gear^.Tag:= random(2);
             inc(Gear^.Timer)
             end;
         if Gear^.Timer < 1833 then inc(Gear^.Timer);
         if Gear^.Timer = 1000 then
             begin
-            sparkles:= AddVisualGear(Gear^.Angle, Gear^.Power, vgtDust, 1);
+            sparkles:= AddVisualGear(hwRound(Gear^.X), Gear^.Angle, vgtDust, 1);
             if sparkles <> nil then
                 begin
                 sparkles^.dX:= 0;
@@ -2382,7 +2406,7 @@
                 //DrawExplosion(gX, gY, 4);
                 
                 if ((GameTicks and $7) = 0) and (Random(2) = 0) then
-                    for i:= 1 to Random(2)+1 do
+                    for i:= Random(2) downto 0 do
                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
                         
                 if Gear^.Health > 0 then
@@ -2396,7 +2420,7 @@
                     begin
                     DrawExplosion(gX, gY, 4);
 
-                    for i:= 0 to Random(3) do
+                    for i:= Random(3) downto 0 do
                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
                     end;
 
@@ -2414,20 +2438,12 @@
         if not sticky then
             begin
             if ((GameTicks and $3) = 0) and (Random(1) = 0) then
-                begin
-                for i:= 1 to Random(2)+1 do
-                    begin
+                for i:= Random(2) downto 0 do
                     AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
-                    end;
-                end;
             end
         else
-            begin
-            for i:= 0 to Random(3) do
-                begin
+            for i:= Random(3) downto 0 do
                 AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
-                end;
-            end;
 
         DeleteGear(Gear)
         end;
@@ -2751,16 +2767,17 @@
 procedure doStepSwitcherWork(Gear: PGear);
 var 
     HHGear: PGear;
+    hedgehog: PHedgehog;
     State: Longword;
 begin
     AllInactive := false;
 
     if ((Gear^.Message and (not gmSwitch)) <> 0) or (TurnTimeLeft = 0) then
         begin
-        HHGear := Gear^.Hedgehog^.Gear;
+        hedgehog := Gear^.Hedgehog;
         //Msg := Gear^.Message and (not gmSwitch);
         DeleteGear(Gear);
-        ApplyAmmoChanges(HHGear^.Hedgehog^);
+        ApplyAmmoChanges(hedgehog^);
 
         HHGear := CurrentHedgehog^.Gear;
         ApplyAmmoChanges(HHGear^.Hedgehog^);
@@ -2775,10 +2792,9 @@
         Gear^.Message := Gear^.Message and (not gmSwitch);
         State := HHGear^.State;
         HHGear^.State := 0;
+        HHGear^.Z := cHHZ;
         HHGear^.Active := false;
-        HHGear^.Z := cHHZ;
-        RemoveGearFromList(HHGear);
-        InsertGearToList(HHGear);
+        HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
 
         PlaySound(sndSwitchHog);
 
@@ -2794,8 +2810,7 @@
         HHGear^.Active := true;
         FollowGear := HHGear;
         HHGear^.Z := cCurrHHZ;
-        RemoveGearFromList(HHGear);
-        InsertGearToList(HHGear);
+        HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
         Gear^.X := HHGear^.X;
         Gear^.Y := HHGear^.Y
         end;
@@ -2940,7 +2955,7 @@
                         end
                 end;
         AfterAttack;
-        DeleteGear(HHGear);
+        HHGear^.Message:= HHGear^.Message or gmDestroy;
         DeleteGear(Gear);
     end
     else
@@ -2984,7 +2999,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 const cakeh =   27;
-    cakeDmg =   75;
 var 
     CakePoints: array[0..Pred(cakeh)] of record
         x, y: hwFloat;
@@ -3054,20 +3068,10 @@
 end;
 
 
-procedure PrevAngle(Gear: PGear; dA: LongInt);
-begin
-    Gear^.Angle := (LongInt(Gear^.Angle) + 4 - dA) mod 4
-end;
-
-procedure NextAngle(Gear: PGear; dA: LongInt);
-begin
-    Gear^.Angle := (LongInt(Gear^.Angle) + 4 + dA) mod 4
-end;
-
 procedure doStepCakeWork(Gear: PGear);
 
 const dirs: array[0..3] of TPoint =   ((X: 0; Y: -1), (X: 1; Y: 0),(X: 0; Y: 1),(X: -1; Y: 0));
-var 
+var
     xx, yy, xxn, yyn: LongInt;
     dA: LongInt;
     tdx, tdy: hwFloat;
@@ -3078,39 +3082,20 @@
     if Gear^.Tag < 7 then
         exit;
 
-    dA := hwSign(Gear^.dX);
-    xx := dirs[Gear^.Angle].x;
-    yy := dirs[Gear^.Angle].y;
-    xxn := dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].x;
-    yyn := dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].y;
-
-    if (xx = 0) then
-        if TestCollisionYwithGear(Gear, yy) <> 0 then
-            PrevAngle(Gear, dA)
-    else
-        begin
-        Gear^.Tag := 0;
-        Gear^.Y := Gear^.Y + int2hwFloat(yy);
-        if not TestCollisionXwithGear(Gear, xxn) then
-            begin
-            Gear^.X := Gear^.X + int2hwFloat(xxn);
-            NextAngle(Gear, dA)
-            end;
+    dec(Gear^.Health);
+    Gear^.Timer := Gear^.Health*10;
+    if Gear^.Health mod 100 = 0 then
+        Gear^.PortalCounter:= 0;
+    // This is not seconds, but at least it is *some* feedback
+    if (Gear^.Health = 0) or ((Gear^.Message and gmAttack) <> 0) then
+        begin
+        FollowGear := Gear;
+        Gear^.RenderTimer := false;
+        Gear^.doStep := @doStepCakeDown;
+        exit
         end;
 
-    if (yy = 0) then
-        if TestCollisionXwithGear(Gear, xx) then
-            PrevAngle(Gear, dA)
-    else
-        begin
-        Gear^.Tag := 0;
-        Gear^.X := Gear^.X + int2hwFloat(xx);
-        if TestCollisionYwithGear(Gear, yyn) = 0 then
-            begin
-            Gear^.Y := Gear^.Y + int2hwFloat(yyn);
-            NextAngle(Gear, dA)
-            end;
-        end;
+    cakeStep(Gear);
 
     if Gear^.Tag = 0 then
         begin
@@ -3121,18 +3106,6 @@
         CakePoints[CakeI].y := Gear^.Y;
         Gear^.DirAngle := DxDy2Angle(tdx, tdy);
         end;
-
-    dec(Gear^.Health);
-    Gear^.Timer := Gear^.Health*10;
-    if Gear^.Health mod 100 = 0 then
-        Gear^.PortalCounter:= 0;
-    // This is not seconds, but at least it is *some* feedback
-    if (Gear^.Health = 0) or ((Gear^.Message and gmAttack) <> 0) then
-        begin
-        FollowGear := Gear;
-        Gear^.RenderTimer := false;
-        Gear^.doStep := @doStepCakeDown
-        end
 end;
 
 procedure doStepCakeUp(Gear: PGear);
@@ -3193,23 +3166,22 @@
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepSeductionWork(Gear: PGear);
 var i: LongInt;
-    hogs: TPGearArray;
+    hogs: PGearArrayS;
 begin
     AllInactive := false;
     hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius);
-    if Length(hogs) > 0 then
-        begin
-        for i:= 0 to Length(hogs) - 1 do
-            begin
-            if hogs[i] <> CurrentHedgehog^.Gear then
+    if hogs.size > 0 then
+        begin
+        for i:= 0 to hogs.size - 1 do
+            with hogs.ar^[i]^ do
                 begin
-                //d:= Distance(Gear^.X - hogs[i]^.X, Gear^.Y - hogs[i]^.Y);
-                hogs[i]^.dX:= _50 * cGravity * (Gear^.X - hogs[i]^.X) / _25;
-                //if Gear^.X < hogs[i]^.X then hogs[i]^.dX.isNegative:= true;
-                hogs[i]^.dY:= -_450 * cGravity;
-                hogs[i]^.Active:= true;
-                end
-            end;
+                if hogs.ar^[i] <> CurrentHedgehog^.Gear then
+                    begin
+                    dX:= _50 * cGravity * (Gear^.X - X) / _25;
+                    dY:= -_450 * cGravity;
+                    Active:= true;
+                    end
+                end;
         end ;
         AfterAttack;
         DeleteGear(Gear);
@@ -3331,10 +3303,10 @@
         if (Gear^.Timer mod 30) = 0 then
             AddVisualGear(hwRound(Gear^.X + _20 * Gear^.dX), hwRound(Gear^.Y + _20 * Gear^.dY), vgtDust);
         if (CheckGearDrowning(Gear)) then
-           begin
+            begin
             StopSoundChan(Gear^.SoundChannel);
             exit
-    end
+        end
     end;
 
     if GameTicks > Gear^.FlightTime then
@@ -3425,8 +3397,9 @@
         end
     else if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Tag <> 0) then
         begin
-        if Gear^.Timer > 0 then dec(Gear^.Timer);
-        if Gear^.Timer = 0 then
+        if Gear^.Timer > 0 then 
+            dec(Gear^.Timer)
+        else
             begin
             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
             DeleteGear(Gear);
@@ -4338,7 +4311,7 @@
         and (CurAmmoGear^.Kind =gtRope) then
                CurAmmoGear^.PortalCounter:= 1;
 
-        if not isbullet
+        if not isbullet and (iterator^.State and gstInvisible = 0) 
         and (iterator^.Kind <> gtFlake) then
             FollowGear := iterator;
 
@@ -4417,7 +4390,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);
@@ -4697,11 +4670,13 @@
 
                     // add some fire to the tunnel
                     if getRandom(6) = 0 then
-                        AddGear(x - Gear^.Radius + LongInt(getRandom(2 * Gear^.Radius)), y -
-                        getRandom(Gear^.Radius + 1), gtFlame, gsttmpFlag, _0, _0, 0);
+                        begin
+                        tmp:= GetRandom(2 * Gear^.Radius);
+                        AddGear(x - Gear^.Radius + tmp, y - GetRandom(Gear^.Radius + 1), gtFlame, gsttmpFlag, _0, _0, 0)
+                        end
                     end;
 
-                if getRandom(100) = 0 then
+                if random(100) = 0 then
                     AddVisualGear(x, y, vgtSmokeTrace); 
                 end
                 else dec(Gear^.Health, 5); // if underwater get additional damage
@@ -5061,7 +5036,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepResurrectorWork(Gear: PGear);
 var
-    graves: TPGearArray;
+    graves: PGearArrayS;
     resgear: PGear;
     hh: PHedgehog;
     i: LongInt;
@@ -5096,7 +5071,7 @@
 
     graves := GearsNear(Gear^.X, Gear^.Y, gtGrave, Gear^.Radius);
 
-    if Length(graves) = 0 then
+    if graves.size = 0 then
         begin
         StopSoundChan(Gear^.SoundChannel);
         Gear^.Timer := 250;
@@ -5106,12 +5081,13 @@
 
     if ((Gear^.Message and gmAttack) <> 0) and (hh^.Gear^.Health > 0) and (TurnTimeLeft > 0) then
         begin
-        if Length(graves) <= Gear^.Tag then Gear^.Tag:= 0;
+        if graves.size <= Gear^.Tag then Gear^.Tag:= 0;
         dec(hh^.Gear^.Health);
         if (hh^.Gear^.Health = 0) and (hh^.Gear^.Damage = 0) then
             hh^.Gear^.Damage:= 1;
         RenderHealth(hh^);
-        inc(graves[Gear^.Tag]^.Health);
+        RecountTeamHealth(hh^.Team);
+        inc(graves.ar^[Gear^.Tag]^.Health);
         inc(Gear^.Tag)
 {-for i:= 0 to High(graves) do begin
             if hh^.Gear^.Health > 0 then begin
@@ -5123,19 +5099,20 @@
     else 
         begin
         // now really resurrect the hogs with the hp saved in the graves
-        for i:= 0 to Length(graves) - 1 do
-            if graves[i]^.Health > 0 then
+        for i:= 0 to graves.size - 1 do
+            if graves.ar^[i]^.Health > 0 then
                 begin
-                resgear := AddGear(hwRound(graves[i]^.X), hwRound(graves[i]^.Y), gtHedgehog, gstWait, _0, _0, 0);
-                resgear^.Hedgehog := graves[i]^.Hedgehog;
-                resgear^.Health := graves[i]^.Health;
-                PHedgehog(graves[i]^.Hedgehog)^.Gear := resgear;
-                DeleteGear(graves[i]);
+                resgear := AddGear(hwRound(graves.ar^[i]^.X), hwRound(graves.ar^[i]^.Y), gtHedgehog, gstWait, _0, _0, 0);
+                resgear^.Hedgehog := graves.ar^[i]^.Hedgehog;
+                resgear^.Health := graves.ar^[i]^.Health;
+                PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := resgear;
+                graves.ar^[i]^.Message:= graves.ar^[i]^.Message or gmDestroy;
+                graves.ar^[i]^.Active:= true;
                 RenderHealth(resgear^.Hedgehog^);
                 RecountTeamHealth(resgear^.Hedgehog^.Team);
                 resgear^.Hedgehog^.Effects[heResurrected]:= 1;
                 // only make hat-less hedgehogs look like zombies, preserve existing hats
-                
+
                 if resgear^.Hedgehog^.Hat = 'NoHat' then
                     LoadHedgehogHat(resgear, 'Reserved/Zombie');
                 end;
@@ -5152,18 +5129,18 @@
 
 procedure doStepResurrector(Gear: PGear);
 var
-    graves: TPGearArray;
+    graves: PGearArrayS;
     i: LongInt;
 begin
     AllInactive := false;
     graves := GearsNear(Gear^.X, Gear^.Y, gtGrave, Gear^.Radius);
 
-    if Length(graves) > 0 then
-        begin
-        for i:= 0 to Length(graves) - 1 do
+    if graves.size > 0 then
+        begin
+        for i:= 0 to graves.size - 1 do
             begin
-            PHedgehog(graves[i]^.Hedgehog)^.Gear := nil;
-            graves[i]^.Health := 0;
+            PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := nil;
+            graves.ar^[i]^.Health := 0;
             end;
         Gear^.doStep := @doStepResurrectorWork;
         end 
@@ -5482,7 +5459,7 @@
     HHGear, iter: PGear;
     ndX, ndY: hwFloat;
     i, t, gX, gY: LongInt;
-    hogs: TPGearArray;
+    hogs: PGearArrayS;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
     if (Gear^.Health = 0) or (HHGear = nil) or (HHGear^.Damage <> 0) then
@@ -5546,9 +5523,9 @@
 // freeze nearby hogs
                 if GameTicks mod 10 = 0 then dec(Gear^.Health);
                 hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius);
-                if Length(hogs) > 0 then
-                    for i:= 0 to Length(hogs) - 1 do
-                        if hogs[i] <> HHGear then
+                if hogs.size > 0 then
+                    for i:= 0 to hogs.size - 1 do
+                        if hogs.ar^[i] <> HHGear then
                             begin
                             //if Gear^.Hedgehog^.Effects[heFrozen]:= 0;
                             end;
@@ -5574,3 +5551,41 @@
         end
     end;
 end;
+
+procedure doStepAddAmmo(Gear: PGear);
+var a: TAmmoType;
+    gi: PGear;
+begin
+if Gear^.Timer > 0 then dec(Gear^.Timer)
+else
+    begin
+    if Gear^.Pos = posCaseUtility then
+        a:= GetUtility(Gear^.Hedgehog)
+    else
+        a:= GetAmmo(Gear^.Hedgehog);
+    CheckSum:= CheckSum xor GameTicks;
+    gi := GearsList;
+    while gi <> nil do
+        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);
+        gi := gi^.NextGear
+        end;
+    AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y));
+    DeleteGear(Gear)
+    end;
+end;
+
+procedure doStepGenericFaller(Gear: PGear);
+begin
+if Gear^.Timer < $FFFFFFFF then
+    if Gear^.Timer > 0 then
+        dec(Gear^.Timer)
+    else
+        begin
+        DeleteGear(Gear);
+        exit
+        end;
+    
+doStepFallingGear(Gear);
+end;