23 uses uTypes, uFloat; |
23 uses uTypes, uFloat; |
24 |
24 |
25 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline; |
25 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline; |
26 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord); |
26 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord); |
27 procedure AddSplashForGear(Gear: PGear; justSkipping: boolean); |
27 procedure AddSplashForGear(Gear: PGear; justSkipping: boolean); |
|
28 procedure AddBounceEffectForGear(Gear: PGear; imageScale: Single); |
28 procedure AddBounceEffectForGear(Gear: PGear); |
29 procedure AddBounceEffectForGear(Gear: PGear); |
29 |
30 |
30 function ModifyDamage(dmg: Longword; Gear: PGear): Longword; |
31 function ModifyDamage(dmg: Longword; Gear: PGear): Longword; |
31 procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource); |
32 procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource); |
32 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword); |
33 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword); |
33 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource); |
34 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource; Damage: Longword); |
34 procedure HHHeal(Hedgehog: PHedgehog; healthBoost: Longword; showMessage: boolean; vgTint: Longword); |
35 procedure HHHeal(Hedgehog: PHedgehog; healthBoost: LongInt; showMessage: boolean; vgTint: Longword); |
35 procedure HHHeal(Hedgehog: PHedgehog; healthBoost: Longword; showMessage: boolean); |
36 procedure HHHeal(Hedgehog: PHedgehog; healthBoost: LongInt; showMessage: boolean); |
|
37 function IncHogHealth(Hedgehog: PHedgehog; healthBoost: LongInt): LongInt; |
36 procedure CheckHHDamage(Gear: PGear); |
38 procedure CheckHHDamage(Gear: PGear); |
37 procedure CalcRotationDirAngle(Gear: PGear); |
39 procedure CalcRotationDirAngle(Gear: PGear); |
38 procedure ResurrectHedgehog(var gear: PGear); |
40 procedure ResurrectHedgehog(var gear: PGear); |
39 |
41 |
40 procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); inline; |
42 procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); inline; |
41 procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean); |
43 procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean); |
42 |
44 |
|
45 function CheckGearNear(Kind: TGearType; X, Y: hwFloat; rX, rY: LongInt): PGear; |
43 function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear; |
46 function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear; |
44 function CheckGearDrowning(var Gear: PGear): boolean; |
47 function CheckGearDrowning(var Gear: PGear): boolean; |
45 procedure CheckCollision(Gear: PGear); inline; |
48 procedure CheckCollision(Gear: PGear); inline; |
46 procedure CheckCollisionWithLand(Gear: PGear); inline; |
49 procedure CheckCollisionWithLand(Gear: PGear); inline; |
47 |
50 |
48 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); |
51 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); |
|
52 procedure AmmoShoveCache(Ammo: PGear; Damage, Power: LongInt); |
49 procedure AmmoShoveLine(Ammo: PGear; Damage, Power: LongInt; oX, oY, tX, tY: hwFloat); |
53 procedure AmmoShoveLine(Ammo: PGear; Damage, Power: LongInt; oX, oY, tX, tY: hwFloat); |
50 function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; |
54 function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; |
51 procedure SpawnBoxOfSmth; |
55 function SpawnBoxOfSmth: PGear; |
|
56 procedure PlayBoxSpawnTaunt(Gear: PGear); |
52 procedure ShotgunShot(Gear: PGear); |
57 procedure ShotgunShot(Gear: PGear); |
53 function CanUseTardis(HHGear: PGear): boolean; |
58 function CanUseTardis(HHGear: PGear): boolean; |
54 |
59 |
55 procedure SetAllToActive; |
60 procedure SetAllToActive; |
56 procedure SetAllHHToActive(Ice: boolean); |
61 procedure SetAllHHToActive(Ice: boolean); |
174 Gear^.dY:= Gear^.dY + SignAs(_0_005 * dmg + cHHKick, tdY)/(Gear^.Density/_3); |
172 Gear^.dY:= Gear^.dY + SignAs(_0_005 * dmg + cHHKick, tdY)/(Gear^.Density/_3); |
175 |
173 |
176 Gear^.State:= (Gear^.State or gstMoving) and (not gstLoser); |
174 Gear^.State:= (Gear^.State or gstMoving) and (not gstLoser); |
177 if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and (not gstCollision); |
175 if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and (not gstCollision); |
178 if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heInvulnerable] = 0) then |
176 if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heInvulnerable] = 0) then |
179 Gear^.State:= (Gear^.State or gstMoving) and (not gstWinner); |
177 begin |
|
178 Gear^.State:= (Gear^.State or gstMoving) and (not (gstHHJumping or gstHHHJump)); |
|
179 if (not GameOver) then |
|
180 Gear^.State:= (Gear^.State and (not gstWinner)); |
|
181 end; |
180 Gear^.Active:= true; |
182 Gear^.Active:= true; |
181 if Gear^.Kind <> gtFlame then FollowGear:= Gear |
183 if Gear^.Kind <> gtFlame then FollowGear:= Gear; |
|
184 if Gear^.Kind = gtAirMine then |
|
185 begin |
|
186 Gear^.Tag:= 1; |
|
187 Gear^.FlightTime:= 5000; |
|
188 end |
182 end; |
189 end; |
183 if ((Mask and EXPLPoisoned) <> 0) and (Gear^.Kind = gtHedgehog) and |
190 if ((Mask and EXPLPoisoned) <> 0) and (Gear^.Kind = gtHedgehog) and |
184 (Gear^.Hedgehog^.Effects[heInvulnerable] = 0) and (Gear^.Hedgehog^.Effects[heFrozen] = 0) and |
191 (Gear^.Hedgehog^.Effects[heInvulnerable] = 0) and (Gear^.Hedgehog^.Effects[heFrozen] = 0) and |
185 (Gear^.State and gstHHDeath = 0) then |
192 (Gear^.State and gstHHDeath = 0) then |
186 begin |
193 begin |
187 if Gear^.Hedgehog^.Effects[hePoisoned] = 0 then |
194 if Gear^.Hedgehog^.Effects[hePoisoned] = 0 then |
188 begin |
195 begin |
189 s:= ansistring(Gear^.Hedgehog^.Name); |
196 s:= ansistring(Gear^.Hedgehog^.Name); |
190 AddCaption(FormatA(GetEventString(eidPoisoned), s), cWhiteColor, capgrpMessage); |
197 AddCaption(FormatA(GetEventString(eidPoisoned), s), capcolDefault, capgrpMessage); |
191 uStats.HedgehogPoisoned(Gear, AttackingHog) |
198 uStats.HedgehogPoisoned(Gear, AttackingHog) |
192 end; |
199 end; |
193 Gear^.Hedgehog^.Effects[hePoisoned] := 5; |
200 Gear^.Hedgehog^.Effects[hePoisoned] := 5; |
194 end |
201 end |
195 end; |
202 end; |
274 if (Gear^.Kind = gtHedgehog) then |
281 if (Gear^.Kind = gtHedgehog) then |
275 begin |
282 begin |
276 Gear^.LastDamage := AttackerHog; |
283 Gear^.LastDamage := AttackerHog; |
277 |
284 |
278 Gear^.Hedgehog^.Team^.Clan^.Flawless:= false; |
285 Gear^.Hedgehog^.Team^.Clan^.Flawless:= false; |
279 HHHurt(Gear^.Hedgehog, Source); |
286 |
280 AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), Damage, Gear^.Hedgehog^.Team^.Clan^.Color); |
287 if (Gear^.State and gstHHDeath) <> 0 then |
|
288 // If hog took damage while dying, explode hog instantly (see doStepHedgehogDead) |
|
289 Gear^.Timer:= 1 |
|
290 else |
|
291 begin |
|
292 HHHurt(Gear^.Hedgehog, Source, Damage); |
|
293 AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), Damage, Gear^.Hedgehog^.Team^.Clan^.Color); |
|
294 end; |
|
295 |
281 tmpDmg:= min(Damage, max(0,Gear^.Health-Gear^.Damage)); |
296 tmpDmg:= min(Damage, max(0,Gear^.Health-Gear^.Damage)); |
282 if (Gear <> CurrentHedgehog^.Gear) and (CurrentHedgehog^.Gear <> nil) and (tmpDmg >= 1) then |
297 if (Gear <> CurrentHedgehog^.Gear) and (CurrentHedgehog^.Gear <> nil) and (tmpDmg >= 1) then |
283 begin |
298 begin |
284 if cVampiric then |
299 if cVampiric then |
285 begin |
300 begin |
286 vampDmg:= hwRound(int2hwFloat(tmpDmg)*_0_8); |
301 vampDmg:= hwRound(int2hwFloat(tmpDmg)*_0_8); |
287 if vampDmg >= 1 then |
302 if vampDmg >= 1 then |
288 begin |
303 begin |
289 // was considering pulsing on attack, Tiy thinks it should be permanent while in play |
304 // was considering pulsing on attack, Tiy thinks it should be permanent while in play |
290 //CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State or gstVampiric; |
305 //CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State or gstVampiric; |
291 inc(CurrentHedgehog^.Gear^.Health,vampDmg); |
306 vampDmg:= IncHogHealth(CurrentHedgehog, vampDmg); |
292 RenderHealth(CurrentHedgehog^); |
307 RenderHealth(CurrentHedgehog^); |
293 RecountTeamHealth(CurrentHedgehog^.Team); |
308 RecountTeamHealth(CurrentHedgehog^.Team); |
294 HHHeal(CurrentHedgehog, vampDmg, true, $FF0000FF); |
309 HHHeal(CurrentHedgehog, vampDmg, true, $FF0000FF); |
295 end |
310 end |
296 end; |
311 end; |
303 end; |
318 end; |
304 end; |
319 end; |
305 |
320 |
306 uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false); |
321 uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false); |
307 |
322 |
308 if AprilOne and (Gear^.Hedgehog^.Hat = 'fr_tomato') and (Damage > 2) then |
323 if AprilOne and (Gear^.Hedgehog^.Hat = 'fr_tomato') and (Damage > 2) then |
309 for i := 0 to random(min(Damage,20))+5 do |
324 for i := 0 to random(min(Damage,20))+5 do |
310 begin |
325 begin |
311 vg:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot); |
326 vg:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot); |
312 if vg <> nil then |
327 if vg <> nil then |
313 with vg^ do |
328 with vg^ do |
314 begin |
329 begin |
315 dx:= 0.001 * (random(100)+10); |
330 dx:= 0.001 * (random(100)+10); |
316 dy:= 0.001 * (random(100)+10); |
331 dy:= 0.001 * (random(100)+10); |
317 tdy:= -cGravityf; |
332 tdy:= -cGravityf; |
318 if random(2) = 0 then |
333 if random(2) = 0 then |
319 dx := -dx; |
334 dx := -dx; |
320 //if random(2) = 0 then |
335 FrameTicks:= random(500) + 1000; |
321 // dy := -dy; |
336 State:= ord(sprBubbles); |
322 FrameTicks:= random(500) + 1000; |
337 Tint:= $ff0000ff |
323 State:= ord(sprBubbles); |
338 end |
324 //Tint:= $bd2f03ff |
339 end |
325 Tint:= $ff0000ff |
|
326 end |
|
327 end |
|
328 end else |
340 end else |
329 //else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure |
|
330 Gear^.Hedgehog:= AttackerHog; |
341 Gear^.Hedgehog:= AttackerHog; |
331 inc(Gear^.Damage, Damage); |
342 inc(Gear^.Damage, Damage); |
332 |
343 |
333 ScriptCall('onGearDamage', Gear^.UID, Damage); |
344 ScriptCall('onGearDamage', Gear^.UID, Damage); |
334 end; |
345 end; |
389 AddCaption(FormatA(trmsg[sidHealthGain], s), Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo) |
406 AddCaption(FormatA(trmsg[sidHealthGain], s), Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo) |
390 end; |
407 end; |
391 |
408 |
392 i:= 0; |
409 i:= 0; |
393 // One particle for every 5 HP. Max. 200 particles |
410 // One particle for every 5 HP. Max. 200 particles |
394 while (i < healthBoost) and (i < 1000) do |
411 if (vgTint <> 0) then |
395 begin |
412 while (i < healthBoost) and (i < 1000) do |
396 vg:= AddVisualGear(hwRound(Hedgehog^.Gear^.X), hwRound(Hedgehog^.Gear^.Y), vgtStraightShot); |
413 begin |
397 if vg <> nil then |
414 vg:= AddVisualGear(hwRound(Hedgehog^.Gear^.X), hwRound(Hedgehog^.Gear^.Y), vgtStraightShot); |
398 with vg^ do |
415 if vg <> nil then |
399 begin |
416 with vg^ do |
400 Tint:= vgTint; |
417 begin |
401 State:= ord(sprHealth) |
418 Tint:= vgTint; |
402 end; |
419 State:= ord(sprHealth) |
403 inc(i, 5) |
420 end; |
404 end; |
421 inc(i, 5) |
|
422 end; |
405 end; |
423 end; |
406 |
424 |
407 // Shorthand for the same above, but with tint implied |
425 // Shorthand for the same above, but with tint implied |
408 procedure HHHeal(Hedgehog: PHedgehog; healthBoost: Longword; showMessage: boolean); |
426 procedure HHHeal(Hedgehog: PHedgehog; healthBoost: LongInt; showMessage: boolean); |
409 begin |
427 begin |
410 HHHeal(Hedgehog, healthBoost, showMessage, $00FF00FF); |
428 HHHeal(Hedgehog, healthBoost, showMessage, $00FF00FF); |
|
429 end; |
|
430 |
|
431 // Increase hog health by healthBoost (at least 1). |
|
432 // Resulting health is capped at cMaxHogHealth. |
|
433 // Returns actual amount healed. |
|
434 function IncHogHealth(Hedgehog: PHedgehog; healthBoost: LongInt): LongInt; |
|
435 var oldHealth: LongInt; |
|
436 begin |
|
437 if healthBoost < 1 then |
|
438 begin |
|
439 IncHogHealth:= 0; |
|
440 exit; |
|
441 end; |
|
442 oldHealth:= Hedgehog^.Gear^.Health; |
|
443 inc(Hedgehog^.Gear^.Health, healthBoost); |
|
444 // Prevent overflow |
|
445 if (Hedgehog^.Gear^.Health < 1) or (Hedgehog^.Gear^.Health > cMaxHogHealth) then |
|
446 Hedgehog^.Gear^.Health:= cMaxHogHealth; |
|
447 IncHogHealth:= Hedgehog^.Gear^.Health - oldHealth; |
411 end; |
448 end; |
412 |
449 |
413 procedure CheckHHDamage(Gear: PGear); |
450 procedure CheckHHDamage(Gear: PGear); |
414 var |
451 var |
415 dmg: LongInt; |
452 dmg: LongInt; |
797 end; |
837 end; |
798 tempTeam := gear^.Hedgehog^.Team; |
838 tempTeam := gear^.Hedgehog^.Team; |
799 DeleteCI(gear); |
839 DeleteCI(gear); |
800 gX := hwRound(gear^.X); |
840 gX := hwRound(gear^.X); |
801 gY := hwRound(gear^.Y); |
841 gY := hwRound(gear^.Y); |
802 // might need more sparkles for a column |
842 // Spawn a few sparkles at death position. |
|
843 // Might need more sparkles for a column. |
803 sparkles:= AddVisualGear(gX, gY, vgtDust, 1); |
844 sparkles:= AddVisualGear(gX, gY, vgtDust, 1); |
804 if sparkles <> nil then |
845 if sparkles <> nil then |
805 begin |
846 begin |
806 sparkles^.Tint:= tempTeam^.Clan^.Color shl 8 or $FF; |
847 sparkles^.Tint:= tempTeam^.Clan^.Color shl 8 or $FF; |
807 //sparkles^.Angle:= random(360); |
|
808 end; |
848 end; |
|
849 // Set new position of gear (might fail) |
809 FindPlace(gear, false, 0, LAND_WIDTH, true); |
850 FindPlace(gear, false, 0, LAND_WIDTH, true); |
810 if gear <> nil then |
851 if gear <> nil then |
811 begin |
852 begin |
812 AddVisualGear(hwRound(gear^.X), hwRound(gear^.Y), vgtExplosion); |
853 // Visual effect at position of resurrection |
|
854 expl:= AddVisualGear(hwRound(gear^.X), hwRound(gear^.Y), vgtExplosion); |
813 PlaySound(sndWarp); |
855 PlaySound(sndWarp); |
814 RenderHealth(gear^.Hedgehog^); |
856 RenderHealth(gear^.Hedgehog^); |
815 ScriptCall('onGearResurrect', gear^.uid); |
857 if expl <> nil then |
|
858 ScriptCall('onGearResurrect', gear^.uid, expl^.uid) |
|
859 else |
|
860 ScriptCall('onGearResurrect', gear^.uid); |
816 gear^.State := gstWait; |
861 gear^.State := gstWait; |
817 end; |
862 end; |
818 RecountTeamHealth(tempTeam); |
863 RecountTeamHealth(tempTeam); |
819 end; |
864 end; |
820 |
865 |
1023 Gear:= nil |
1068 Gear:= nil |
1024 end |
1069 end |
1025 end |
1070 end |
1026 end; |
1071 end; |
1027 |
1072 |
|
1073 function CheckGearNearImpl(Kind: TGearType; X, Y: hwFloat; rX, rY: LongInt; exclude: PGear): PGear; |
|
1074 var t: PGear; |
|
1075 width, bound, dX, dY: hwFloat; |
|
1076 isHit: Boolean; |
|
1077 i, j: LongWord; |
|
1078 begin |
|
1079 bound:= _1_5 * int2hwFloat(max(rX, rY)); |
|
1080 rX:= sqr(rX); |
|
1081 rY:= sqr(rY); |
|
1082 width:= int2hwFloat(RightX - LeftX); |
|
1083 if (Kind = gtHedgehog) then |
|
1084 begin |
|
1085 for j:= 0 to Pred(TeamsCount) do |
|
1086 if TeamsArray[j]^.TeamHealth > 0 then // it's impossible for a team to have hogs in game and zero health right? |
|
1087 with TeamsArray[j]^ do |
|
1088 for i:= 0 to cMaxHHIndex do |
|
1089 with Hedgehogs[i] do |
|
1090 if (Gear <> nil) and (Gear <> exclude) then |
|
1091 begin |
|
1092 // code duplication - could throw into an inline function I guess |
|
1093 dX := X - Gear^.X; |
|
1094 dY := Y - Gear^.Y; |
|
1095 isHit := (hwAbs(dX) + hwAbs(dY) < bound) |
|
1096 and (not ((hwSqr(dX) / rX + hwSqr(dY) / rY) > _1)); |
|
1097 |
|
1098 if (not isHit) and (WorldEdge = weWrap) then |
|
1099 begin |
|
1100 if (hwAbs(dX - width) + hwAbs(dY) < bound) |
|
1101 and (not ((hwSqr(dX - width) / rX + hwSqr(dY) / rY) > _1)) then |
|
1102 isHit := true |
|
1103 else if (hwAbs(dX + width) + hwAbs(dY) < bound) |
|
1104 and (not ((hwSqr(dX + width) / rX + hwSqr(dY) / rY) > _1)) then |
|
1105 isHit := true |
|
1106 end; |
|
1107 |
|
1108 if isHit then |
|
1109 begin |
|
1110 CheckGearNearImpl:= Gear; |
|
1111 exit; |
|
1112 end |
|
1113 end; |
|
1114 end |
|
1115 else |
|
1116 begin |
|
1117 t:= GearsList; |
|
1118 |
|
1119 while t <> nil do |
|
1120 begin |
|
1121 if (t <> exclude) and (t^.Kind = Kind) then |
|
1122 begin |
|
1123 dX := X - t^.X; |
|
1124 dY := Y - t^.Y; |
|
1125 isHit := (hwAbs(dX) + hwAbs(dY) < bound) |
|
1126 and (not ((hwSqr(dX) / rX + hwSqr(dY) / rY) > _1)); |
|
1127 |
|
1128 if (not isHit) and (WorldEdge = weWrap) then |
|
1129 begin |
|
1130 if (hwAbs(dX - width) + hwAbs(dY) < bound) |
|
1131 and (not ((hwSqr(dX - width) / rX + hwSqr(dY) / rY) > _1)) then |
|
1132 isHit := true |
|
1133 else if (hwAbs(dX + width) + hwAbs(dY) < bound) |
|
1134 and (not ((hwSqr(dX + width) / rX + hwSqr(dY) / rY) > _1)) then |
|
1135 isHit := true |
|
1136 end; |
|
1137 |
|
1138 if isHit then |
|
1139 begin |
|
1140 CheckGearNearImpl:= t; |
|
1141 exit; |
|
1142 end; |
|
1143 end; |
|
1144 t:= t^.NextGear |
|
1145 end |
|
1146 end; |
|
1147 |
|
1148 CheckGearNearImpl:= nil |
|
1149 end; |
|
1150 |
|
1151 function CheckGearNear(Kind: TGearType; X, Y: hwFloat; rX, rY: LongInt): PGear; |
|
1152 begin |
|
1153 CheckGearNear := CheckGearNearImpl(Kind, X, Y, rX, rY, nil); |
|
1154 end; |
|
1155 |
1028 function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear; |
1156 function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear; |
1029 var t: PGear; |
1157 begin |
1030 begin |
1158 CheckGearNear := CheckGearNearImpl(Kind, Gear^.X, Gear^.Y, rX, rY, Gear); |
1031 t:= GearsList; |
|
1032 rX:= sqr(rX); |
|
1033 rY:= sqr(rY); |
|
1034 |
|
1035 while t <> nil do |
|
1036 begin |
|
1037 if (t <> Gear) and (t^.Kind = Kind) then |
|
1038 if (not ((hwSqr(Gear^.X - t^.X) / rX + hwSqr(Gear^.Y - t^.Y) / rY) > _1)) or |
|
1039 ((WorldEdge = weWrap) and ( |
|
1040 (not ((hwSqr(Gear^.X - int2hwFloat(RightX-LeftX) - t^.X) / rX + hwSqr(Gear^.Y - t^.Y) / rY) > _1)) or |
|
1041 (not ((hwSqr(Gear^.X + int2hwFloat(RightX-LeftX) - t^.X) / rX + hwSqr(Gear^.Y - t^.Y) / rY) > _1)))) then |
|
1042 begin |
|
1043 CheckGearNear:= t; |
|
1044 exit; |
|
1045 end; |
|
1046 t:= t^.NextGear |
|
1047 end; |
|
1048 |
|
1049 CheckGearNear:= nil |
|
1050 end; |
1159 end; |
1051 |
1160 |
1052 procedure CheckCollision(Gear: PGear); inline; |
1161 procedure CheckCollision(Gear: PGear); inline; |
1053 begin |
1162 begin |
1054 if (TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0) |
1163 if (TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0) |
1260 Ammo^.Health:= 0; |
1375 Ammo^.Health:= 0; |
1261 while i > 0 do |
1376 while i > 0 do |
1262 begin |
1377 begin |
1263 dec(i); |
1378 dec(i); |
1264 Gear:= t^.ar[i]; |
1379 Gear:= t^.ar[i]; |
1265 if (Ammo^.Data <> nil) and (Ammo^.Kind in [gtDEagleShot, gtSniperRifleShot, gtMinigunBullet]) and (PGear(Ammo^.Data) = Gear) |
1380 if (Ammo^.Kind in [gtDEagleShot, gtSniperRifleShot, gtMinigunBullet, |
1266 or ((Ammo^.Kind = gtMinigunBullet) and (not UpdateHitOrder(Gear, Ammo^.WDTimer))) then |
1381 gtFirePunch, gtKamikaze, gtWhip, gtShover]) |
|
1382 and (((Ammo^.Data <> nil) and (PGear(Ammo^.Data) = Gear)) |
|
1383 or (not UpdateHitOrder(Gear, Ammo^.WDTimer))) then |
1267 continue; |
1384 continue; |
1268 |
1385 |
1269 if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and |
1386 if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and |
1270 (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then |
1387 (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then |
1271 Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000); |
1388 Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000); |
1272 tmpDmg:= ModifyDamage(Damage, Gear); |
1389 tmpDmg:= ModifyDamage(Damage, Gear); |
1273 if (Gear^.State and gstNoDamage) = 0 then |
1390 if (Gear^.State and gstNoDamage) = 0 then |
1274 begin |
1391 begin |
1275 |
1392 |
1276 if (Gear^.Kind <> gtMinigun) and |
|
1277 ((Ammo^.Kind = gtDEagleShot) |
|
1278 or (Ammo^.Kind = gtSniperRifleShot) |
|
1279 or (Ammo^.Kind = gtMinigunBullet)) then |
|
1280 begin |
|
1281 VGear := AddVisualGear(t^.cX[i], t^.cY[i], vgtBulletHit); |
|
1282 if VGear <> nil then |
|
1283 VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY); |
|
1284 end; |
|
1285 |
|
1286 if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then |
1393 if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then |
1287 Gear^.FlightTime:= 1; |
1394 Gear^.FlightTime:= 1; |
1288 |
|
1289 |
1395 |
1290 case Gear^.Kind of |
1396 case Gear^.Kind of |
1291 gtHedgehog, |
1397 gtHedgehog, |
1292 gtMine, |
1398 gtMine, |
|
1399 gtAirMine, |
1293 gtSMine, |
1400 gtSMine, |
1294 gtKnife, |
1401 gtKnife, |
1295 gtTarget, |
1402 gtTarget, |
1296 gtCase, |
1403 gtCase, |
1297 gtExplosives: //, |
1404 gtExplosives: |
1298 //gtStructure: |
1405 begin |
1299 begin |
1406 if (Ammo^.Kind in [gtFirePunch, gtKamikaze]) and (Gear^.Kind <> gtSMine) then |
|
1407 PlaySound(sndFirePunchHit); |
|
1408 |
|
1409 if Ammo^.Kind in [gtDEagleShot, gtSniperRifleShot, gtMinigunBullet] then |
|
1410 begin |
|
1411 VGear := AddVisualGear(t^.cX[i], t^.cY[i], vgtBulletHit); |
|
1412 if VGear <> nil then |
|
1413 VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY); |
|
1414 end; |
1300 if (Ammo^.Kind = gtDrill) then |
1415 if (Ammo^.Kind = gtDrill) then |
1301 begin |
1416 begin |
1302 Ammo^.Timer:= 0; |
1417 Ammo^.Timer:= 0; |
1303 exit; |
1418 exit; |
1304 end; |
1419 end; |
1324 dy := -dy; |
1439 dy := -dy; |
1325 FrameTicks:= 600+random(200); |
1440 FrameTicks:= 600+random(200); |
1326 State:= ord(sprStar) |
1441 State:= ord(sprStar) |
1327 end |
1442 end |
1328 end; |
1443 end; |
1329 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove) |
1444 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove); |
|
1445 |
|
1446 if Gear^.Kind = gtAirmine then |
|
1447 begin |
|
1448 Gear^.Tag:= 1; |
|
1449 Gear^.FlightTime:= 5000; |
|
1450 end |
1330 end |
1451 end |
1331 else |
1452 else |
1332 Gear^.State:= Gear^.State or gstWinner; |
1453 Gear^.State:= Gear^.State or gstWinner; |
1333 if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then |
1454 if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then |
1334 begin |
1455 begin |
1335 if (Ammo^.Hedgehog^.Gear <> nil) then |
1456 if (Ammo^.Hedgehog^.Gear <> nil) then |
1336 Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable); |
1457 Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable); |
1337 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch |
1458 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsExplosion); // crank up damage for explosives + blowtorch |
1338 end; |
1459 end; |
1339 |
1460 |
1340 if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then |
1461 if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then |
1341 begin |
1462 begin |
1342 Gear^.dX:= Gear^.dX + Ammo^.dX * Power * _0_005; |
1463 Gear^.dX:= Ammo^.dX * Power * _0_005; |
1343 Gear^.dY:= Gear^.dY + Ammo^.dY * Power * _0_005 |
1464 Gear^.dY:= Ammo^.dY * Power * _0_005 |
1344 end |
1465 end |
1345 else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then |
1466 else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then |
1346 begin |
1467 begin |
1347 Gear^.dX:= Gear^.dX + Ammo^.dX * Power * _0_01; |
1468 Gear^.dX:= Ammo^.dX * Power * _0_01; |
1348 Gear^.dY:= Gear^.dY + Ammo^.dY * Power * _0_01 |
1469 Gear^.dY:= Ammo^.dY * Power * _0_01 |
1349 end; |
1470 end; |
1350 |
1471 |
1351 if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then |
1472 if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then |
1352 begin |
1473 begin |
1353 Gear^.Active:= true; |
1474 Gear^.Active:= true; |
1381 end; |
1502 end; |
1382 |
1503 |
1383 procedure AmmoShoveLine(Ammo: PGear; Damage, Power: LongInt; oX, oY, tX, tY: hwFloat); |
1504 procedure AmmoShoveLine(Ammo: PGear; Damage, Power: LongInt; oX, oY, tX, tY: hwFloat); |
1384 var t: PGearArray; |
1505 var t: PGearArray; |
1385 begin |
1506 begin |
1386 if Ammo^.Kind = gtMinigunBullet then |
1507 t:= CheckAllGearsLineCollision(Ammo, oX, oY, tX, tY); |
1387 t:= CheckAllGearsLineCollision(Ammo, oX, oY, tX, tY) |
|
1388 else |
|
1389 t:= CheckGearsLineCollision(Ammo, oX, oY, tX, tY); |
|
1390 AmmoShoveImpl(Ammo, Damage, Power, t); |
1508 AmmoShoveImpl(Ammo, Damage, Power, t); |
1391 end; |
1509 end; |
1392 |
1510 |
1393 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); |
1511 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); |
1394 begin |
1512 begin |
1395 AmmoShoveImpl(Ammo, Damage, Power, |
1513 AmmoShoveImpl(Ammo, Damage, Power, |
1396 CheckGearsCollision(Ammo)); |
1514 CheckGearsCollision(Ammo)); |
1397 end; |
1515 end; |
1398 |
1516 |
|
1517 procedure AmmoShoveCache(Ammo: PGear; Damage, Power: LongInt); |
|
1518 begin |
|
1519 AmmoShoveImpl(Ammo, Damage, Power, |
|
1520 CheckCacheCollision(Ammo)); |
|
1521 end; |
1399 |
1522 |
1400 function CountGears(Kind: TGearType): Longword; |
1523 function CountGears(Kind: TGearType): Longword; |
1401 var t: PGear; |
1524 var t: PGear; |
1402 count: Longword = 0; |
1525 count: Longword = 0; |
1403 begin |
1526 begin |
1549 FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); |
1673 FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); |
1550 t:= GetRandom(t); |
1674 t:= GetRandom(t); |
1551 i:= Low(TAmmoType); |
1675 i:= Low(TAmmoType); |
1552 FollowGear^.Pos:= posCaseUtility; |
1676 FollowGear^.Pos:= posCaseUtility; |
1553 FollowGear^.AmmoType:= i; |
1677 FollowGear^.AmmoType:= i; |
1554 AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo); |
1678 AddCaption(GetEventString(eidNewUtilityPack), capcolDefault, capgrpAmmoInfo); |
1555 end |
1679 end |
1556 end; |
1680 end; |
1557 |
1681 |
1558 // handles case of no ammo or utility crates - considered also placing booleans in uAmmos and altering probabilities |
1682 // handles case of no ammo or utility crates - considered also placing booleans in uAmmos and altering probabilities |
1559 if (FollowGear <> nil) then |
1683 if (FollowGear <> nil) then |
1560 begin |
1684 begin |
1561 FindPlace(FollowGear, true, 0, LAND_WIDTH); |
1685 FindPlace(FollowGear, true, 0, LAND_WIDTH); |
1562 |
1686 PlayBoxSpawnTaunt(FollowGear); |
1563 if (FollowGear <> nil) then |
1687 SpawnBoxOfSmth:= FollowGear; |
1564 AddVoice(sndReinforce, CurrentTeam^.voicepack) |
|
1565 end |
1688 end |
|
1689 end; |
|
1690 |
|
1691 procedure PlayBoxSpawnTaunt(Gear: PGear); |
|
1692 const |
|
1693 // Max. distance between hog and crate for sndThisOneIsMine taunt |
|
1694 ThisOneIsMineDistance : LongInt = 130; |
|
1695 var d, minD: LongInt; |
|
1696 gi, closestHog: PGear; |
|
1697 begin |
|
1698 // Taunt |
|
1699 if (Gear <> nil) then |
|
1700 begin |
|
1701 // Look for hog closest to the crate (on the X axis) |
|
1702 gi := GearsList; |
|
1703 minD := LAND_WIDTH + ThisOneIsMineDistance + 1; |
|
1704 closestHog:= nil; |
|
1705 while gi <> nil do |
|
1706 begin |
|
1707 if (gi^.Kind = gtHedgehog) then |
|
1708 begin |
|
1709 // Y axis is ignored to simplify calculations |
|
1710 d := hwRound(hwAbs(gi^.X - Gear^.X)); |
|
1711 if d < minD then |
|
1712 begin |
|
1713 minD := d; |
|
1714 closestHog:= gi; |
|
1715 end; |
|
1716 end; |
|
1717 gi := gi^.NextGear; |
|
1718 end; |
|
1719 |
|
1720 // Is closest hog close enough to the crate (on the X axis)? |
|
1721 if (closestHog <> nil) and (closestHog^.Hedgehog <> nil) and (minD <= ThisOneIsMineDistance) then |
|
1722 // If so, there's a chance for a special taunt |
|
1723 if random(3) > 0 then |
|
1724 AddVoice(sndThisOneIsMine, closestHog^.Hedgehog^.Team^.voicepack) |
|
1725 else |
|
1726 AddVoice(sndReinforce, CurrentTeam^.voicepack) |
|
1727 else |
|
1728 // Default crate drop taunt |
|
1729 AddVoice(sndReinforce, CurrentTeam^.voicepack); |
|
1730 end; |
1566 end; |
1731 end; |
1567 |
1732 |
1568 |
1733 |
1569 function GetAmmo(Hedgehog: PHedgehog): TAmmoType; |
1734 function GetAmmo(Hedgehog: PHedgehog): TAmmoType; |
1570 var t, aTot: LongInt; |
1735 var t, aTot: LongInt; |
1627 * From the depths (same as from sky, but from sea, with submersible flag set) |
1792 * From the depths (same as from sky, but from sea, with submersible flag set) |
1628 |
1793 |
1629 Trying to make the checks a little broader than on first pass to catch things that don't move normally. |
1794 Trying to make the checks a little broader than on first pass to catch things that don't move normally. |
1630 *) |
1795 *) |
1631 function WorldWrap(var Gear: PGear): boolean; |
1796 function WorldWrap(var Gear: PGear): boolean; |
1632 //var tdx: hwFloat; |
1797 var bounced: boolean; |
1633 begin |
1798 begin |
1634 WorldWrap:= false; |
1799 WorldWrap:= false; |
1635 if WorldEdge = weNone then exit(false); |
1800 if WorldEdge = weNone then exit(false); |
1636 if (hwRound(Gear^.X) < LongInt(leftX)) or |
1801 if (hwRound(Gear^.X) < leftX) or |
1637 (hwRound(Gear^.X) > LongInt(rightX)) then |
1802 (hwRound(Gear^.X) > rightX) then |
1638 begin |
1803 begin |
1639 if WorldEdge = weWrap then |
1804 if WorldEdge = weWrap then |
1640 begin |
1805 begin |
1641 if (hwRound(Gear^.X) < LongInt(leftX)) then |
1806 if (hwRound(Gear^.X) < leftX) then |
1642 Gear^.X:= Gear^.X + int2hwfloat(rightX - leftX) |
1807 Gear^.X:= Gear^.X + int2hwfloat(rightX - leftX) |
1643 else Gear^.X:= Gear^.X - int2hwfloat(rightX - leftX); |
1808 else Gear^.X:= Gear^.X - int2hwfloat(rightX - leftX); |
1644 LeftImpactTimer:= 150; |
1809 LeftImpactTimer:= 150; |
1645 RightImpactTimer:= 150 |
1810 RightImpactTimer:= 150; |
|
1811 WorldWrap:= true; |
1646 end |
1812 end |
1647 else if WorldEdge = weBounce then |
1813 else if WorldEdge = weBounce then |
1648 begin |
1814 begin |
1649 if (hwRound(Gear^.X) - Gear^.Radius < LongInt(leftX)) then |
1815 bounced:= false; |
|
1816 // Bounce left |
|
1817 if (hwRound(Gear^.X) - Gear^.Radius < leftX) and (((hwSign(Gear^.dX) = -1) and (not isZero(Gear^.dX))) or (Gear^.Kind = gtHedgehog)) then |
1650 begin |
1818 begin |
1651 LeftImpactTimer:= 333; |
1819 LeftImpactTimer:= 333; |
|
1820 // Set X coordinate to bounce edge, unless the gear spawned inside the bounce edge before |
|
1821 if (Gear^.State and gstInBounceEdge) = 0 then |
|
1822 Gear^.X:= int2hwfloat(leftX + Gear^.Radius); |
|
1823 // Invert horizontal speed |
1652 Gear^.dX.isNegative:= false; |
1824 Gear^.dX.isNegative:= false; |
1653 Gear^.X:= int2hwfloat(LongInt(leftX) + Gear^.Radius) |
1825 bounced:= true; |
1654 end |
1826 end |
1655 else |
1827 // Bounce right |
|
1828 else if (hwRound(Gear^.X) + Gear^.Radius > rightX) and (((hwSign(Gear^.dX) = 1) and (not isZero(Gear^.dX))) or (Gear^.Kind = gtHedgehog)) then |
1656 begin |
1829 begin |
1657 RightImpactTimer:= 333; |
1830 RightImpactTimer:= 333; |
|
1831 // Set X coordinate to bounce edge, unless the gear spawned inside the bounce edge before |
|
1832 if (Gear^.State and gstInBounceEdge) = 0 then |
|
1833 Gear^.X:= int2hwfloat(rightX - Gear^.Radius); |
|
1834 // Invert horizontal speed |
1658 Gear^.dX.isNegative:= true; |
1835 Gear^.dX.isNegative:= true; |
1659 Gear^.X:= int2hwfloat(rightX-Gear^.Radius) |
1836 bounced:= true; |
1660 end; |
1837 end; |
1661 if (Gear^.Radius > 2) and (Gear^.dX.QWordValue > _0_001.QWordValue) then |
1838 // Clear gstInBounceEdge when gear is no longer inside a bounce edge area |
1662 AddBounceEffectForGear(Gear); |
1839 if ((Gear^.State and gstInBounceEdge) <> 0) and (hwRound(Gear^.X) - Gear^.Radius >= leftX) and (hwRound(Gear^.X) + Gear^.Radius <= rightX) then |
1663 end{ |
1840 Gear^.State:= Gear^.State and (not gstInBounceEdge); |
1664 else if WorldEdge = weSea then |
1841 if (bounced) then |
1665 begin |
1842 begin |
1666 if (hwRound(Gear^.Y) > cWaterLine) and (Gear^.State and gstSubmersible <> 0) then |
1843 WorldWrap:= true; |
1667 Gear^.State:= Gear^.State and (not gstSubmersible) |
1844 if (Gear^.dX.QWordValue > _0_001.QWordValue) then |
1668 else |
1845 AddBounceEffectForGear(Gear); |
1669 begin |
1846 end; |
1670 Gear^.State:= Gear^.State or gstSubmersible; |
1847 end |
1671 Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight; |
1848 else |
1672 Gear^.Y:= int2hwFloat(cWaterLine+cVisibleWater+Gear^.Radius*2); |
1849 WorldWrap:= true; |
1673 tdx:= Gear^.dX; |
1850 end; |
1674 Gear^.dX:= -Gear^.dY; |
1851 end; |
1675 Gear^.dY:= tdx; |
1852 |
1676 Gear^.dY.isNegative:= true |
1853 (* |
|
1854 Applies wrap-around logic for the target of homing gears. |
|
1855 |
|
1856 In wrap-around world edge, the shortest way may to the target might |
|
1857 be across the border, so the X value of the target would lead the |
|
1858 gear to the wrong direction across the whole map. This procedure |
|
1859 changes the target X in this case. |
|
1860 This function must be called after the gear passed through |
|
1861 the wrap-around world edge (WorldWrap returned true). |
|
1862 |
|
1863 No-op for other world edges. |
|
1864 |
|
1865 Returns true if target has been changed. |
|
1866 *) |
|
1867 function HomingWrap(var Gear: PGear): boolean; |
|
1868 var dist_center, dist_right, dist_left: hwFloat; |
|
1869 begin |
|
1870 if WorldEdge = weWrap then |
|
1871 begin |
|
1872 HomingWrap:= false; |
|
1873 // We just check the same target 3 times: |
|
1874 // 1) in current section (no change) |
|
1875 // 2) clone in the right section |
|
1876 // 3) clone in the left section |
|
1877 // The gear will go for the target with the shortest distance to the gear. |
|
1878 // For simplicity, we only check distance on the X axis. |
|
1879 dist_center:= hwAbs(Gear^.X - int2hwFloat(Gear^.Target.X)); |
|
1880 dist_right:= hwAbs(Gear^.X - int2hwFloat(Gear^.Target.X + (RightX-LeftX))); |
|
1881 dist_left:= hwAbs(Gear^.X - int2hwFloat(Gear^.Target.X - (RightX-LeftX))); |
|
1882 if (dist_left < dist_right) and (dist_left < dist_center) then |
|
1883 begin |
|
1884 dec(Gear^.Target.X, RightX-LeftX); |
|
1885 HomingWrap:= true; |
1677 end |
1886 end |
1678 end}; |
1887 else if (dist_right < dist_left) and (dist_right < dist_center) then |
1679 (* |
1888 begin |
1680 * Window in the sky (Gear moved high into the sky, Y is used to determine X) [unfortunately, not a safe thing to do. shame, I thought aerial bombardment would be kinda neat |
1889 inc(Gear^.Target.X, RightX-LeftX); |
1681 This one would be really easy to freeze game unless it was flagged unfortunately. |
1890 HomingWrap:= true; |
1682 |
1891 end; |
1683 else |
1892 end; |
1684 begin |
1893 end; |
1685 Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight; |
1894 |
1686 Gear^.Y:= -_2048-_256-_256; |
1895 // Add an audiovisual bounce effect for gear after it bounced from bouncy material. |
1687 tdx:= Gear^.dX; |
1896 // Graphical effect is based on speed. |
1688 Gear^.dX:= Gear^.dY; |
|
1689 Gear^.dY:= tdx; |
|
1690 Gear^.dY.isNegative:= false |
|
1691 end |
|
1692 *) |
|
1693 WorldWrap:= true |
|
1694 end; |
|
1695 end; |
|
1696 |
|
1697 procedure AddBounceEffectForGear(Gear: PGear); |
1897 procedure AddBounceEffectForGear(Gear: PGear); |
|
1898 begin |
|
1899 AddBounceEffectForGear(Gear, hwFloat2Float(Gear^.Density * hwAbs(Gear^.dY) + hwAbs(Gear^.dX)) / 1.5); |
|
1900 end; |
|
1901 |
|
1902 // Same as above, but can specify the size of bounce image with imageScale manually. |
|
1903 procedure AddBounceEffectForGear(Gear: PGear; imageScale: Single); |
1698 var boing: PVisualGear; |
1904 var boing: PVisualGear; |
1699 begin |
1905 begin |
|
1906 if (Gear^.Density < _0_01) or (Gear^.Radius < 2) then |
|
1907 exit; |
1700 boing:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot, 0, false, 1); |
1908 boing:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot, 0, false, 1); |
1701 if boing <> nil then |
1909 if boing <> nil then |
1702 with boing^ do |
1910 with boing^ do |
1703 begin |
1911 begin |
1704 Angle:= random(360); |
1912 Angle:= random(360); |
1705 dx:= 0; |
1913 dx:= 0; |
1706 dy:= 0; |
1914 dy:= 0; |
1707 FrameTicks:= 200; |
1915 FrameTicks:= 200; |
1708 Scale:= hwFloat2Float(Gear^.Density * hwAbs(Gear^.dY) + hwAbs(Gear^.dX)) / 1.5; |
1916 Scale:= imageScale; |
1709 State:= ord(sprBoing) |
1917 State:= ord(sprBoing) |
1710 end; |
1918 end; |
1711 if Gear^.Kind = gtDuck then |
1919 PlaySound(sndMelonImpact, true) |
1712 PlaySound(sndDuckDrop, true) |
1920 end; |
|
1921 |
|
1922 function IsHogFacingLeft(Gear: PGear): boolean; |
|
1923 var sign: LongInt; |
|
1924 begin |
|
1925 sign:= hwSign(Gear^.dX); |
|
1926 if (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtParachute) then |
|
1927 IsHogFacingLeft:= CurAmmoGear^.Tag = -1 |
|
1928 else if ((Gear^.State and gstHHHJump) <> 0) and (Gear^.Hedgehog^.Effects[heArtillery] = 0) then |
|
1929 IsHogFacingLeft:= sign > 0 |
1713 else |
1930 else |
1714 PlaySound(sndMelonImpact, true) |
1931 IsHogFacingLeft:= sign < 0; |
1715 end; |
1932 end; |
1716 |
1933 |
1717 function IsHogLocal(HH: PHedgehog): boolean; |
1934 function IsHogLocal(HH: PHedgehog): boolean; |
1718 begin |
1935 begin |
1719 IsHogLocal:= (not (HH^.Team^.ExtDriven or (HH^.BotLevel > 0))) or (HH^.Team^.Clan^.ClanIndex = LocalClan) or (GameType = gmtDemo); |
1936 IsHogLocal:= (not (HH^.Team^.ExtDriven or (HH^.BotLevel > 0))) or (HH^.Team^.Clan^.LocalOrAlly) or (GameType = gmtDemo); |
1720 end; |
1937 end; |
1721 |
1938 |
1722 end. |
1939 end. |