diff -r 6e8b807bda4b -r ba39a1d396c0 hedgewars/uGearsUtils.pas --- 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