hedgewars/uGearsUtils.pas
branchios-develop
changeset 13413 ba39a1d396c0
parent 13407 06792533ef91
child 13568 470982c05f7e
--- a/hedgewars/uGearsUtils.pas	Sun Jun 10 18:56:51 2018 +0200
+++ b/hedgewars/uGearsUtils.pas	Sun Jun 10 19:12:26 2018 +0200
@@ -31,6 +31,8 @@
 procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword);
 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
+procedure HHHeal(Hedgehog: PHedgehog; healthBoost: Longword; showMessage: boolean; vgTint: Longword);
+procedure HHHeal(Hedgehog: PHedgehog; healthBoost: Longword; showMessage: boolean);
 procedure CheckHHDamage(Gear: PGear);
 procedure CalcRotationDirAngle(Gear: PGear);
 procedure ResurrectHedgehog(var gear: PGear);
@@ -38,12 +40,14 @@
 procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); inline;
 procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean);
 
+function  CheckGearNear(Kind: TGearType; X, Y: hwFloat; rX, rY: LongInt): PGear;
 function  CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear;
 function  CheckGearDrowning(var Gear: PGear): boolean;
 procedure CheckCollision(Gear: PGear); inline;
 procedure CheckCollisionWithLand(Gear: PGear); inline;
 
 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
+procedure AmmoShoveLine(Ammo: PGear; Damage, Power: LongInt; oX, oY, tX, tY: hwFloat);
 function  GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS;
 procedure SpawnBoxOfSmth;
 procedure ShotgunShot(Gear: PGear);
@@ -262,8 +266,7 @@
 end;
 
 procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
-var s: ansistring;
-    vampDmg, tmpDmg, i: Longword;
+var vampDmg, tmpDmg, i: Longword;
     vg: PVisualGear;
 begin
     if Damage = 0 then
@@ -287,22 +290,9 @@
                     // was considering pulsing on attack, Tiy thinks it should be permanent while in play
                     //CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State or gstVampiric;
                     inc(CurrentHedgehog^.Gear^.Health,vampDmg);
-                    s:= IntToStr(vampDmg);
-                    AddCaption(FormatA(trmsg[sidHealthGain], s), CurrentHedgehog^.Team^.Clan^.Color, capgrpAmmoinfo);
                     RenderHealth(CurrentHedgehog^);
                     RecountTeamHealth(CurrentHedgehog^.Team);
-                    i:= 0;
-                    while (i < vampDmg) and (i < 1000) do
-                        begin
-                        vg:= AddVisualGear(hwRound(CurrentHedgehog^.Gear^.X), hwRound(CurrentHedgehog^.Gear^.Y), vgtStraightShot);
-                        if vg <> nil then
-                            with vg^ do
-                                begin
-                                Tint:= $FF0000FF;
-                                State:= ord(sprHealth)
-                                end;
-                        inc(i, 5);
-                        end;
+                    HHHeal(CurrentHedgehog, vampDmg, true, $FF0000FF);
                     end
                 end;
             if (GameFlags and gfKarma <> 0) and (GameFlags and gfInvulnerable = 0) and
@@ -354,6 +344,7 @@
 HHGear^.Active:= true;
 end;
 
+// Play effects for hurt hedgehog
 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
 begin
 if Hedgehog^.Effects[heFrozen] <> 0 then exit;
@@ -378,6 +369,48 @@
     end
 end;
 
+{-
+Show heal particles and message at hog gear.
+Hedgehog: Hedgehog which gets the health boost
+healthBoost: Amount of added health added
+showMessage: Whether to show announcer message
+vgTint: Tint of heal particle
+-}
+procedure HHHeal(Hedgehog: PHedgehog; healthBoost: Longword; showMessage: boolean; vgTint: Longword);
+var i: LongInt;
+    vg: PVisualGear;
+    s: ansistring;
+begin
+    if healthBoost < 1 then
+        exit;
+
+    if showMessage then
+        begin
+        s:= IntToStr(healthBoost);
+        AddCaption(FormatA(trmsg[sidHealthGain], s), Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo)
+        end;
+
+    i:= 0;
+    // One particle for every 5 HP. Max. 200 particles
+    while (i < healthBoost) and (i < 1000) do
+        begin
+        vg:= AddVisualGear(hwRound(Hedgehog^.Gear^.X), hwRound(Hedgehog^.Gear^.Y), vgtStraightShot);
+        if vg <> nil then
+            with vg^ do
+                begin
+                Tint:= vgTint;
+                State:= ord(sprHealth)
+                end;
+        inc(i, 5)
+        end;
+end;
+
+// Shorthand for the same above, but with tint implied
+procedure HHHeal(Hedgehog: PHedgehog; healthBoost: Longword; showMessage: boolean);
+begin
+    HHHeal(Hedgehog, healthBoost, showMessage, $00FF00FF);
+end;
+
 procedure CheckHHDamage(Gear: PGear);
 var
     dmg: LongInt;
@@ -663,7 +696,8 @@
                     TurnTimeLeft := 0;
                 Gear^.RenderTimer := false;
                 if (Gear^.Kind <> gtSniperRifleShot) and (Gear^.Kind <> gtShotgunShot)
-                and (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot) then
+                and (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot)
+                and (Gear^.Kind <> gtMinigunBullet) then
                     if Gear^.Kind = gtHedgehog then
                         begin
                         if Gear^.Hedgehog^.Effects[heResurrectable] <> 0 then
@@ -992,20 +1026,48 @@
     end
 end;
 
-function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear;
+function CheckGearNear(Kind: TGearType; X, Y: hwFloat; rX, rY: LongInt): PGear;
 var t: PGear;
+	width: hwFloat;
 begin
 t:= GearsList;
 rX:= sqr(rX);
 rY:= sqr(rY);
+width:= int2hwFloat(RightX-LeftX);
+
+while t <> nil do
+    begin
+    if (t^.Kind = Kind) then
+        if (not ((hwSqr(X - t^.X) / rX + hwSqr(Y - t^.Y) / rY) > _1)) or
+        ((WorldEdge = weWrap) and (
+        (not ((hwSqr(X - width - t^.X) / rX + hwSqr(Y - t^.Y) / rY) > _1)) or
+        (not ((hwSqr(X + width - t^.X) / rX + hwSqr(Y - t^.Y) / rY) > _1)))) then
+        begin
+            CheckGearNear:= t;
+            exit;
+        end;
+    t:= t^.NextGear
+    end;
+
+CheckGearNear:= nil
+end;
+
+function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear;
+var t: PGear;
+	width: hwFloat;
+begin
+t:= GearsList;
+rX:= sqr(rX);
+rY:= sqr(rY);
+width:= int2hwFloat(RightX-LeftX);
 
 while t <> nil do
     begin
     if (t <> Gear) and (t^.Kind = Kind) then
         if (not ((hwSqr(Gear^.X - t^.X) / rX + hwSqr(Gear^.Y - t^.Y) / rY) > _1)) or
         ((WorldEdge = weWrap) and (
-        (not ((hwSqr(Gear^.X - int2hwFloat(RightX-LeftX) - t^.X) / rX + hwSqr(Gear^.Y - t^.Y) / rY) > _1)) or
-        (not ((hwSqr(Gear^.X + int2hwFloat(RightX-LeftX) - t^.X) / rX + hwSqr(Gear^.Y - t^.Y) / rY) > _1)))) then
+        (not ((hwSqr(Gear^.X - width - t^.X) / rX + hwSqr(Gear^.Y - t^.Y) / rY) > _1)) or
+        (not ((hwSqr(Gear^.X + width - t^.X) / rX + hwSqr(Gear^.Y - t^.Y) / rY) > _1)))) then
         begin
             CheckGearNear:= t;
             exit;
@@ -1117,6 +1179,7 @@
         gtHedgehog,
             gtMine,
             gtSMine,
+            gtAirMine,
             gtKnife,
             gtCase,
             gtTarget,
@@ -1190,7 +1253,7 @@
     usable:= true;
     HH:= HHGear^.Hedgehog;
     if HHGear <> nil then
-    if (HHGear = nil) or (HH^.King) or (SuddenDeathDmg) then
+    if (HHGear = nil) or (HH^.King) or (SuddenDeathActive) then
         usable:= false;
     cnt:= 0;
     for j:= 0 to Pred(HH^.Team^.Clan^.TeamsNumber) do
@@ -1204,13 +1267,14 @@
     CanUseTardis:= usable;
 end;
 
-procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
+procedure AmmoShoveImpl(Ammo: PGear; Damage, Power: LongInt; collisions: PGearArray);
 var t: PGearArray;
     Gear: PGear;
     i, j, tmpDmg: LongInt;
     VGear: PVisualGear;
 begin
-t:= CheckGearsCollision(Ammo);
+t:= collisions;
+
 // Just to avoid hogs on rope dodging fire.
 if (CurAmmoGear <> nil) and ((CurAmmoGear^.Kind = gtRope) or (CurAmmoGear^.Kind = gtJetpack) or (CurAmmoGear^.Kind = gtBirdy))
 and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.CollisionIndex = -1)
@@ -1228,18 +1292,22 @@
     begin
     dec(i);
     Gear:= t^.ar[i];
-    if (Ammo^.Data <> nil) and (Ammo^.Kind in [gtDEagleShot, gtSniperRifleShot]) and (PGear(Ammo^.Data) = Gear) then
+    if (Ammo^.Kind in [gtDEagleShot, gtSniperRifleShot, gtMinigunBullet])
+        and (((Ammo^.Data <> nil) and (PGear(Ammo^.Data) = Gear))
+             or (not UpdateHitOrder(Gear, Ammo^.WDTimer))) then
         continue;
+
     if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and
-       (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then
+    (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then
         Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000);
     tmpDmg:= ModifyDamage(Damage, Gear);
     if (Gear^.State and gstNoDamage) = 0 then
         begin
 
-        if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then
+        if (not (Gear^.Kind in [gtMinigun, gtPortal])) and
+            (Ammo^.Kind in [gtDEagleShot, gtSniperRifleShot, gtMinigunBullet]) then
             begin
-            VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit);
+            VGear := AddVisualGear(t^.cX[i], t^.cY[i], vgtBulletHit);
             if VGear <> nil then
                 VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
             end;
@@ -1251,6 +1319,7 @@
         case Gear^.Kind of
             gtHedgehog,
             gtMine,
+            gtAirMine,
             gtSMine,
             gtKnife,
             gtTarget,
@@ -1268,7 +1337,10 @@
                 if (Ammo^.Kind = gtKnife) and (tmpDmg > 0) then
                     for j:= 1 to max(1,min(3,tmpDmg div 5)) do
                         begin
-                        VGear:= AddVisualGear(hwRound(Ammo^.X-((Ammo^.X-Gear^.X)/_2)), hwRound(Ammo^.Y-((Ammo^.Y-Gear^.Y)/_2)), vgtStraightShot);
+                        VGear:= AddVisualGear(
+                            t^.cX[i] - ((t^.cX[i] - hwround(Gear^.X)) div 2),
+                            t^.cY[i] - ((t^.cY[i] - hwround(Gear^.Y)) div 2),
+                            vgtStraightShot);
                         if VGear <> nil then
                             with VGear^ do
                                 begin
@@ -1297,13 +1369,13 @@
 
             if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
                 begin
-                Gear^.dX:= Ammo^.dX * Power * _0_005;
-                Gear^.dY:= Ammo^.dY * Power * _0_005
+                Gear^.dX:= Gear^.dX + Ammo^.dX * Power * _0_005;
+                Gear^.dY:= Gear^.dY + Ammo^.dY * Power * _0_005
                 end
             else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then
                 begin
-                Gear^.dX:= Ammo^.dX * Power * _0_01;
-                Gear^.dY:= Ammo^.dY * Power * _0_01
+                Gear^.dX:= Gear^.dX + Ammo^.dX * Power * _0_01;
+                Gear^.dY:= Gear^.dY + Ammo^.dY * Power * _0_01
                 end;
 
             if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
@@ -1338,6 +1410,19 @@
     SetAllToActive
 end;
 
+procedure AmmoShoveLine(Ammo: PGear; Damage, Power: LongInt; oX, oY, tX, tY: hwFloat);
+var t: PGearArray;
+begin
+    t:= CheckAllGearsLineCollision(Ammo, oX, oY, tX, tY);
+    AmmoShoveImpl(Ammo, Damage, Power, t);
+end;
+
+procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
+begin
+    AmmoShoveImpl(Ammo, Damage, Power,
+        CheckGearsCollision(Ammo));
+end;
+
 
 function CountGears(Kind: TGearType): Longword;
 var t: PGear;
@@ -1423,7 +1508,6 @@
     GearsNear.ar:= @GearsNearArray
 end;
 
-
 procedure SpawnBoxOfSmth;
 var t, aTot, uTot, a, h: LongInt;
     i: TAmmoType;
@@ -1578,9 +1662,6 @@
 if (hwRound(Gear^.X) < LongInt(leftX)) or
    (hwRound(Gear^.X) > LongInt(rightX)) then
     begin
-    // bullets can now hurt the hog that fired them
-    if (WorldEdge <> weSea) and (Gear^.Kind in [gtDEagleShot, gtSniperRifleShot]) then
-        Gear^.Data:= nil;
     if WorldEdge = weWrap then
         begin
         if (hwRound(Gear^.X) < LongInt(leftX)) then