21 unit uGearsUtils; |
21 unit uGearsUtils; |
22 interface |
22 interface |
23 uses uTypes; |
23 uses uTypes; |
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 |
27 |
28 function ModifyDamage(dmg: Longword; Gear: PGear): Longword; |
28 function ModifyDamage(dmg: Longword; Gear: PGear): Longword; |
29 procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource); |
29 procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource); |
30 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword); |
30 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword); |
31 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource); |
31 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource); |
231 end; |
231 end; |
232 inc(i, 5); |
232 inc(i, 5); |
233 end; |
233 end; |
234 end |
234 end |
235 end; |
235 end; |
236 if ((GameFlags and gfKarma) <> 0) and |
236 if ((GameFlags and gfKarma) <> 0) and |
237 ((GameFlags and gfInvulnerable) = 0) |
237 ((GameFlags and gfInvulnerable) = 0) |
238 and (not CurrentHedgehog^.Gear^.Invulnerable) then |
238 and (not CurrentHedgehog^.Gear^.Invulnerable) then |
239 begin // this cannot just use Damage or it interrupts shotgun and gets you called stupid |
239 begin // this cannot just use Damage or it interrupts shotgun and gets you called stupid |
240 inc(CurrentHedgehog^.Gear^.Karma, tmpDmg); |
240 inc(CurrentHedgehog^.Gear^.Karma, tmpDmg); |
241 CurrentHedgehog^.Gear^.LastDamage := CurrentHedgehog; |
241 CurrentHedgehog^.Gear^.LastDamage := CurrentHedgehog; |
242 spawnHealthTagForHH(CurrentHedgehog^.Gear, tmpDmg); |
242 spawnHealthTagForHH(CurrentHedgehog^.Gear, tmpDmg); |
243 end; |
243 end; |
244 uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false); |
244 uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false); |
245 end; |
245 end; |
246 end |
246 end else |
247 else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure |
247 //else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure |
248 Gear^.Hedgehog:= AttackerHog; |
248 Gear^.Hedgehog:= AttackerHog; |
249 inc(Gear^.Damage, Damage); |
249 inc(Gear^.Damage, Damage); |
250 |
250 |
251 ScriptCall('onGearDamage', Gear^.UID, Damage); |
251 ScriptCall('onGearDamage', Gear^.UID, Damage); |
252 end; |
252 end; |
253 |
253 |
254 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword); |
254 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword); |
255 var tag: PVisualGear; |
255 var tag: PVisualGear; |
258 if (tag <> nil) then |
258 if (tag <> nil) then |
259 tag^.Hedgehog:= HHGear^.Hedgehog; // the tag needs the tag to determine the text color |
259 tag^.Hedgehog:= HHGear^.Hedgehog; // the tag needs the tag to determine the text color |
260 AllInactive:= false; |
260 AllInactive:= false; |
261 HHGear^.Active:= true; |
261 HHGear^.Active:= true; |
262 end; |
262 end; |
263 |
263 |
264 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource); |
264 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource); |
265 begin |
265 begin |
266 if (Source = dsFall) or (Source = dsExplosion) then |
266 if (Source = dsFall) or (Source = dsExplosion) then |
267 case random(3) of |
267 case random(3) of |
268 0: PlaySoundV(sndOoff1, Hedgehog^.Team^.voicepack); |
268 0: PlaySoundV(sndOoff1, Hedgehog^.Team^.voicepack); |
318 end |
318 end |
319 end; |
319 end; |
320 |
320 |
321 |
321 |
322 procedure CalcRotationDirAngle(Gear: PGear); |
322 procedure CalcRotationDirAngle(Gear: PGear); |
323 var |
323 var |
324 dAngle: real; |
324 dAngle: real; |
325 begin |
325 begin |
326 // Frac/Round to be kind to JS as of 2012-08-27 where there is yet no int64/uint64 |
326 // Frac/Round to be kind to JS as of 2012-08-27 where there is yet no int64/uint64 |
327 //dAngle := (Gear^.dX.QWordValue + Gear^.dY.QWordValue) / $80000000; |
327 //dAngle := (Gear^.dX.QWordValue + Gear^.dY.QWordValue) / $80000000; |
328 dAngle := (Gear^.dX.Round + Gear^.dY.Round) / 2 + (Gear^.dX.Frac/$100000000+Gear^.dY.Frac/$100000000); |
328 dAngle := (Gear^.dX.Round + Gear^.dY.Round) / 2 + (Gear^.dX.Frac/$100000000+Gear^.dY.Frac/$100000000); |
336 else if 360 < Gear^.DirAngle then |
336 else if 360 < Gear^.DirAngle then |
337 Gear^.DirAngle := Gear^.DirAngle - 360 |
337 Gear^.DirAngle := Gear^.DirAngle - 360 |
338 end; |
338 end; |
339 |
339 |
340 function CheckGearDrowning(Gear: PGear): boolean; |
340 function CheckGearDrowning(Gear: PGear): boolean; |
341 var |
341 var |
342 skipSpeed, skipAngle, skipDecay: hwFloat; |
342 skipSpeed, skipAngle, skipDecay: hwFloat; |
343 i, maxDrops, X, Y: LongInt; |
343 i, maxDrops, X, Y: LongInt; |
344 vdX, vdY: real; |
344 vdX, vdY: real; |
345 particle, splash: PVisualGear; |
345 particle, splash: PVisualGear; |
346 isSubmersible: boolean; |
346 isSubmersible: boolean; |
399 end |
399 end |
400 end |
400 end |
401 else |
401 else |
402 Gear^.doStep := @doStepDrowningGear; |
402 Gear^.doStep := @doStepDrowningGear; |
403 if Gear^.Kind = gtFlake then |
403 if Gear^.Kind = gtFlake then |
404 exit // skip splashes |
404 exit // skip splashes |
405 end; |
405 end; |
406 if ((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius)) |
406 if ((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius)) |
407 or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) |
407 or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) |
408 and (CurAmmoGear^.dY < _0_01))) then |
408 and (CurAmmoGear^.dY < _0_01))) then |
409 if Gear^.Density * Gear^.dY > _1 then |
409 if Gear^.Density * Gear^.dY > _1 then |
410 PlaySound(sndSplash) |
410 PlaySound(sndSplash) |
411 else if Gear^.Density * Gear^.dY > _0_5 then |
411 else if Gear^.Density * Gear^.dY > _0_5 then |
412 PlaySound(sndSkip) |
412 PlaySound(sndSkip) |
413 else |
413 else |
414 PlaySound(sndDroplet2); |
414 PlaySound(sndDroplet2); |
415 end; |
415 end; |
416 |
416 |
418 and (((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius)) |
418 and (((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius)) |
419 or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) |
419 or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) |
420 and (CurAmmoGear^.dY < _0_01)))) then |
420 and (CurAmmoGear^.dY < _0_01)))) then |
421 begin |
421 begin |
422 splash:= AddVisualGear(X, cWaterLine, vgtSplash); |
422 splash:= AddVisualGear(X, cWaterLine, vgtSplash); |
423 if splash <> nil then |
423 if splash <> nil then |
424 with splash^ do |
424 with splash^ do |
425 begin |
425 begin |
426 Scale:= hwFloat2Float(Gear^.Density / _3 * Gear^.dY); |
426 Scale:= hwFloat2Float(Gear^.Density / _3 * Gear^.dY); |
427 if Scale > 1 then Scale:= power(Scale,0.3333) |
427 if Scale > 1 then Scale:= power(Scale,0.3333) |
428 else Scale:= Scale + ((1-Scale) / 2); |
428 else Scale:= Scale + ((1-Scale) / 2); |
441 begin |
441 begin |
442 dX := dX - vdX / 10; |
442 dX := dX - vdX / 10; |
443 dY := dY - vdY / 5; |
443 dY := dY - vdY / 5; |
444 if splash <> nil then |
444 if splash <> nil then |
445 begin |
445 begin |
446 if splash^.Scale > 1 then |
446 if splash^.Scale > 1 then |
447 begin |
447 begin |
448 dX:= dX * power(splash^.Scale,0.3333); // tone down the droplet height further |
448 dX:= dX * power(splash^.Scale,0.3333); // tone down the droplet height further |
449 dY:= dY * power(splash^.Scale, 0.3333) |
449 dY:= dY * power(splash^.Scale, 0.3333) |
450 end |
450 end |
451 else |
451 else |
452 begin |
452 begin |
453 dX:= dX * splash^.Scale; |
453 dX:= dX * splash^.Scale; |
454 dY:= dY * splash^.Scale |
454 dY:= dY * splash^.Scale |
455 end |
455 end |
456 end |
456 end |
480 gear^.Damage := 0; |
480 gear^.Damage := 0; |
481 gear^.Health := gear^.Hedgehog^.InitialHealth; |
481 gear^.Health := gear^.Hedgehog^.InitialHealth; |
482 gear^.Hedgehog^.Effects[hePoisoned] := 0; |
482 gear^.Hedgehog^.Effects[hePoisoned] := 0; |
483 if (CurrentHedgehog^.Effects[heResurrectable] = 0) or ((CurrentHedgehog^.Effects[heResurrectable] <> 0) |
483 if (CurrentHedgehog^.Effects[heResurrectable] = 0) or ((CurrentHedgehog^.Effects[heResurrectable] <> 0) |
484 and (Gear^.Hedgehog^.Team^.Clan <> CurrentHedgehog^.Team^.Clan)) then |
484 and (Gear^.Hedgehog^.Team^.Clan <> CurrentHedgehog^.Team^.Clan)) then |
485 with CurrentHedgehog^ do |
485 with CurrentHedgehog^ do |
486 begin |
486 begin |
487 inc(Team^.stats.AIKills); |
487 inc(Team^.stats.AIKills); |
488 FreeTexture(Team^.AIKillsTex); |
488 FreeTexture(Team^.AIKillsTex); |
489 Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16); |
489 Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16); |
490 end; |
490 end; |
497 if sparkles <> nil then |
497 if sparkles <> nil then |
498 begin |
498 begin |
499 sparkles^.Tint:= tempTeam^.Clan^.Color shl 8 or $FF; |
499 sparkles^.Tint:= tempTeam^.Clan^.Color shl 8 or $FF; |
500 //sparkles^.Angle:= random(360); |
500 //sparkles^.Angle:= random(360); |
501 end; |
501 end; |
502 FindPlace(gear, false, 0, LAND_WIDTH, true); |
502 FindPlace(gear, false, 0, LAND_WIDTH, true); |
503 if gear <> nil then |
503 if gear <> nil then |
504 begin |
504 begin |
505 AddVisualGear(hwRound(gear^.X), hwRound(gear^.Y), vgtExplosion); |
505 AddVisualGear(hwRound(gear^.X), hwRound(gear^.Y), vgtExplosion); |
506 PlaySound(sndWarp); |
506 PlaySound(sndWarp); |
507 RenderHealth(gear^.Hedgehog^); |
507 RenderHealth(gear^.Hedgehog^); |
578 while y < cWaterLine do |
578 while y < cWaterLine do |
579 begin |
579 begin |
580 repeat |
580 repeat |
581 inc(y, 2); |
581 inc(y, 2); |
582 until (y >= cWaterLine) or |
582 until (y >= cWaterLine) or |
583 ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) = 0)) or |
583 ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) = 0)) or |
584 (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FF00) = 0)); |
584 (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FF00) = 0)); |
585 |
585 |
586 sy:= y; |
586 sy:= y; |
587 |
587 |
588 repeat |
588 repeat |
589 inc(y); |
589 inc(y); |
590 until (y >= cWaterLine) or |
590 until (y >= cWaterLine) or |
591 ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) <> 0)) or |
591 ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) <> 0)) or |
592 (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FF00) <> 0)); |
592 (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FF00) <> 0)); |
593 |
593 |
594 if (y - sy > Gear^.Radius * 2) |
594 if (y - sy > Gear^.Radius * 2) |
595 and (((Gear^.Kind = gtExplosives) |
595 and (((Gear^.Kind = gtExplosives) |
596 and (y < cWaterLine) |
596 and (y < cWaterLine) |
597 and (ignoreNearObjects or NoGearsToAvoid(x, y - Gear^.Radius, 60, 60)) |
597 and (ignoreNearObjects or NoGearsToAvoid(x, y - Gear^.Radius, 60, 60)) |
688 procedure CheckCollisionWithLand(Gear: PGear); inline; |
688 procedure CheckCollisionWithLand(Gear: PGear); inline; |
689 begin |
689 begin |
690 if TestCollisionX(Gear, hwSign(Gear^.dX)) |
690 if TestCollisionX(Gear, hwSign(Gear^.dX)) |
691 or TestCollisionY(Gear, hwSign(Gear^.dY)) then |
691 or TestCollisionY(Gear, hwSign(Gear^.dY)) then |
692 Gear^.State := Gear^.State or gstCollision |
692 Gear^.State := Gear^.State or gstCollision |
693 else |
693 else |
694 Gear^.State := Gear^.State and (not gstCollision) |
694 Gear^.State := Gear^.State and (not gstCollision) |
695 end; |
695 end; |
696 |
696 |
697 function MakeHedgehogsStep(Gear: PGear) : boolean; |
697 function MakeHedgehogsStep(Gear: PGear) : boolean; |
698 begin |
698 begin |