Start refactoring uGears. Breaks build.
--- a/hedgewars/GSHandlers.inc Tue Nov 29 17:42:42 2011 +0400
+++ b/hedgewars/GSHandlers.inc Fri Dec 30 13:54:39 2011 +0400
@@ -133,90 +133,6 @@
end;
////////////////////////////////////////////////////////////////////////////////
-procedure doStepDrowningGear(Gear: PGear);
-forward;
-
-function CheckGearDrowning(Gear: PGear): boolean;
-var
- skipSpeed, skipAngle, skipDecay: hwFloat;
- i, maxDrops, X, Y: LongInt;
- vdX, vdY: real;
- particle: PVisualGear;
- isSubmersible: boolean;
-begin
- isSubmersible:= (Gear = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amJetpack);
- // probably needs tweaking. might need to be in a case statement based upon gear type
- Y:= hwRound(Gear^.Y);
- if cWaterLine < Y + Gear^.Radius then
- begin
- skipSpeed := _0_25;
- skipAngle := _1_9;
- skipDecay := _0_87;
- X:= hwRound(Gear^.X);
- vdX:= hwFloat2Float(Gear^.dX);
- vdY:= hwFloat2Float(Gear^.dY);
- // this could perhaps be a tiny bit higher.
- if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed) and
- (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)) then
- begin
- Gear^.dY.isNegative := true;
- Gear^.dY := Gear^.dY * skipDecay;
- Gear^.dX := Gear^.dX * skipDecay;
- CheckGearDrowning := false;
- PlaySound(sndSkip)
- end
- else
- begin
- if not isSubmersible then
- begin
- CheckGearDrowning := true;
- Gear^.State := gstDrowning;
- Gear^.RenderTimer := false;
- if (Gear^.Kind <> gtSniperRifleShot) and (Gear^.Kind <> gtShotgunShot) and
- (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot) then
- if Gear^.Kind = gtHedgehog then
- begin
- if Gear^.Hedgehog^.Effects[heResurrectable] then
- ResurrectHedgehog(Gear)
- else
- begin
- Gear^.doStep := @doStepDrowningGear;
- Gear^.State := Gear^.State and (not gstHHDriven);
- AddCaption(Format(GetEventString(eidDrowned), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
- end
- end
- else Gear^.doStep := @doStepDrowningGear;
- if Gear^.Kind = gtFlake then exit // skip splashes
- end;
- if ((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius)) or
- (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) and (CurAmmoGear^.dY < _0_01))) then
- // don't play splash if they are already way past the surface
- PlaySound(sndSplash)
- end;
-
- if ((cReducedQuality and rqPlainSplash) = 0) and
- (((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius)) or
- (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) and (CurAmmoGear^.dY < _0_01)))) then
- begin
- AddVisualGear(X, cWaterLine, vgtSplash);
-
- maxDrops := (Gear^.Radius div 2) + round(vdX * Gear^.Radius * 2) + round(vdY * Gear^.Radius * 2);
- for i:= max(maxDrops div 3, min(32, Random(maxDrops))) downto 0 do
- begin
- particle := AddVisualGear(X - 3 + Random(6), cWaterLine, vgtDroplet);
- if particle <> nil then
- begin
- particle^.dX := particle^.dX - vdX / 10;
- particle^.dY := particle^.dY - vdY / 5;
- end
- end
- end;
- if isSubmersible and (CurAmmoGear^.Pos = 0) then CurAmmoGear^.Pos := 1000
- end
- else
- CheckGearDrowning := false;
-end;
-
procedure CheckCollision(Gear: PGear); inline;
begin
if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) or (TestCollisionYwithGear(Gear, hwSign(Gear^.dY)) <> 0) then
@@ -232,52 +148,9 @@
else Gear^.State := Gear^.State and (not gstCollision)
end;
-procedure CheckHHDamage(Gear: PGear);
-var
- dmg: Longword;
- i: LongInt;
- particle: PVisualGear;
-begin
- if _0_4 < Gear^.dY then
- begin
- dmg := ModifyDamage(1 + hwRound((hwAbs(Gear^.dY) - _0_4) * 70), Gear);
- PlaySound(sndBump);
- if dmg < 1 then exit;
-
- for i:= min(12, (3 + dmg div 10)) downto 0 do
- begin
- particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
- if particle <> nil then particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480);
- end;
-
- if (Gear^.Invulnerable) then exit;
-
- //if _0_6 < Gear^.dY then
- // PlaySound(sndOw4, Gear^.Hedgehog^.Team^.voicepack)
- //else
- // PlaySound(sndOw1, Gear^.Hedgehog^.Team^.voicepack);
-
- if Gear^.LastDamage <> nil then
- ApplyDamage(Gear, Gear^.LastDamage, dmg, dsFall)
- else
- ApplyDamage(Gear, CurrentHedgehog, dmg, dsFall);
- end
-end;
////////////////////////////////////////////////////////////////////////////////
-procedure CalcRotationDirAngle(Gear: PGear);
-var
- dAngle: real;
-begin
- dAngle := (Gear^.dX.QWordValue + Gear^.dY.QWordValue) / $80000000;
- if not Gear^.dX.isNegative then
- Gear^.DirAngle := Gear^.DirAngle + dAngle
- else
- Gear^.DirAngle := Gear^.DirAngle - dAngle;
-
- if Gear^.DirAngle < 0 then Gear^.DirAngle := Gear^.DirAngle + 360
- else if 360 < Gear^.DirAngle then Gear^.DirAngle := Gear^.DirAngle - 360
-end;
+
////////////////////////////////////////////////////////////////////////////////
procedure doStepDrowningGear(Gear: PGear);
--- a/hedgewars/HHHandlers.inc Tue Nov 29 17:42:42 2011 +0400
+++ b/hedgewars/HHHandlers.inc Fri Dec 30 13:54:39 2011 +0400
@@ -17,1138 +17,3 @@
*)
////////////////////////////////////////////////////////////////////////////////
-
-procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
-begin
-if (Source = dsFall) or (Source = dsExplosion) then
- case random(3) of
- 0: PlaySound(sndOoff1, Hedgehog^.Team^.voicepack);
- 1: PlaySound(sndOoff2, Hedgehog^.Team^.voicepack);
- 2: PlaySound(sndOoff3, Hedgehog^.Team^.voicepack);
- end
-else if (Source = dsPoison) then
- case random(2) of
- 0: PlaySound(sndPoisonCough, Hedgehog^.Team^.voicepack);
- 1: PlaySound(sndPoisonMoan, Hedgehog^.Team^.voicepack);
- end
-else
- case random(4) of
- 0: PlaySound(sndOw1, Hedgehog^.Team^.voicepack);
- 1: PlaySound(sndOw2, Hedgehog^.Team^.voicepack);
- 2: PlaySound(sndOw3, Hedgehog^.Team^.voicepack);
- 3: PlaySound(sndOw4, Hedgehog^.Team^.voicepack);
- end
-end;
-
-// Shouldn't more of this ammo switching stuff be moved to uAmmos ?
-function ChangeAmmo(HHGear: PGear): boolean;
-var slot, i: Longword;
- ammoidx: LongInt;
-begin
-ChangeAmmo:= false;
-slot:= HHGear^.MsgParam;
-
-with HHGear^.Hedgehog^ do
- begin
- HHGear^.Message:= HHGear^.Message and (not gmSlot);
- ammoidx:= 0;
- if ((HHGear^.State and (gstAttacking or gstAttacked)) <> 0) or
- ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0)) or
- ((HHGear^.State and gstHHDriven) = 0) then exit;
- ChangeAmmo:= true;
-
- while (ammoidx < cMaxSlotAmmoIndex) and (Ammo^[slot, ammoidx].AmmoType <> CurAmmoType) do inc(ammoidx);
-
- if ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (MultiShootAttacks > 0) then OnUsedAmmo(HHGear^.Hedgehog^);
-
- MultiShootAttacks:= 0;
- HHGear^.Message:= HHGear^.Message and (not (gmLJump or gmHJump));
-
- if Ammoz[CurAmmoType].Slot = slot then
- begin
- i:= 0;
- repeat
- inc(ammoidx);
- if (ammoidx > cMaxSlotAmmoIndex) then
- begin
- inc(i);
- CurAmmoType:= amNothing;
- ammoidx:= -1;
- //TryDo(i < 2, 'Engine bug: no ammo in current slot', true)
- end;
- until (i = 1) or ((Ammo^[slot, ammoidx].Count > 0) and (Team^.Clan^.TurnNumber > Ammoz[Ammo^[slot, ammoidx].AmmoType].SkipTurns))
- end
- else
- begin
- i:= 0;
- // check whether there is ammo in slot
- while (i <= cMaxSlotAmmoIndex)
- and ((Ammo^[slot, i].Count = 0)
- or (Team^.Clan^.TurnNumber <= Ammoz[Ammo^[slot, i].AmmoType].SkipTurns)) do inc(i);
-
- if i <= cMaxSlotAmmoIndex then ammoidx:= i
- else ammoidx:= -1
- end;
- if ammoidx >= 0 then CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
- end
-end;
-
-procedure HHSetWeapon(HHGear: PGear);
-var t: LongInt;
- weap: TAmmoType;
- Hedgehog: PHedgehog;
- s: boolean;
-begin
-s:= false;
-
-weap:= TAmmoType(HHGear^.MsgParam);
-Hedgehog:= HHGear^.Hedgehog;
-
-if Hedgehog^.Team^.Clan^.TurnNumber <= Ammoz[weap].SkipTurns then exit; // weapon is not activated yet
-
-HHGear^.MsgParam:= Ammoz[weap].Slot;
-
-t:= cMaxSlotAmmoIndex;
-
-HHGear^.Message:= HHGear^.Message and (not gmWeapon);
-
-with Hedgehog^ do
- while (CurAmmoType <> weap) and (t >= 0) do
- begin
- s:= ChangeAmmo(HHGear);
- dec(t)
- end;
-
-if s then ApplyAmmoChanges(HHGear^.Hedgehog^)
-end;
-
-procedure HHSetTimer(Gear: PGear);
-var CurWeapon: PAmmo;
- color: LongWord;
-begin
-Gear^.Message:= Gear^.Message and (not gmTimer);
-CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^);
-with Gear^.Hedgehog^ do
- if ((Gear^.Message and gmPrecise) <> 0) and ((CurWeapon^.Propz and ammoprop_SetBounce) <> 0) then
- begin
- color:= Gear^.Hedgehog^.Team^.Clan^.Color;
- case Gear^.MsgParam of
- 1: begin
- AddCaption(format(trmsg[sidBounce], trmsg[sidBounce1]), color, capgrpAmmostate);
- CurWeapon^.Bounciness:= 350;
- end;
- 2: begin
- AddCaption(format(trmsg[sidBounce], trmsg[sidBounce2]), color, capgrpAmmostate);
- CurWeapon^.Bounciness:= 700;
- end;
- 3: begin
- AddCaption(format(trmsg[sidBounce], trmsg[sidBounce3]), color, capgrpAmmostate);
- CurWeapon^.Bounciness:= 1000;
- end;
- 4: begin
- AddCaption(format(trmsg[sidBounce], trmsg[sidBounce4]), color, capgrpAmmostate);
- CurWeapon^.Bounciness:= 2000;
- end;
- 5: begin
- AddCaption(format(trmsg[sidBounce], trmsg[sidBounce5]), color, capgrpAmmostate);
- CurWeapon^.Bounciness:= 4000;
- end
- end
- end
- else if (CurWeapon^.Propz and ammoprop_Timerable) <> 0 then
- begin
- CurWeapon^.Timer:= 1000 * Gear^.MsgParam;
- with CurrentTeam^ do
- ApplyAmmoChanges(Hedgehogs[CurrHedgehog]);
- end;
-end;
-
-
-procedure Attack(Gear: PGear);
-var xx, yy, newDx, newDy, lx, ly: hwFloat;
- speech: PVisualGear;
- newGear: PGear;
- CurWeapon: PAmmo;
- altUse: boolean;
- elastic: hwFloat;
-begin
-newGear:= nil;
-bShowFinger:= false;
-CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^);
-with Gear^,
- Gear^.Hedgehog^ do
- begin
- if ((State and gstHHDriven) <> 0)and
- ((State and (gstAttacked or gstHHChooseTarget)) = 0) and
- (((State and gstMoving) = 0) or
- (Power > 0) or
- (CurAmmoType = amTeleport) or
- // Allow attacks while moving on ammo with AltAttack
- ((CurAmmoGear <> nil) and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)) or
- ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AttackInMove) <> 0)) and
- ((TargetPoint.X <> NoPointX) or ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) = 0)) then
- begin
- State:= State or gstAttacking;
- if Power = cMaxPower then Message:= Message and (not gmAttack)
- else if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) = 0 then Message:= Message and (not gmAttack)
- else begin
- if Power = 0 then
- begin
- AttackBar:= CurrentTeam^.AttackBar;
- PlaySound(sndThrowPowerUp)
- end;
- inc(Power)
- end;
- if ((Message and gmAttack) <> 0) then exit;
-
- if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0 then
- begin
- StopSound(sndThrowPowerUp);
- PlaySound(sndThrowRelease);
- end;
-
- xx:= SignAs(AngleSin(Angle), dX);
- yy:= -AngleCos(Angle);
-
- lx:= X + int2hwfloat(round(GetLaunchX(CurAmmoType, hwSign(dX), Angle)));
- ly:= Y + int2hwfloat(round(GetLaunchY(CurAmmoType, Angle)));
-
- if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then xx:= - xx;
- if Ammoz[CurAmmoType].Ammo.AttackVoice <> sndNone then
- AddVoice(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
-
-// Initiating alt attack
- if (CurAmmoGear <> nil) and
- ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) and
- ((Gear^.Message and gmLJump) <> 0) and
- ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
- begin
- newDx:= dX / _2;
- newDy:= dY / _2;
- altUse:= true;
- end
- else
- begin
- newDx:= xx*Power/cPowerDivisor;
- newDy:= yy*Power/cPowerDivisor;
- altUse:= false
- end;
-
- case CurAmmoType of
- amGrenade: newGear:= AddGear(hwRound(lx), hwRound(ly), gtGrenade, 0, newDx, newDy, CurWeapon^.Timer);
- amMolotov: newGear:= AddGear(hwRound(lx), hwRound(ly), gtMolotov, 0, newDx, newDy, 0);
- amClusterBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtClusterBomb, 0, newDx, newDy, CurWeapon^.Timer);
- amGasBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtGasBomb, 0, newDx, newDy, CurWeapon^.Timer);
- amBazooka: newGear:= AddGear(hwRound(lx), hwRound(ly), gtShell, 0, newDx, newDy, 0);
- amSnowball: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSnowball, 0, newDx, newDy, 0);
- amBee: newGear:= AddGear(hwRound(lx), hwRound(ly), gtBee, 0, newDx, newDy, 0);
- amShotgun: begin
- PlaySound(sndShotgunReload);
- newGear:= AddGear(hwRound(lx), hwRound(ly), gtShotgunShot, 0, xx * _0_5, yy * _0_5, 0);
- end;
- amPickHammer: newGear:= AddGear(hwRound(lx), hwRound(ly) + cHHRadius, gtPickHammer, 0, _0, _0, 0);
- amSkip: ParseCommand('/skip', true);
- amRope: newGear:= AddGear(hwRound(lx), hwRound(ly), gtRope, 0, xx, yy, 0);
- amMine: if altUse then
- newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtMine, gstWait, newDx, newDy, 3000)
- else
- newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtMine, gstWait, SignAs(_0_02, dX), _0, 3000);
- amSMine: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSMine, 0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
- amDEagle: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtDEagleShot, 0, xx * _0_5, yy * _0_5, 0);
- amSineGun: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSineGunShot, 0, xx * _0_5, yy * _0_5, 0);
- amPortalGun: begin
- newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtPortal, 0, xx * _0_6, yy * _0_6,
- // set selected color
- CurWeapon^.Pos);
- end;
- amSniperRifle: begin
- PlaySound(sndSniperReload);
- newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSniperRifleShot, 0, xx * _0_5, yy * _0_5, 0);
- end;
- amDynamite: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtDynamite, 0, SignAs(_0_03, dX), _0, 5000);
- amFirePunch: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtFirePunch, 0, xx, _0, 0);
- amWhip: begin
- newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtWhip, 0, SignAs(_1, dX), - _0_8, 0);
- PlaySound(sndWhipCrack)
- end;
- amHammer: begin
- newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtHammer, 0, SignAs(_1, dX), - _0_8, 0);
- PlaySound(sndWhack)
- end;
- amBaseballBat: begin
- newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtShover, gsttmpFlag, xx * _0_5, yy * _0_5, 0);
- PlaySound(sndBaseballBat) // TODO: Only play if something is hit?
- end;
- amParachute: begin
- newGear:= AddGear(hwRound(lx), hwRound(ly), gtParachute, 0, _0, _0, 0);
- PlaySound(sndParachute)
- end;
- // we save CurWeapon^.Pos (in this case: cursor direction) by using it as (otherwise irrelevant) X value of the new gear.
- amAirAttack: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 0, _0, _0, 0);
- amMineStrike: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 1, _0, _0, 0);
- amDrillStrike: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 3, _0, _0, CurWeapon^.Timer);
- amNapalm: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 2, _0, _0, 0);
- amBlowTorch: newGear:= AddGear(hwRound(lx), hwRound(ly), gtBlowTorch, 0, SignAs(_0_5, dX), _0, 0);
- amGirder: newGear:= AddGear(0, 0, gtGirder, CurWeapon^.Pos, _0, _0, 0);
- amTeleport: newGear:= AddGear(CurWeapon^.Pos, 0, gtTeleport, 0, _0, _0, 0);
- amSwitch: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSwitcher, 0, _0, _0, 0);
- amMortar: begin
- playSound(sndMortar);
- newGear:= AddGear(hwRound(lx), hwRound(ly), gtMortar, 0, xx*cMaxPower/cPowerDivisor, yy*cMaxPower/cPowerDivisor, 0);
- end;
- amRCPlane: begin
- newGear:= AddGear(hwRound(lx), hwRound(ly), gtRCPlane, 0, xx * cMaxPower / cPowerDivisor / 4, yy * cMaxPower / cPowerDivisor / 4, 0);
- newGear^.SoundChannel:= LoopSound(sndRCPlane, nil)
- end;
- amKamikaze: newGear:= AddGear(hwRound(lx), hwRound(ly), gtKamikaze, 0, xx * _0_5, yy * _0_5, 0);
- amCake: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 3, hwRound(ly), gtCake, 0, xx, _0, 0);
- amSeduction: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSeduction, 0, _0, _0, 0);
- amWatermelon: newGear:= AddGear(hwRound(lx), hwRound(ly), gtWatermelon, 0, newDx, newDy, CurWeapon^.Timer);
- amHellishBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtHellishBomb, 0, newDx, newDy, 0);
- amDrill: newGear:= AddGear(hwRound(lx), hwRound(ly), gtDrill, 0, newDx, newDy, 0);
- amBallgun: newGear:= AddGear(hwRound(X), hwRound(Y), gtBallgun, 0, xx * _0_5, yy * _0_5, 0);
- amJetpack: newGear:= AddGear(hwRound(lx), hwRound(ly), gtJetpack, 0, _0, _0, 0);
- amBirdy: begin
- PlaySound(sndWhistle);
- newGear:= AddGear(hwRound(lx), hwRound(ly) - 32, gtBirdy, 0, _0, _0, 0);
- end;
- amLowGravity: begin
- PlaySound(sndLowGravity);
- cGravity:= cMaxWindSpeed;
- cGravityf:= 0.00025
- end;
- amExtraDamage:begin
- PlaySound(sndHellishImpact4);
- cDamageModifier:= _1_5
- end;
- amInvulnerable: Invulnerable:= true;
- amExtraTime: begin
- PlaySound(sndSwitchHog);
- TurnTimeLeft:= TurnTimeLeft + 30000
- end;
- amLaserSight: cLaserSighting:= true;
- amVampiric: begin
- PlaySound(sndOw1, Team^.voicepack);
- cVampiric:= true;
- end;
- amPiano: begin
- // Tuck the hedgehog away until the piano attack is completed
- Unplaced:= true;
- X:= _0;
- Y:= _0;
- newGear:= AddGear(TargetPoint.X, 0, gtPiano, 0, _0, _0, 0);
- PauseMusic
- end;
- amFlamethrower: newGear:= AddGear(hwRound(X), hwRound(Y), gtFlamethrower, 0, xx * _0_5, yy * _0_5, 0);
- amLandGun: newGear:= AddGear(hwRound(X), hwRound(Y), gtLandGun, 0, xx * _0_5, yy * _0_5, 0);
- amResurrector: begin
- newGear:= AddGear(hwRound(lx), hwRound(ly),
- gtResurrector, 0, _0, _0, 0);
- newGear^.SoundChannel := LoopSound(sndResurrector);
- end;
- //amMelonStrike: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 4, _0, _0, 0);
- amStructure: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtStructure, gstWait, SignAs(_0_02, dX), _0, 3000);
- amTardis: newGear:= AddGear(hwRound(X), hwRound(Y), gtTardis, 0, _0, _0, 5000);
- end;
- case CurAmmoType of
- amGrenade, amMolotov,
- amClusterBomb, amGasBomb,
- amBazooka, amSnowball,
- amBee, amSMine,
- amMortar, amWatermelon,
- amHellishBomb, amDrill: FollowGear:= newGear;
-
- amShotgun, amPickHammer,
- amRope, amDEagle,
- amSineGun, amSniperRifle,
- amFirePunch, amWhip,
- amHammer, amBaseballBat,
- amParachute, amBlowTorch,
- amGirder, amTeleport,
- amSwitch, amRCPlane,
- amKamikaze, amCake,
- amSeduction, amBallgun,
- amJetpack, amBirdy,
- amFlamethrower, amLandGun,
- amResurrector, amStructure,
- amTardis, amPiano: CurAmmoGear:= newGear;
- end;
- if (CurAmmoType = amMine) or (CurAmmoType = amSMine) and (GameFlags and gfInfAttack <> 0) then newGear^.FlightTime:= GameTicks + 1000;
- if Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then
- begin
- newGear^.Target.X:= TargetPoint.X;
- newGear^.Target.Y:= TargetPoint.Y
- end;
-
- // Clear FollowGear if using on a rope/parachute/saucer etc so focus stays with the hog's movement
- if altUse then FollowGear:= nil;
-
- if (newGear <> nil) and ((Ammoz[newGear^.AmmoType].Ammo.Propz and ammoprop_SetBounce) <> 0) then
- begin
- elastic:= int2hwfloat(CurWeapon^.Bounciness) / _1000;
-
- if elastic < _1 then newGear^.Elasticity:= newGear^.Elasticity * elastic
- else if elastic > _1 then newGear^.Elasticity:= _1 - ((_1-newGear^.Elasticity) / elastic);
-(* Experimented with friction modifier. Didn't seem helpful
- fric:= int2hwfloat(CurWeapon^.Bounciness) / _250;
- if fric < _1 then newGear^.Friction:= newGear^.Friction * fric
- else if fric > _1 then newGear^.Friction:= _1 - ((_1-newGear^.Friction) / fric)*)
- end;
-
-
- uStats.AmmoUsed(CurAmmoType);
-
- if not (SpeechText = '') then
- begin
- speech:= AddVisualGear(0, 0, vgtSpeechBubble);
- if speech <> nil then
- begin
- speech^.Text:= SpeechText;
- speech^.Hedgehog:= Gear^.Hedgehog;
- speech^.FrameTicks:= SpeechType;
- end;
- SpeechText:= ''
- end;
-
- Power:= 0;
- if (CurAmmoGear <> nil)
- and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) = 0){check for dropping ammo from rope} then
- begin
- Message:= Message or gmAttack;
- CurAmmoGear^.Message:= Message
- end else begin
- if not CurrentTeam^.ExtDriven and
- ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0) then SendIPC('a');
- AfterAttack;
- end
- end else Message:= Message and (not gmAttack);
- end;
- TargetPoint.X := NoPointX;
- ScriptCall('onHogAttack');
-end;
-
-procedure AfterAttack;
-var s: shortstring;
- a: TAmmoType;
-begin
-with CurrentHedgehog^.Gear^,
- CurrentHedgehog^ do
- begin
- a:= CurAmmoType;
- State:= State and (not gstAttacking);
- if (Ammoz[a].Ammo.Propz and ammoprop_Effect) = 0 then
- begin
- Inc(MultiShootAttacks);
-
- if (Ammoz[a].Ammo.NumPerTurn >= MultiShootAttacks) then
- begin
- s:= inttostr(Ammoz[a].Ammo.NumPerTurn - MultiShootAttacks + 1);
- AddCaption(format(trmsg[sidRemaining], s), cWhiteColor, capgrpAmmostate);
- end;
-
- if (Ammoz[a].Ammo.NumPerTurn >= MultiShootAttacks) or
- ((GameFlags and gfMultiWeapon) <> 0) then
- begin
- isInMultiShoot:= true
- end
- else
- begin
- OnUsedAmmo(CurrentHedgehog^);
- if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) = 0) and (((GameFlags and gfInfAttack) = 0) or PlacingHogs) then
- begin
- if TagTurnTimeLeft = 0 then TagTurnTimeLeft:= TurnTimeLeft;
- TurnTimeLeft:=(Ammoz[a].TimeAfterTurn * cGetAwayTime) div 100;
- end;
- if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) = 0) then State:= State or gstAttacked;
- if (Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) <> 0 then ApplyAmmoChanges(CurrentHedgehog^)
- end;
- end
- else
- begin
- OnUsedAmmo(CurrentHedgehog^);
- ApplyAmmoChanges(CurrentHedgehog^);
- end;
- AttackBar:= 0
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepHedgehogDead(Gear: PGear);
-const frametime = 200;
- timertime = frametime * 6;
-begin
-if Gear^.Hedgehog^.Unplaced then exit;
-if Gear^.Timer > 1 then
- begin
- AllInactive:= false;
- dec(Gear^.Timer);
- if (Gear^.Timer mod frametime) = 0 then inc(Gear^.Pos)
- end
-else if Gear^.Timer = 1 then
- begin
- Gear^.State:= Gear^.State or gstNoDamage;
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, CurrentHedgehog, EXPLAutoSound);
- AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtGrave, 0, _0, _0, 0)^.Hedgehog:= Gear^.Hedgehog;
- DeleteGear(Gear);
- SetAllToActive
- end
-else // Gear^.Timer = 0
- begin
- AllInactive:= false;
- Gear^.Z:= cCurrHHZ;
- RemoveGearFromList(Gear);
- InsertGearToList(Gear);
- PlaySound(sndByeBye, Gear^.Hedgehog^.Team^.voicepack);
- Gear^.Pos:= 0;
- Gear^.Timer:= timertime
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepHedgehogGone(Gear: PGear);
-const frametime = 65;
- timertime = frametime * 11;
-begin
-if Gear^.Hedgehog^.Unplaced then exit;
-if Gear^.Timer > 1 then
- begin
- AllInactive:= false;
- dec(Gear^.Timer);
- if (Gear^.Timer mod frametime) = 0 then inc(Gear^.Pos)
- end else
-if Gear^.Timer = 1 then
- begin
- DeleteGear(Gear);
- SetAllToActive
- end else // Gear^.Timer = 0
- begin
- AllInactive:= false;
- Gear^.Z:= cCurrHHZ;
- RemoveGearFromList(Gear);
- InsertGearToList(Gear);
- PlaySound(sndByeBye, Gear^.Hedgehog^.Team^.voicepack);
- PlaySound(sndWarp);
- Gear^.Pos:= 0;
- Gear^.Timer:= timertime
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure PickUp(HH, Gear: PGear);
-var s: shortstring;
- a: TAmmoType;
- i: LongInt;
- vga: PVisualGear;
-begin
-Gear^.Message:= gmDestroy;
-PlaySound(sndShotgunReload);
-if (Gear^.Pos and posCaseExplode) <> 0 then
- if (Gear^.Pos and posCasePoison) <> 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound + EXPLPoisoned)
- else
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound)
-else if (Gear^.Pos and posCasePoison) <> 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound + EXPLPoisoned + EXPLNoDamage)
-else
-case Gear^.Pos of
- posCaseUtility,
- posCaseAmmo: begin
- if Gear^.AmmoType <> amNothing then a:= Gear^.AmmoType
- else
- begin
- for i:= 0 to GameTicks and $7F do GetRandom(2); // Burn some random numbers
- if Gear^.Pos = posCaseUtility then a:= GetUtility
- else a:= GetAmmo
- end;
- AddAmmo(HH^.Hedgehog^, a);
-// Possibly needs to check shared clan ammo game flag once added.
-// On the other hand, no obvious reason that clan members shouldn't know what ammo another clan member picked up
- if (not (HH^.Hedgehog^.Team^.ExtDriven
- or (HH^.Hedgehog^.BotLevel > 0)))
- or (HH^.Hedgehog^.Team^.Clan^.ClanIndex = LocalClan)
- or (GameType = gmtDemo) then
- begin
- s:= trammo[Ammoz[a].NameId] + ' (+' + IntToStr(Ammoz[a].NumberInCase) + ')';
- AddCaption(s, HH^.Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo);
-
- // show ammo icon
- vga:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtAmmo);
- if vga <> nil then
- vga^.Frame:= Longword(a);
- end;
-
- end;
- posCaseHealth: begin
- inc(HH^.Health, Gear^.Health);
- HH^.Hedgehog^.Effects[hePoisoned] := false;
- str(Gear^.Health, s);
- s:= '+' + s;
- AddCaption(s, HH^.Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo);
- RenderHealth(HH^.Hedgehog^);
- RecountTeamHealth(HH^.Hedgehog^.Team);
-
- i:= 0;
- while i < Gear^.Health do
- begin
- vga:= AddVisualGear(hwRound(HH^.X), hwRound(HH^.Y), vgtStraightShot);
- if vga <> nil then
- with vga^ do
- begin
- Tint:= $00FF00FF;
- State:= ord(sprHealth)
- end;
- inc(i, 5);
- end;
- end;
- end
-end;
-
-const StepTicks: LongWord = 0;
-
-procedure HedgehogStep(Gear: PGear);
-var PrevdX: LongInt;
- CurWeapon: PAmmo;
-begin
-CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^);
-if ((Gear^.State and (gstAttacking or gstMoving)) = 0) then
- begin
- if isCursorVisible then
- with Gear^.Hedgehog^ do
- with CurWeapon^ do
- begin
- if (Gear^.Message and gmLeft ) <> 0 then
- Pos:= (Pos - 1 + Ammoz[AmmoType].PosCount) mod Ammoz[AmmoType].PosCount
- else
- if (Gear^.Message and gmRight ) <> 0 then
- Pos:= (Pos + 1) mod Ammoz[AmmoType].PosCount
- else exit;
- StepTicks:= 200;
- exit
- end;
-
- if ((Gear^.Message and gmAnimate) <> 0) then
- begin
- Gear^.Message:= 0;
- Gear^.State:= Gear^.State or gstAnimation;
- Gear^.Tag:= Gear^.MsgParam;
- Gear^.Timer:= 0;
- Gear^.Pos:= 0
- end;
-
- if ((Gear^.Message and gmLJump ) <> 0) then
- begin
- Gear^.Message:= Gear^.Message and (not gmLJump);
- DeleteCI(Gear);
- if TestCollisionYwithGear(Gear, -1) = 0 then
- if not TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) then Gear^.Y:= Gear^.Y - _2 else
- if not TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) then Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithGear(Gear, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then
- begin
- Gear^.dY:= -_0_15;
- if not cArtillery then Gear^.dX:= SignAs(_0_15, Gear^.dX);
- Gear^.State:= Gear^.State or gstMoving or gstHHJumping;
- PlaySound(sndJump1, Gear^.Hedgehog^.Team^.voicepack);
- exit
- end;
- end;
-
- if ((Gear^.Message and gmHJump ) <> 0) then
- begin
- DeleteCI(Gear);
- Gear^.Message:= Gear^.Message and (not gmHJump);
-
- Gear^.dY:= -_0_2;
- SetLittle(Gear^.dX);
- Gear^.State:= Gear^.State or gstMoving or gstHHJumping;
- PlaySound(sndJump3, Gear^.Hedgehog^.Team^.voicepack);
- exit
- end;
-
- PrevdX:= hwSign(Gear^.dX);
- if (Gear^.Message and gmLeft )<>0 then Gear^.dX:= -cLittle else
- if (Gear^.Message and gmRight )<>0 then Gear^.dX:= cLittle else exit;
-
- if (Gear^.Message and (gmLeft or gmRight)) <> 0 then
- begin
- StepSoundTimer:= cHHStepTicks;
- end;
-
- StepTicks:= cHHStepTicks;
- if PrevdX <> hwSign(Gear^.dX) then
- begin
- FollowGear:= Gear;
- exit
- end;
- DeleteCI(Gear); // must be after exit!! (see previous line)
-
- Gear^.Hedgehog^.visStepPos:= (Gear^.Hedgehog^.visStepPos + 1) and 7;
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
- begin
- if not (TestCollisionXwithXYShift(Gear, _0, -6, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithXYShift(Gear, _0, -5, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithXYShift(Gear, _0, -4, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
- end;
-
- if (not cArtillery) and ((Gear^.Message and gmPrecise) = 0) and (not TestCollisionXwithGear(Gear, hwSign(Gear^.dX))) then
- Gear^.X:= Gear^.X + SignAs(_1, Gear^.dX);
-
- SetAllHHToActive;
-
- if TestCollisionYwithGear(Gear, 1) = 0 then
- begin
- Gear^.Y:= Gear^.Y + _1;
- if TestCollisionYwithGear(Gear, 1) = 0 then
- begin
- Gear^.Y:= Gear^.Y + _1;
- if TestCollisionYwithGear(Gear, 1) = 0 then
- begin
- Gear^.Y:= Gear^.Y + _1;
- if TestCollisionYwithGear(Gear, 1) = 0 then
- begin
- Gear^.Y:= Gear^.Y + _1;
- if TestCollisionYwithGear(Gear, 1) = 0 then
- begin
- Gear^.Y:= Gear^.Y + _1;
- if TestCollisionYwithGear(Gear, 1) = 0 then
- begin
- Gear^.Y:= Gear^.Y + _1;
- if TestCollisionYwithGear(Gear, 1) = 0 then
- begin
- Gear^.Y:= Gear^.Y - _6;
- Gear^.dY:= _0;
- Gear^.State:= Gear^.State or gstMoving;
- exit
- end;
- end
- end
- end
- end
- end
- end;
- AddGearCI(Gear)
- end
-end;
-
-procedure HedgehogChAngle(HHGear: PGear);
-var da: LongWord;
-begin
-with HHGear^.Hedgehog^ do
- if ((CurAmmoType = amRope) and
- ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving)) or
- ((CurAmmoType = amPortalGun) and
- ((HHGear^.State and gstMoving) <> 0)) then da:= 2
- else da:= 1;
-
-if (((HHGear^.Message and gmPrecise) = 0) or ((GameTicks mod 5) = 1)) then
- if ((HHGear^.Message and gmUp) <> 0) and (HHGear^.Angle >= CurMinAngle + da) then dec(HHGear^.Angle, da)
- else
- if ((HHGear^.Message and gmDown) <> 0) and (HHGear^.Angle + da <= CurMaxAngle) then inc(HHGear^.Angle, da)
-end;
-
-procedure doStepHedgehog(Gear: PGear); forward;
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepHedgehogMoving(Gear: PGear);
-var isFalling, isUnderwater: boolean;
- land: Word;
-begin
-land:= 0;
-isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
-if Gear^.dX.QWordValue > 8160437862 then Gear^.dX.QWordValue:= 8160437862;
-if Gear^.dY.QWordValue > 8160437862 then Gear^.dY.QWordValue:= 8160437862;
-
-if Gear^.Hedgehog^.Unplaced then
- begin
- Gear^.dY:= _0;
- Gear^.dX:= _0;
- Gear^.State:= Gear^.State and (not gstMoving);
- exit
- end;
-isFalling:= (Gear^.dY.isNegative) or not TestCollisionYKick(Gear, 1);
-if isFalling then
- begin
- if (Gear^.dY.isNegative) and TestCollisionYKick(Gear, -1) then Gear^.dY:= _0;
- Gear^.State:= Gear^.State or gstMoving;
- if (CurrentHedgehog^.Gear = Gear)
- and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then
- begin
- FollowGear:= Gear;
- end;
- if isUnderwater then Gear^.dY:= Gear^.dY + cGravity / _2
- else
- begin
- Gear^.dY:= Gear^.dY + cGravity;
-// this set of circumstances could be less complex if jumping was more clearly identified
- if ((GameFlags and gfMoreWind) <> 0) and
- (((Gear^.Damage <> 0) or
- ((CurAmmoGear <> nil) and
- ((CurAmmoGear^.AmmoType = amJetpack) or
- (CurAmmoGear^.AmmoType = amBirdy))) or
- ((Gear^.dY.QWordValue + Gear^.dX.QWordValue) > _0_55.QWordValue)))
- then Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
- end
- end
-else
- begin
- land:= TestCollisionYwithGear(Gear, 1);
- if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_55.QWordValue) and ((land and lfIce) = 0)
- and ((Gear^.State and gstHHJumping) <> 0) then SetLittle(Gear^.dX);
-
- if not Gear^.dY.isNegative then
- begin
- CheckHHDamage(Gear);
-
- if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) and
- (Gear^.dX.QWordValue < _0_02.QWordValue) then Gear^.dX.isNegative:= not Gear^.dX.isNegative; // landing after high jump
-
- Gear^.State:= Gear^.State and (not (gstHHJumping or gstHHHJump));
- Gear^.dY:= _0;
- end else Gear^.dY:= Gear^.dY + cGravity;
-
- if ((Gear^.State and gstMoving) <> 0) then
- begin
- if land and lfIce <> 0 then
- begin
- Gear^.dX:= Gear^.dX * (_1 - (_1 - Gear^.Friction) / _2)
- end
- else Gear^.dX:= Gear^.dX * Gear^.Friction;
- end
- end;
-
-if (Gear^.State <> 0) then DeleteCI(Gear);
-
-if isUnderwater then
- begin
- Gear^.dY:= Gear^.dY * _0_999;
- Gear^.dX:= Gear^.dX * _0_999;
- end;
-
-if (Gear^.State and gstMoving) <> 0 then
- if TestCollisionXKick(Gear, hwSign(Gear^.dX)) then
- if not isFalling then
- if hwAbs(Gear^.dX) > _0_01 then
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -1, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_96; Gear^.Y:= Gear^.Y - _1 end else
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -2, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_93; Gear^.Y:= Gear^.Y - _2 end else
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -3, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_9 ; Gear^.Y:= Gear^.Y - _3 end else
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -4, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_87; Gear^.Y:= Gear^.Y - _4 end else
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -5, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_84; Gear^.Y:= Gear^.Y - _5 end else
- if hwAbs(Gear^.dX) > _0_02 then Gear^.dX:= -Gear^.Elasticity * Gear^.dX
- else begin
- Gear^.State:= Gear^.State and (not gstMoving);
- while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
- SetLittle(Gear^.dX)
- end
- else begin
- Gear^.State:= Gear^.State and (not gstMoving);
- while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
- SetLittle(Gear^.dX)
- end
- else if (hwAbs(Gear^.dX) > cLittle)
- and ((Gear^.State and gstHHJumping) = 0)
- then Gear^.dX:= -Gear^.Elasticity * Gear^.dX
- else SetLittle(Gear^.dX);
-
-if (not isFalling) and
- (hwAbs(Gear^.dX) + hwAbs(Gear^.dY) < _0_03) then
- begin
- Gear^.State:= Gear^.State and (not gstWinner);
- Gear^.State:= Gear^.State and (not gstMoving);
- while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
- SetLittle(Gear^.dX);
- Gear^.dY:= _0
- end else Gear^.State:= Gear^.State or gstMoving;
-
-if (Gear^.State and gstMoving) <> 0 then
- begin
- Gear^.State:= Gear^.State and (not gstAnimation);
-// ARTILLERY but not being moved by explosions
- Gear^.X:= Gear^.X + Gear^.dX;
- Gear^.Y:= Gear^.Y + Gear^.dY;
- if (not Gear^.dY.isNegative) and
- (not TestCollisionYKick(Gear, 1)) and
- TestCollisionYwithXYShift(Gear, 0, 1, 1) then
- begin
- CheckHHDamage(Gear);
- Gear^.dY:= _0;
- Gear^.Y:= Gear^.Y + _1
- end;
- CheckGearDrowning(Gear);
- // hide target cursor if current hog is drowning
- if (Gear^.State and gstDrowning) <> 0 then
- if (CurrentHedgehog^.Gear = Gear) then
- isCursorVisible:= false
- end;
-
-if (hwAbs(Gear^.dY) > _0) and (Gear^.FlightTime > 0) and ((GameFlags and gfLowGravity) = 0) then
- begin
- inc(Gear^.FlightTime);
- if Gear^.FlightTime = 3000 then
- begin
- AddCaption(GetEventString(eidHomerun), cWhiteColor, capgrpMessage);
- PlaySound(sndHomerun)
- end;
- end
-else
- begin
- uStats.hedgehogFlight(Gear, Gear^.FlightTime);
- Gear^.FlightTime:= 0;
- end;
-
-end;
-
-procedure doStepHedgehogDriven(HHGear: PGear);
-var t: PGear;
- wasJumping: boolean;
- Hedgehog: PHedgehog;
-begin
-Hedgehog:= HHGear^.Hedgehog;
-if isInMultiShoot then
- HHGear^.Message:= 0;
-
-if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_Utility) <> 0) and isInMultiShoot then
- AllInactive:= true
-else if not isInMultiShoot then AllInactive:= false;
-
-if (TurnTimeLeft = 0) or (HHGear^.Damage > 0) then
- begin
- if TagTurnTimeLeft = 0 then TagTurnTimeLeft:= TurnTimeLeft;
- TurnTimeLeft:= 0;
- isCursorVisible:= false;
- HHGear^.State:= HHGear^.State and (not (gstHHDriven or gstAnimation or gstAttacking));
- AttackBar:= 0;
- if HHGear^.Damage > 0 then
- HHGear^.State:= HHGear^.State and (not (gstHHJumping or gstHHHJump));
- exit
- end;
-
-if (HHGear^.State and gstAnimation) <> 0 then
- begin
- HHGear^.Message:= 0;
- if (HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].VoiceDelay) and (HHGear^.Timer = 0) then PlaySound(Wavez[TWave(HHGear^.Tag)].Voice, Hedgehog^.Team^.voicepack);
- inc(HHGear^.Timer);
- if HHGear^.Timer = Wavez[TWave(HHGear^.Tag)].Interval then
- begin
- HHGear^.Timer:= 0;
- inc(HHGear^.Pos);
- if HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].FramesCount then
- HHGear^.State:= HHGear^.State and (not gstAnimation)
- end;
- exit
- end;
-
-if ((HHGear^.State and gstMoving) <> 0)
- or (StepTicks = cHHStepTicks)
- or (CurAmmoGear <> nil) then // we are moving
- begin
- with Hedgehog^ do
- if (CurAmmoGear = nil)
- and (HHGear^.dY > _0_39)
- and (CurAmmoType = amParachute) then HHGear^.Message:= HHGear^.Message or gmAttack;
- // check for case with ammo
- t:= CheckGearNear(HHGear, gtCase, 36, 36);
- if t <> nil then
- PickUp(HHGear, t)
- end;
-
-if (CurAmmoGear = nil) then
- if (((HHGear^.Message and gmAttack) <> 0)
- or ((HHGear^.State and gstAttacking) <> 0)) then
- Attack(HHGear) // should be before others to avoid desync with '/put' msg and changing weapon msgs
- else
-else
- with Hedgehog^ do
- if ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
- and ((HHGear^.Message and gmLJump) <> 0)
- and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
- begin
- Attack(HHGear);
- HHGear^.Message:= HHGear^.Message and (not gmLJump)
- end;
-
-if (CurAmmoGear = nil)
- or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
- or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) then
- begin
- if ((HHGear^.Message and gmSlot) <> 0) then
- if ChangeAmmo(HHGear) then ApplyAmmoChanges(Hedgehog^);
-
- if ((HHGear^.Message and gmWeapon) <> 0) then HHSetWeapon(HHGear);
-
- if ((HHGear^.Message and gmTimer) <> 0) then HHSetTimer(HHGear);
- end;
-
-if CurAmmoGear <> nil then
- begin
- CurAmmoGear^.Message:= HHGear^.Message;
- exit
- end;
-
-if not isInMultiShoot then
- HedgehogChAngle(HHGear);
-
-if (HHGear^.State and gstMoving) <> 0 then
- begin
- wasJumping:= ((HHGear^.State and gstHHJumping) <> 0);
-
- if ((HHGear^.Message and gmHJump) <> 0) and
- wasJumping and
- ((HHGear^.State and gstHHHJump) = 0) then
- if (not (hwAbs(HHGear^.dX) > cLittle)) and (HHGear^.dY < -_0_02) then
- begin
- HHGear^.State:= HHGear^.State or gstHHHJump;
- HHGear^.dY:= -_0_25;
- if not cArtillery then HHGear^.dX:= -SignAs(_0_02, HHGear^.dX);
- PlaySound(sndJump2, Hedgehog^.Team^.voicepack)
- end;
-
- HHGear^.Message:= HHGear^.Message and (not (gmLJump or gmHJump));
-
- if (not cArtillery) and wasJumping and
- TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
-
- if Hedgehog^.Gear <> nil then doStepHedgehogMoving(HHGear);
-
- if ((HHGear^.State and (gstMoving or gstDrowning)) = 0) then
- begin
- AddGearCI(HHGear);
- if wasJumping then
- StepTicks:= 410
- else
- StepTicks:= 95
- end;
- exit
- end;
-
- if not isInMultiShoot and (Hedgehog^.Gear <> nil) then
- begin
- if StepTicks > 0 then dec(StepTicks);
- if (StepTicks = 0) then HedgehogStep(HHGear)
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepHedgehogFree(Gear: PGear);
-var prevState: Longword;
-begin
-prevState:= Gear^.State;
-
-doStepHedgehogMoving(Gear);
-
-if (Gear^.State and (gstMoving or gstDrowning)) <> 0 then
- begin
- if Gear^.Damage > 0 then CalcRotationDirAngle(Gear);
- AllInactive:= false;
- exit
- end;
-
-if (Gear^.Health = 0) then
- begin
- if PrvInactive or ((GameFlags and gfInfAttack) <> 0) then
- begin
- Gear^.Timer:= 0;
- FollowGear:= Gear;
- PrvInactive:= false;
- AllInactive:= false;
-
- if (Gear^.State and gstHHGone) = 0 then
- begin
- Gear^.Hedgehog^.Effects[hePoisoned] := false;
- if Gear^.Hedgehog^.Effects[heResurrectable] then begin
- ResurrectHedgehog(Gear);
- end else
- begin
- Gear^.State:= (Gear^.State or gstHHDeath) and (not gstAnimation);
- Gear^.doStep:= @doStepHedgehogDead;
- // Death message
- AddCaption(Format(GetEventString(eidDied), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
- end;
- end
- else
- begin
- Gear^.State:= Gear^.State and (not gstAnimation);
- Gear^.doStep:= @doStepHedgehogGone;
-
- // Gone message
- AddCaption(Format(GetEventString(eidGone), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
- end
- end;
- exit
- end;
-
-if ((Gear^.State and gstWait) = 0) and
- (prevState <> Gear^.State) then
- begin
- Gear^.State:= Gear^.State or gstWait;
- Gear^.Timer:= 150
- end else
- begin
- if Gear^.Timer = 0 then
- begin
- Gear^.State:= Gear^.State and (not (gstWait or gstLoser or gstWinner or gstAttacked or gstNotKickable or gstHHChooseTarget));
- Gear^.Active:= false;
- AddGearCI(Gear);
- exit
- end else dec(Gear^.Timer)
- end;
-
-AllInactive:= false
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepHedgehog(Gear: PGear);
-(*
-var x,y,tx,ty: LongInt;
- tdX, tdY, slope: hwFloat;
- land: Word; *)
-var slope: hwFloat;
-begin
-if (Gear^.Message and gmDestroy) <> 0 then
- begin
- DeleteGear(Gear);
- exit
- end;
-
-if (Gear^.State and gstHHDriven) = 0 then
- doStepHedgehogFree(Gear)
-else
- begin
- with Gear^.Hedgehog^ do
- if Team^.hasGone then
- TeamGoneEffect(Team^)
- else
- doStepHedgehogDriven(Gear)
- end;
-if (Gear^.Message and (gmAllStoppable or gmLJump or gmHJump) = 0) and
- (Gear^.State and (gstHHJumping or gstHHHJump or gstAttacking) = 0) and
- (not Gear^.dY.isNegative) and
- (GameTicks mod (100*LongWOrd(hwRound(cMaxWindSpeed*2/cGravity))) = 0) and
- (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
- begin
- slope:= CalcSlopeBelowGear(Gear);
- Gear^.dX:=Gear^.dX+slope*_0_07;
- if slope.QWordValue <> 0 then Gear^.State:= Gear^.State or gstMoving;
-(*
- x:= hwRound(Gear^.X);
- y:= hwRound(Gear^.Y);
- AddVisualGear(x, y, vgtSmokeTrace);
- AddVisualGear(x - hwRound(_5*slope), y + hwRound(_5*slope), vgtSmokeTrace);
- AddVisualGear(x + hwRound(_5*slope), y - hwRound(_5*slope), vgtSmokeTrace);
- AddVisualGear(x - hwRound(_20 * slope), y + hwRound(_20 * slope), vgtSmokeTrace);
- AddVisualGear(x + hwRound(_20 * slope), y - hwRound(_20 * slope), vgtSmokeTrace);
- AddVisualGear(x - hwRound(_30 * slope), y + hwRound(_30 * slope), vgtSmokeTrace);
- AddVisualGear(x + hwRound(_30 * slope), y - hwRound(_30 * slope), vgtSmokeTrace);
- AddVisualGear(x - hwRound(_40 * slope), y + hwRound(_40 * slope), vgtSmokeTrace);
- AddVisualGear(x + hwRound(_40 * slope), y - hwRound(_40 * slope), vgtSmokeTrace);
- AddVisualGear(x - hwRound(_50 * slope), y + hwRound(_50 * slope), vgtSmokeTrace);
- AddVisualGear(x + hwRound(_50 * slope), y - hwRound(_50 * slope), vgtSmokeTrace); *)
- end
-end;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uGearUtils.pas Fri Dec 30 13:54:39 2011 +0400
@@ -0,0 +1,126 @@
+unit uGearUtils;
+interface
+uses uTypes;
+
+procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord = $FFFFFFFF);
+
+implementation
+uses uGearsList;
+
+procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord);
+var Gear: PGear;
+ dmg, dmgRadius, dmgBase: LongInt;
+ fX, fY: hwFloat;
+ vg: PVisualGear;
+ i, cnt: LongInt;
+begin
+ if Radius > 4 then AddFileLog('Explosion: at (' + inttostr(x) + ',' + inttostr(y) + ')');
+ if Radius > 25 then KickFlakes(Radius, X, Y);
+
+ if ((Mask and EXPLNoGfx) = 0) then
+ begin
+ vg:= nil;
+ if Radius > 50 then vg:= AddVisualGear(X, Y, vgtBigExplosion)
+ else if Radius > 10 then vg:= AddVisualGear(X, Y, vgtExplosion);
+ if vg <> nil then
+ vg^.Tint:= Tint;
+ end;
+ if (Mask and EXPLAutoSound) <> 0 then PlaySound(sndExplosion);
+
+ if (Mask and EXPLAllDamageInRadius) = 0 then
+ dmgRadius:= Radius shl 1
+ else
+ dmgRadius:= Radius;
+ dmgBase:= dmgRadius + cHHRadius div 2;
+ fX:= int2hwFloat(X);
+ fY:= int2hwFloat(Y);
+ Gear:= GearsList;
+ while Gear <> nil do
+ begin
+ dmg:= 0;
+ //dmg:= dmgRadius + cHHRadius div 2 - hwRound(Distance(Gear^.X - int2hwFloat(X), Gear^.Y - int2hwFloat(Y)));
+ //if (dmg > 1) and
+ if (Gear^.State and gstNoDamage) = 0 then
+ begin
+ case Gear^.Kind of
+ gtHedgehog,
+ gtMine,
+ gtBall,
+ gtMelonPiece,
+ gtGrenade,
+ gtClusterBomb,
+ // gtCluster, too game breaking I think
+ gtSMine,
+ gtCase,
+ gtTarget,
+ gtFlame,
+ gtExplosives,
+ gtStructure: begin
+ // Run the calcs only once we know we have a type that will need damage
+ if hwRound(hwAbs(Gear^.X-fX)+hwAbs(Gear^.Y-fY)) < dmgBase then
+ dmg:= dmgBase - max(hwRound(Distance(Gear^.X - fX, Gear^.Y - fY)),Gear^.Radius);
+ if dmg > 1 then
+ begin
+ dmg:= ModifyDamage(min(dmg div 2, Radius), Gear);
+ //AddFileLog('Damage: ' + inttostr(dmg));
+ if (Mask and EXPLNoDamage) = 0 then
+ begin
+ if not Gear^.Invulnerable then
+ ApplyDamage(Gear, AttackingHog, dmg, dsExplosion)
+ else
+ Gear^.State:= Gear^.State or gstWinner;
+ end;
+ if ((Mask and EXPLDoNotTouchAny) = 0) and (((Mask and EXPLDoNotTouchHH) = 0) or (Gear^.Kind <> gtHedgehog)) then
+ begin
+ DeleteCI(Gear);
+ if Gear^.Kind <> gtHedgehog then
+ begin
+ Gear^.dX:= Gear^.dX + SignAs(_0_005 * dmg + cHHKick, Gear^.X - fX)/Gear^.Density;
+ Gear^.dY:= Gear^.dY + SignAs(_0_005 * dmg + cHHKick, Gear^.Y - fY)/Gear^.Density;
+ end
+ else
+ begin
+ Gear^.dX:= Gear^.dX + SignAs(_0_005 * dmg + cHHKick, Gear^.X - fX);
+ Gear^.dY:= Gear^.dY + SignAs(_0_005 * dmg + cHHKick, Gear^.Y - fY);
+ end;
+
+ Gear^.State:= (Gear^.State or gstMoving) and (not gstLoser);
+ if not Gear^.Invulnerable then
+ Gear^.State:= (Gear^.State or gstMoving) and (not gstWinner);
+ Gear^.Active:= true;
+ if Gear^.Kind <> gtFlame then FollowGear:= Gear
+ end;
+ if ((Mask and EXPLPoisoned) <> 0) and (Gear^.Kind = gtHedgehog) and (not Gear^.Invulnerable) then
+ Gear^.Hedgehog^.Effects[hePoisoned] := true;
+ end;
+
+ end;
+ gtGrave: begin
+ // Run the calcs only once we know we have a type that will need damage
+ if hwRound(hwAbs(Gear^.X-fX)+hwAbs(Gear^.Y-fY)) < dmgBase then
+ dmg:= dmgBase - hwRound(Distance(Gear^.X - fX, Gear^.Y - fY));
+ if dmg > 1 then
+ begin
+ dmg:= ModifyDamage(min(dmg div 2, Radius), Gear);
+ Gear^.dY:= - _0_004 * dmg;
+ Gear^.Active:= true
+ end
+ end;
+ end;
+ end;
+ Gear:= Gear^.NextGear
+ end;
+
+ if (Mask and EXPLDontDraw) = 0 then
+ if (GameFlags and gfSolidLand) = 0 then
+ begin
+ cnt:= DrawExplosion(X, Y, Radius) div 1608; // approx 2 16x16 circles to erase per chunk
+ if (cnt > 0) and (SpritesData[sprChunk].Texture <> nil) then
+ for i:= 0 to cnt do
+ AddVisualGear(X, Y, vgtChunk)
+ end;
+
+ uAIMisc.AwareOfExplosion(0, 0, 0)
+end;
+
+end.
--- a/hedgewars/uGears.pas Tue Nov 29 17:42:42 2011 +0400
+++ b/hedgewars/uGears.pas Fri Dec 30 13:54:39 2011 +0400
@@ -37,17 +37,14 @@
procedure initModule;
procedure freeModule;
-function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content: Longword ): PGear;
function SpawnFakeCrateAt(x, y: LongInt; crate: TCrateType; explode: boolean; poison: boolean ): PGear;
function GetAmmo: TAmmoType;
function GetUtility: TAmmoType;
-procedure ResurrectHedgehog(gear: PGear);
procedure HideHog(HH: PHedgehog);
procedure RestoreHog(HH: PHedgehog);
procedure ProcessGears;
procedure EndTurnCleanup;
-procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
procedure SetAllToActive;
procedure SetAllHHToActive;
procedure DrawGears;
@@ -57,27 +54,20 @@
function GearByUID(uid : Longword) : PGear;
procedure InsertGearToList(Gear: PGear);
procedure RemoveGearFromList(Gear: PGear);
-function ModifyDamage(dmg: Longword; Gear: PGear): Longword;
-procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean = false);
procedure DeleteGear(Gear: PGear);
implementation
uses uStore, uSound, uTeams, uRandom, uCollisions, uIO, uLandGraphics,
uAIMisc, uLocale, uAI, uAmmos, uStats, uVisualGears, uScript, GLunit, uMobile, uVariables,
- uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug, uLandTexture;
+ uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug, uLandTexture,
+ uGearsHedgehog;
-procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord = $FFFFFFFF); forward;
procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); forward;
//procedure AmmoFlameWork(Ammo: PGear); forward;
function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): TPGearArray; forward;
-function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear; forward;
procedure SpawnBoxOfSmth; forward;
-procedure AfterAttack; forward;
-procedure HedgehogStep(Gear: PGear); forward;
-procedure doStepHedgehogMoving(Gear: PGear); forward;
-procedure HedgehogChAngle(HHGear: PGear); forward;
procedure ShotgunShot(Gear: PGear); forward;
procedure PickUp(HH, Gear: PGear); forward;
procedure HHSetWeapon(HHGear: PGear); forward;
@@ -88,7 +78,6 @@
// Note: step handlers of gears that are hedgehogs are in a different file
// than the handlers for all other gears.
{$INCLUDE "GSHandlers.inc"}
-{$INCLUDE "HHHandlers.inc"}
const doStepHandlers: array[TGearType] of TGearStepProcedure = (
@doStepBomb,
@@ -154,523 +143,6 @@
@doStepLandGun,
@doStepTardis);
-procedure InsertGearToList(Gear: PGear);
-var tmp, ptmp: PGear;
-begin
- tmp:= GearsList;
- ptmp:= GearsList;
- while (tmp <> nil) and (tmp^.Z <= Gear^.Z) do
- begin
- ptmp:= tmp;
- tmp:= tmp^.NextGear
- end;
-
- if ptmp <> tmp then
- begin
- Gear^.NextGear:= ptmp^.NextGear;
- Gear^.PrevGear:= ptmp;
- if ptmp^.NextGear <> nil then ptmp^.NextGear^.PrevGear:= Gear;
- ptmp^.NextGear:= Gear
- end
- else
- begin
- Gear^.NextGear:= GearsList;
- if Gear^.NextGear <> nil then Gear^.NextGear^.PrevGear:= Gear;
- GearsList:= Gear;
- end;
-end;
-
-procedure RemoveGearFromList(Gear: PGear);
-begin
-if Gear^.NextGear <> nil then Gear^.NextGear^.PrevGear:= Gear^.PrevGear;
-if Gear^.PrevGear <> nil then
- Gear^.PrevGear^.NextGear:= Gear^.NextGear
-else
- GearsList:= Gear^.NextGear
-end;
-
-procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword);
-var tag: PVisualGear;
-begin
-tag:= AddVisualGear(hwRound(HHGear^.X), hwRound(HHGear^.Y), vgtHealthTag, dmg);
-if (tag <> nil) then
- tag^.Hedgehog:= HHGear^.Hedgehog; // the tag needs the tag to determine the text color
-AllInactive:= false;
-HHGear^.Active:= true;
-end;
-
-function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
-const Counter: Longword = 0;
-var gear: PGear;
-begin
-inc(Counter);
-AddFileLog('AddGear: #' + inttostr(Counter) + ' (' + inttostr(x) + ',' + inttostr(y) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
-
-New(gear);
-FillChar(gear^, sizeof(TGear), 0);
-gear^.X:= int2hwFloat(X);
-gear^.Y:= int2hwFloat(Y);
-gear^.Target.X:= NoPointX;
-gear^.Kind := Kind;
-gear^.State:= State;
-gear^.Active:= true;
-gear^.dX:= dX;
-gear^.dY:= dY;
-gear^.doStep:= doStepHandlers[Kind];
-gear^.CollisionIndex:= -1;
-gear^.Timer:= Timer;
-gear^.FlightTime:= 0;
-gear^.uid:= Counter;
-gear^.SoundChannel:= -1;
-gear^.ImpactSound:= sndNone;
-gear^.nImpactSounds:= 0;
-gear^.Density:= _1;
-// Define ammo association, if any.
-gear^.AmmoType:= GearKindAmmoTypeMap[Kind];
-if Ammoz[Gear^.AmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then gear^.Z:= cHHZ+1
-else gear^.Z:= cUsualZ;
-
-if CurrentHedgehog <> nil then
- begin
- gear^.Hedgehog:= CurrentHedgehog;
- gear^.IntersectGear:= CurrentHedgehog^.Gear
- end;
-
-case Kind of
- gtGrenade,
- gtClusterBomb,
- gtGasBomb: begin
- gear^.ImpactSound:= sndGrenadeImpact;
- gear^.nImpactSounds:= 1;
- gear^.AdvBounce:= 1;
- gear^.Radius:= 5;
- gear^.Elasticity:= _0_8;
- gear^.Friction:= _0_8;
- gear^.Density:= _1_5;
- gear^.RenderTimer:= true;
- if gear^.Timer = 0 then gear^.Timer:= 3000
- end;
- gtWatermelon: begin
- gear^.ImpactSound:= sndMelonImpact;
- gear^.nImpactSounds:= 1;
- gear^.AdvBounce:= 1;
- gear^.Radius:= 6;
- gear^.Elasticity:= _0_8;
- gear^.Friction:= _0_995;
- gear^.Density:= _2;
- gear^.RenderTimer:= true;
- if gear^.Timer = 0 then gear^.Timer:= 3000
- end;
- gtMelonPiece: begin
- gear^.Density:= _2;
- end;
- gtHedgehog: begin
- gear^.AdvBounce:= 1;
- gear^.Radius:= cHHRadius;
- gear^.Elasticity:= _0_35;
- gear^.Friction:= _0_999;
- gear^.Angle:= cMaxAngle div 2;
- gear^.Density:= _3;
- gear^.Z:= cHHZ;
- if (GameFlags and gfAISurvival) <> 0 then
- if gear^.Hedgehog^.BotLevel > 0 then
- gear^.Hedgehog^.Effects[heResurrectable] := true;
- end;
- gtShell: begin
- gear^.Radius:= 4;
- gear^.Density:= _1;
- end;
- gtSnowball: begin
- gear^.ImpactSound:= sndMudballImpact;
- gear^.nImpactSounds:= 1;
- gear^.Radius:= 4;
- gear^.Elasticity:= _1;
- gear^.Friction:= _1;
- gear^.Density:= _0_5;
- end;
-
- gtFlake: begin
- with Gear^ do
- begin
- Pos:= 0;
- Radius:= 1;
- DirAngle:= random * 360;
- if State and gstTmpFlag = 0 then
- begin
- dx.isNegative:= GetRandom(2) = 0;
- dx.QWordValue:= GetRandom(100000000);
- dy.isNegative:= false;
- dy.QWordValue:= GetRandom(70000000);
- if GetRandom(2) = 0 then dx := -dx
- end;
- State:= State or gstInvisible;
- Health:= random(vobFrameTicks);
- Timer:= random(vobFramesCount);
- Angle:= (random(2) * 2 - 1) * (1 + random(10000)) * vobVelocity
- end
- end;
- gtGrave: begin
- gear^.ImpactSound:= sndGraveImpact;
- gear^.nImpactSounds:= 1;
- gear^.Radius:= 10;
- gear^.Elasticity:= _0_6;
- end;
- gtBee: begin
- gear^.Radius:= 5;
- gear^.Timer:= 500;
- gear^.RenderTimer:= true;
- gear^.Elasticity:= _0_9;
- gear^.Tag:= 0;
- end;
- gtSeduction: begin
- gear^.Radius:= 250;
- end;
- gtShotgunShot: begin
- gear^.Timer:= 900;
- gear^.Radius:= 2
- end;
- gtPickHammer: begin
- gear^.Radius:= 10;
- gear^.Timer:= 4000
- end;
- gtHammerHit: begin
- gear^.Radius:= 8;
- gear^.Timer:= 125
- end;
- gtRope: begin
- gear^.Radius:= 3;
- gear^.Friction:= _450 * _0_01 * cRopePercent;
- RopePoints.Count:= 0;
- end;
- gtMine: begin
- gear^.ImpactSound:= sndMineImpact;
- gear^.nImpactSounds:= 1;
- gear^.Health:= 10;
- gear^.State:= gear^.State or gstMoving;
- gear^.Radius:= 2;
- gear^.Elasticity:= _0_55;
- gear^.Friction:= _0_995;
- gear^.Density:= _0_9;
- if cMinesTime < 0 then
- gear^.Timer:= getrandom(51)*100
- else
- gear^.Timer:= cMinesTime;
- end;
- gtSMine: begin
- gear^.Health:= 10;
- gear^.State:= gear^.State or gstMoving;
- gear^.Radius:= 2;
- gear^.Elasticity:= _0_55;
- gear^.Friction:= _0_995;
- gear^.Density:= _0_9;
- gear^.Timer:= 500;
- end;
- gtCase: begin
- gear^.ImpactSound:= sndGraveImpact;
- gear^.nImpactSounds:= 1;
- gear^.Radius:= 16;
- gear^.Elasticity:= _0_3
- end;
- gtExplosives: begin
- gear^.ImpactSound:= sndGrenadeImpact;
- gear^.nImpactSounds:= 1;
- gear^.Radius:= 16;
- gear^.Elasticity:= _0_4;
- gear^.Friction:= _0_995;
- gear^.Density:= _6;
- gear^.Health:= cBarrelHealth;
- gear^.Z:= cHHZ-1
- end;
- gtDEagleShot: begin
- gear^.Radius:= 1;
- gear^.Health:= 50
- end;
- gtSniperRifleShot: begin
- gear^.Radius:= 1;
- gear^.Health:= 50
- end;
- gtDynamite: begin
- gear^.Radius:= 3;
- gear^.Elasticity:= _0_55;
- gear^.Friction:= _0_03;
- gear^.Density:= _2;
- gear^.Timer:= 5000;
- end;
- gtCluster: begin
- gear^.Radius:= 2;
- gear^.Density:= _1_5;
- gear^.RenderTimer:= true
- end;
- gtShover: gear^.Radius:= 20;
- gtFlame: begin
- gear^.Tag:= GetRandom(32);
- gear^.Radius:= 1;
- gear^.Health:= 5;
- gear^.Density:= _1;
- if (gear^.dY.QWordValue = 0) and (gear^.dX.QWordValue = 0) then
- begin
- gear^.dY:= (getrandom - _0_8) * _0_03;
- gear^.dX:= (getrandom - _0_5) * _0_4
- end
- end;
- gtFirePunch: begin
- gear^.Radius:= 15;
- gear^.Tag:= Y
- end;
- gtAirBomb: begin
- gear^.Radius:= 5;
- gear^.Density:= _2;
- end;
- gtBlowTorch: begin
- gear^.Radius:= cHHRadius + cBlowTorchC;
- gear^.Timer:= 7500
- end;
- gtSwitcher: begin
- gear^.Z:= cCurrHHZ
- end;
- gtTarget: begin
- gear^.ImpactSound:= sndGrenadeImpact;
- gear^.nImpactSounds:= 1;
- gear^.Radius:= 10;
- gear^.Elasticity:= _0_3;
- gear^.Timer:= 0
- end;
- gtTardis: begin
- gear^.Timer:= 0;
- gear^.Pos:= 1;
- gear^.Z:= cCurrHHZ+1;
- end;
- gtMortar: begin
- gear^.Radius:= 4;
- gear^.Elasticity:= _0_2;
- gear^.Friction:= _0_08;
- gear^.Density:= _1;
- end;
- gtWhip: gear^.Radius:= 20;
- gtHammer: gear^.Radius:= 20;
- gtKamikaze: begin
- gear^.Health:= 2048;
- gear^.Radius:= 20
- end;
- gtCake: begin
- gear^.Health:= 2048;
- gear^.Radius:= 7;
- gear^.Z:= cOnHHZ;
- gear^.RenderTimer:= true;
- gear^.DirAngle:= -90 * hwSign(Gear^.dX);
- if not dX.isNegative then gear^.Angle:= 1 else gear^.Angle:= 3
- end;
- gtHellishBomb: begin
- gear^.ImpactSound:= sndHellishImpact1;
- gear^.nImpactSounds:= 4;
- gear^.AdvBounce:= 1;
- gear^.Radius:= 4;
- gear^.Elasticity:= _0_5;
- gear^.Friction:= _0_96;
- gear^.Density:= _1_5;
- gear^.RenderTimer:= true;
- gear^.Timer:= 5000
- end;
- gtDrill: begin
- if gear^.Timer = 0 then gear^.Timer:= 5000;
- // Tag for drill strike. if 1 then first impact occured already
- gear^.Tag := 0;
- gear^.Radius:= 4;
- gear^.Density:= _1;
- end;
- gtBall: begin
- gear^.ImpactSound:= sndGrenadeImpact;
- gear^.nImpactSounds:= 1;
- gear^.AdvBounce:= 1;
- gear^.Radius:= 5;
- gear^.Tag:= random(8);
- gear^.Timer:= 5000;
- gear^.Elasticity:= _0_7;
- gear^.Friction:= _0_995;
- gear^.Density:= _1_5;
- end;
- gtBallgun: begin
- gear^.Timer:= 5001;
- end;
- gtRCPlane: begin
- gear^.Timer:= 15000;
- gear^.Health:= 3;
- gear^.Radius:= 8
- end;
- gtJetpack: begin
- gear^.Health:= 2000;
- gear^.Damage:= 100
- end;
- gtMolotov: begin
- gear^.Radius:= 6;
- gear^.Density:= _2;
- end;
- gtBirdy: begin
- gear^.Radius:= 16; // todo: check
- gear^.Timer:= 0;
- gear^.Health := 2000;
- gear^.FlightTime := 2;
- end;
- gtEgg: begin
- gear^.Radius:= 4;
- gear^.Elasticity:= _0_6;
- gear^.Friction:= _0_96;
- gear^.Density:= _1;
- if gear^.Timer = 0 then gear^.Timer:= 3000
- end;
- gtPortal: begin
- gear^.ImpactSound:= sndMelonImpact;
- gear^.nImpactSounds:= 1;
- gear^.AdvBounce:= 0;
- gear^.Radius:= 17;
- // set color
- gear^.Tag:= 2 * gear^.Timer;
- gear^.Timer:= 15000;
- gear^.RenderTimer:= false;
- gear^.Health:= 100;
- end;
- gtPiano: begin
- gear^.Radius:= 32;
- gear^.Density:= _50;
- end;
- gtSineGunShot: begin
- gear^.Radius:= 5;
- gear^.Health:= 6000;
- end;
-gtFlamethrower: begin
- gear^.Tag:= 10;
- gear^.Timer:= 10;
- gear^.Health:= 500;
- gear^.Damage:= 100;
- end;
- gtLandGun: begin
- gear^.Tag:= 10;
- gear^.Timer:= 10;
- gear^.Health:= 1000;
- gear^.Damage:= 100;
- end;
- gtPoisonCloud: begin
- gear^.Timer:= 5000;
- gear^.dY:= int2hwfloat(-4 + longint(getRandom(8))) / 1000;
- end;
- gtResurrector: begin
- gear^.Radius := 100;
- gear^.Tag := 0
- end;
- gtWaterUp: begin
- gear^.Tag := 47;
- end;
- gtNapalmBomb: begin
- gear^.Timer:= 1000;
- gear^.Radius:= 5;
- gear^.Density:= _1_5;
- end;
- gtStructure: begin
- gear^.Elasticity:= _0_55;
- gear^.Friction:= _0_995;
- gear^.Density:= _0_9;
- gear^.Radius:= 13;
- gear^.Health:= 200;
- gear^.Tag:= 3;
- end;
- end;
-
-InsertGearToList(gear);
-AddGear:= gear;
-
-ScriptCall('onGearAdd', gear^.uid);
-end;
-
-procedure DeleteGear(Gear: PGear);
-var team: PTeam;
- t,i: Longword;
- k: boolean;
-begin
-
-ScriptCall('onGearDelete', gear^.uid);
-
-DeleteCI(Gear);
-
-FreeTexture(Gear^.Tex);
-Gear^.Tex:= nil;
-
-// make sure that portals have their link removed before deletion
-if (Gear^.Kind = gtPortal) then
- begin
- if (Gear^.IntersectGear <> nil) then
- if (Gear^.IntersectGear^.IntersectGear = Gear) then
- Gear^.IntersectGear^.IntersectGear:= nil;
- end
-else if Gear^.Kind = gtHedgehog then
- (*
- This behaviour dates back to revision 4, and I accidentally encountered it with TARDIS. I don't think it must apply to any modern weapon, since if it was actually hit, the best the gear could do would be to destroy itself immediately, and you'd still end up with two graves. I believe it should be removed
- if (CurAmmoGear <> nil) and (CurrentHedgehog^.Gear = Gear) then
- begin
- AttackBar:= 0;
- Gear^.Message:= gmDestroy;
- CurAmmoGear^.Message:= gmDestroy;
- exit
- end
- else*)
- begin
- if (hwRound(Gear^.Y) >= cWaterLine) then
- begin
- t:= max(Gear^.Damage, Gear^.Health);
- Gear^.Damage:= t;
- if ((not SuddenDeathDmg and (cWaterOpacity < $FF)) or (SuddenDeathDmg and (cWaterOpacity < $FF))) and (hwRound(Gear^.Y) < cWaterLine + 256) then
- spawnHealthTagForHH(Gear, t);
- end;
-
- team:= Gear^.Hedgehog^.Team;
- if CurrentHedgehog^.Gear = Gear then
- begin
- AttackBar:= 0;
- FreeActionsList; // to avoid ThinkThread on drawned gear
- if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (CurrentHedgehog^.MultiShootAttacks > 0) then OnUsedAmmo(CurrentHedgehog^);
- end;
-
- Gear^.Hedgehog^.Gear:= nil;
- if Gear^.Hedgehog^.King then
- begin
- // are there any other kings left? Just doing nil check. Presumably a mortally wounded king will get reaped soon enough
- k:= false;
- for i:= 0 to Pred(team^.Clan^.TeamsNumber) do
- if (team^.Clan^.Teams[i]^.Hedgehogs[0].Gear <> nil) then k:= true;
- if not k then
- for i:= 0 to Pred(team^.Clan^.TeamsNumber) do
- begin
- team^.Clan^.Teams[i]^.hasGone:= true;
- TeamGoneEffect(team^.Clan^.Teams[i]^)
- end
- end;
-
- // should be not CurrentHedgehog, but hedgehog of the last gear which caused damage to this hog
- // same stand for CheckHHDamage
- if (Gear^.LastDamage <> nil) then
- uStats.HedgehogDamaged(Gear, Gear^.LastDamage, 0, true)
- else
- uStats.HedgehogDamaged(Gear, CurrentHedgehog, 0, true);
-
- inc(KilledHHs);
- RecountTeamHealth(team);
- if (CurrentHedgehog <> nil) and CurrentHedgehog^.Effects[heResurrectable] and (not Gear^.Hedgehog^.Effects[heResurrectable]) then
- with CurrentHedgehog^ do
- begin
- inc(Team^.stats.AIKills);
- FreeTexture(Team^.AIKillsTex);
- Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16);
- end
- end;
-with Gear^ do
- AddFileLog('Delete: #' + inttostr(uid) + ' (' + inttostr(hwRound(x)) + ',' + inttostr(hwRound(y)) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
-
-if CurAmmoGear = Gear then CurAmmoGear:= nil;
-if FollowGear = Gear then FollowGear:= nil;
-if lastGearByUID = Gear then lastGearByUID := nil;
-RemoveGearFromList(Gear);
-Dispose(Gear)
-end;
-
function CheckNoDamage: boolean; // returns TRUE in case of no damaged hhs
var Gear: PGear;
dmg: LongInt;
@@ -1075,69 +547,6 @@
RecountTeamHealth(TeamsArray[i])
end;
-procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
-var s: shortstring;
- vampDmg, tmpDmg, i: Longword;
- vg: PVisualGear;
-begin
- if Damage = 0 then exit; // nothing to apply
-
- if (Gear^.Kind = gtHedgehog) then
- begin
- Gear^.LastDamage := AttackerHog;
-
- Gear^.Hedgehog^.Team^.Clan^.Flawless:= false;
- HHHurt(Gear^.Hedgehog, Source);
- AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), Damage, Gear^.Hedgehog^.Team^.Clan^.Color);
- tmpDmg:= min(Damage, max(0,Gear^.Health-Gear^.Damage));
- if (Gear <> CurrentHedgehog^.Gear) and (CurrentHedgehog^.Gear <> nil) and (tmpDmg >= 1) then
- begin
- if cVampiric then
- begin
- vampDmg:= hwRound(int2hwFloat(tmpDmg)*_0_8);
- if vampDmg >= 1 then
- begin
- // 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);
- str(vampDmg, s);
- s:= '+' + s;
- AddCaption(s, CurrentHedgehog^.Team^.Clan^.Color, capgrpAmmoinfo);
- RenderHealth(CurrentHedgehog^);
- RecountTeamHealth(CurrentHedgehog^.Team);
- i:= 0;
- while i < vampDmg 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;
- end
- end;
- if ((GameFlags and gfKarma) <> 0) and
- ((GameFlags and gfInvulnerable) = 0) and
- (not CurrentHedgehog^.Gear^.Invulnerable) then
- begin // this cannot just use Damage or it interrupts shotgun and gets you called stupid
- inc(CurrentHedgehog^.Gear^.Karma, tmpDmg);
- CurrentHedgehog^.Gear^.LastDamage := CurrentHedgehog;
- spawnHealthTagForHH(CurrentHedgehog^.Gear, tmpDmg);
- end;
- uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false);
- end;
- end else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure
- begin
- Gear^.Hedgehog:= AttackerHog;
- end;
- inc(Gear^.Damage, Damage);
-
- ScriptCall('onGearDamage', Gear^.UID, Damage);
-end;
-
procedure SetAllToActive;
var t: PGear;
begin
@@ -1600,24 +1009,6 @@
end;
end;
-function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear;
-var t: PGear;
-begin
-t:= GearsList;
-rX:= sqr(rX);
-rY:= sqr(rY);
-
-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) then
- exit(t);
- t:= t^.NextGear
- end;
-
-CheckGearNear:= nil
-end;
-
{procedure AmmoFlameWork(Ammo: PGear);
var t: PGear;
begin
@@ -1638,21 +1029,6 @@
end;
end;}
-function CheckGearsNear(mX, mY: LongInt; Kind: TGearsType; rX, rY: LongInt): PGear;
-var t: PGear;
-begin
-t:= GearsList;
-rX:= sqr(rX);
-rY:= sqr(rY);
-while t <> nil do
- begin
- if t^.Kind in Kind then
- if not (hwSqr(int2hwFloat(mX) - t^.X) / rX + hwSqr(int2hwFloat(mY) - t^.Y) / rY > _1) then
- exit(t);
- t:= t^.NextGear
- end;
-CheckGearsNear:= nil
-end;
function CountGears(Kind: TGearType): Longword;
var t: PGear;
@@ -1668,33 +1044,6 @@
CountGears:= count;
end;
-procedure ResurrectHedgehog(gear: PGear);
-var tempTeam : PTeam;
-begin
- AttackBar:= 0;
- gear^.dX := _0;
- gear^.dY := _0;
- gear^.Damage := 0;
- gear^.Health := gear^.Hedgehog^.InitialHealth;
- gear^.Hedgehog^.Effects[hePoisoned] := false;
- if not CurrentHedgehog^.Effects[heResurrectable] then
- with CurrentHedgehog^ do
- begin
- inc(Team^.stats.AIKills);
- FreeTexture(Team^.AIKillsTex);
- Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16);
- end;
- tempTeam := gear^.Hedgehog^.Team;
- DeleteCI(gear);
- FindPlace(gear, false, 0, LAND_WIDTH, true);
- if gear <> nil then begin
- RenderHealth(gear^.Hedgehog^);
- ScriptCall('onGearResurrect', gear^.uid);
- gear^.State := gstWait;
- end;
- RecountTeamHealth(tempTeam);
-end;
-
function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content: Longword): PGear;
begin
FollowGear := AddGear(x, y, gtCase, 0, _0, _0, 0);
@@ -1886,119 +1235,6 @@
end
end;
-procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean = false);
-
- function CountNonZeroz(x, y, r, c: LongInt): LongInt;
- var i: LongInt;
- count: LongInt = 0;
- begin
- if (y and LAND_HEIGHT_MASK) = 0 then
- for i:= max(x - r, 0) to min(x + r, LAND_WIDTH - 4) do
- if Land[y, i] <> 0 then
- begin
- inc(count);
- if count = c then exit(count)
- end;
- CountNonZeroz:= count;
- end;
-
-var x: LongInt;
- y, sy: LongInt;
- ar: array[0..511] of TPoint;
- ar2: array[0..1023] of TPoint;
- cnt, cnt2: Longword;
- delta: LongInt;
- reallySkip, tryAgain: boolean;
-begin
-reallySkip:= false; // try not skipping proximity at first
-tryAgain:= true;
-while tryAgain do
- begin
- delta:= 250;
- cnt2:= 0;
- repeat
- x:= Left + LongInt(GetRandom(Delta));
- repeat
- inc(x, Delta);
- cnt:= 0;
- y:= min(1024, topY) - 2 * Gear^.Radius;
- while y < cWaterLine do
- begin
- repeat
- inc(y, 2);
- until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) = 0);
-
- sy:= y;
-
- repeat
- inc(y);
- until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) <> 0);
-
- if (y - sy > Gear^.Radius * 2) and
- (((Gear^.Kind = gtExplosives)
- and (y < cWaterLine)
- and (reallySkip or (CheckGearsNear(x, y - Gear^.Radius, [gtFlame, gtHedgehog, gtMine, gtCase, gtExplosives], 60, 60) = nil))
- and (CountNonZeroz(x, y+1, Gear^.Radius - 1, Gear^.Radius+1) > Gear^.Radius))
- or
- ((Gear^.Kind <> gtExplosives)
- and (y < cWaterLine)
- and (reallySkip or (CheckGearsNear(x, y - Gear^.Radius, [gtFlame, gtHedgehog, gtMine, gtCase, gtExplosives], 110, 110) = nil)))) then
- begin
- ar[cnt].X:= x;
- if withFall then ar[cnt].Y:= sy + Gear^.Radius
- else ar[cnt].Y:= y - Gear^.Radius;
- inc(cnt)
- end;
-
- inc(y, 45)
- end;
-
- if cnt > 0 then
- with ar[GetRandom(cnt)] do
- begin
- ar2[cnt2].x:= x;
- ar2[cnt2].y:= y;
- inc(cnt2)
- end
- until (x + Delta > Right);
-
- dec(Delta, 60)
- until (cnt2 > 0) or (Delta < 70);
- if (cnt2 = 0) and skipProximity and (not reallySkip) then tryAgain:= true
- else tryAgain:= false;
- reallySkip:= true;
- end;
-
-if cnt2 > 0 then
- with ar2[GetRandom(cnt2)] do
- begin
- Gear^.X:= int2hwFloat(x);
- Gear^.Y:= int2hwFloat(y);
- AddFileLog('Assigned Gear coordinates (' + inttostr(x) + ',' + inttostr(y) + ')');
- end
- else
- begin
- OutError('Can''t find place for Gear', false);
- if Gear^.Kind = gtHedgehog then Gear^.Hedgehog^.Effects[heResurrectable] := false;
- DeleteGear(Gear);
- Gear:= nil
- end
-end;
-
-function ModifyDamage(dmg: Longword; Gear: PGear): Longword;
-var i: hwFloat;
-begin
-(* Invulnerability cannot be placed in here due to still needing kicks
- Not without a new damage machine.
- King check should be in here instead of ApplyDamage since Tiy wants them kicked less
-*)
-i:= _1;
-if (CurrentHedgehog <> nil) and CurrentHedgehog^.King then i:= _1_5;
-if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.King) then
- ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent * _0_5)
-else
- ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent)
-end;
function GearByUID(uid : Longword) : PGear;
var gear: PGear;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uGearsHedgehog.pas Fri Dec 30 13:54:39 2011 +0400
@@ -0,0 +1,1150 @@
+(*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2011 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *)
+
+{$INCLUDE "options.inc"}
+
+unit uGearsHedgehog;
+interface
+uses uTypes;
+
+procedure doStepHedgehog(Gear: PGear);
+procedure AfterAttack;
+procedure HedgehogStep(Gear: PGear);
+procedure doStepHedgehogMoving(Gear: PGear);
+procedure HedgehogChAngle(HHGear: PGear);
+
+implementation
+uses uConsts, uVariables, uFloat, uAmmos, uSound, uCaptions, uMisc,
+ uCommands, uLocale, uUtils, uVisualGears, uStats, uIO, uScript,
+ uGearsList, uGears, uCollisions, uRandom, uStore, uTeams,
+ uGearsUtils;
+
+// Shouldn't more of this ammo switching stuff be moved to uAmmos ?
+function ChangeAmmo(HHGear: PGear): boolean;
+var slot, i: Longword;
+ ammoidx: LongInt;
+begin
+ChangeAmmo:= false;
+slot:= HHGear^.MsgParam;
+
+with HHGear^.Hedgehog^ do
+ begin
+ HHGear^.Message:= HHGear^.Message and (not gmSlot);
+ ammoidx:= 0;
+ if ((HHGear^.State and (gstAttacking or gstAttacked)) <> 0) or
+ ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0)) or
+ ((HHGear^.State and gstHHDriven) = 0) then exit;
+ ChangeAmmo:= true;
+
+ while (ammoidx < cMaxSlotAmmoIndex) and (Ammo^[slot, ammoidx].AmmoType <> CurAmmoType) do inc(ammoidx);
+
+ if ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (MultiShootAttacks > 0) then OnUsedAmmo(HHGear^.Hedgehog^);
+
+ MultiShootAttacks:= 0;
+ HHGear^.Message:= HHGear^.Message and (not (gmLJump or gmHJump));
+
+ if Ammoz[CurAmmoType].Slot = slot then
+ begin
+ i:= 0;
+ repeat
+ inc(ammoidx);
+ if (ammoidx > cMaxSlotAmmoIndex) then
+ begin
+ inc(i);
+ CurAmmoType:= amNothing;
+ ammoidx:= -1;
+ //TryDo(i < 2, 'Engine bug: no ammo in current slot', true)
+ end;
+ until (i = 1) or ((Ammo^[slot, ammoidx].Count > 0) and (Team^.Clan^.TurnNumber > Ammoz[Ammo^[slot, ammoidx].AmmoType].SkipTurns))
+ end
+ else
+ begin
+ i:= 0;
+ // check whether there is ammo in slot
+ while (i <= cMaxSlotAmmoIndex)
+ and ((Ammo^[slot, i].Count = 0)
+ or (Team^.Clan^.TurnNumber <= Ammoz[Ammo^[slot, i].AmmoType].SkipTurns)) do inc(i);
+
+ if i <= cMaxSlotAmmoIndex then ammoidx:= i
+ else ammoidx:= -1
+ end;
+ if ammoidx >= 0 then CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
+ end
+end;
+
+procedure HHSetWeapon(HHGear: PGear);
+var t: LongInt;
+ weap: TAmmoType;
+ Hedgehog: PHedgehog;
+ s: boolean;
+begin
+s:= false;
+
+weap:= TAmmoType(HHGear^.MsgParam);
+Hedgehog:= HHGear^.Hedgehog;
+
+if Hedgehog^.Team^.Clan^.TurnNumber <= Ammoz[weap].SkipTurns then exit; // weapon is not activated yet
+
+HHGear^.MsgParam:= Ammoz[weap].Slot;
+
+t:= cMaxSlotAmmoIndex;
+
+HHGear^.Message:= HHGear^.Message and (not gmWeapon);
+
+with Hedgehog^ do
+ while (CurAmmoType <> weap) and (t >= 0) do
+ begin
+ s:= ChangeAmmo(HHGear);
+ dec(t)
+ end;
+
+if s then ApplyAmmoChanges(HHGear^.Hedgehog^)
+end;
+
+procedure HHSetTimer(Gear: PGear);
+var CurWeapon: PAmmo;
+ color: LongWord;
+begin
+Gear^.Message:= Gear^.Message and (not gmTimer);
+CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^);
+with Gear^.Hedgehog^ do
+ if ((Gear^.Message and gmPrecise) <> 0) and ((CurWeapon^.Propz and ammoprop_SetBounce) <> 0) then
+ begin
+ color:= Gear^.Hedgehog^.Team^.Clan^.Color;
+ case Gear^.MsgParam of
+ 1: begin
+ AddCaption(format(trmsg[sidBounce], trmsg[sidBounce1]), color, capgrpAmmostate);
+ CurWeapon^.Bounciness:= 350;
+ end;
+ 2: begin
+ AddCaption(format(trmsg[sidBounce], trmsg[sidBounce2]), color, capgrpAmmostate);
+ CurWeapon^.Bounciness:= 700;
+ end;
+ 3: begin
+ AddCaption(format(trmsg[sidBounce], trmsg[sidBounce3]), color, capgrpAmmostate);
+ CurWeapon^.Bounciness:= 1000;
+ end;
+ 4: begin
+ AddCaption(format(trmsg[sidBounce], trmsg[sidBounce4]), color, capgrpAmmostate);
+ CurWeapon^.Bounciness:= 2000;
+ end;
+ 5: begin
+ AddCaption(format(trmsg[sidBounce], trmsg[sidBounce5]), color, capgrpAmmostate);
+ CurWeapon^.Bounciness:= 4000;
+ end
+ end
+ end
+ else if (CurWeapon^.Propz and ammoprop_Timerable) <> 0 then
+ begin
+ CurWeapon^.Timer:= 1000 * Gear^.MsgParam;
+ with CurrentTeam^ do
+ ApplyAmmoChanges(Hedgehogs[CurrHedgehog]);
+ end;
+end;
+
+
+procedure Attack(Gear: PGear);
+var xx, yy, newDx, newDy, lx, ly: hwFloat;
+ speech: PVisualGear;
+ newGear: PGear;
+ CurWeapon: PAmmo;
+ altUse: boolean;
+ elastic: hwFloat;
+begin
+newGear:= nil;
+bShowFinger:= false;
+CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^);
+with Gear^,
+ Gear^.Hedgehog^ do
+ begin
+ if ((State and gstHHDriven) <> 0)and
+ ((State and (gstAttacked or gstHHChooseTarget)) = 0) and
+ (((State and gstMoving) = 0) or
+ (Power > 0) or
+ (CurAmmoType = amTeleport) or
+ // Allow attacks while moving on ammo with AltAttack
+ ((CurAmmoGear <> nil) and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)) or
+ ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AttackInMove) <> 0)) and
+ ((TargetPoint.X <> NoPointX) or ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) = 0)) then
+ begin
+ State:= State or gstAttacking;
+ if Power = cMaxPower then Message:= Message and (not gmAttack)
+ else if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) = 0 then Message:= Message and (not gmAttack)
+ else begin
+ if Power = 0 then
+ begin
+ AttackBar:= CurrentTeam^.AttackBar;
+ PlaySound(sndThrowPowerUp)
+ end;
+ inc(Power)
+ end;
+ if ((Message and gmAttack) <> 0) then exit;
+
+ if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0 then
+ begin
+ StopSound(sndThrowPowerUp);
+ PlaySound(sndThrowRelease);
+ end;
+
+ xx:= SignAs(AngleSin(Angle), dX);
+ yy:= -AngleCos(Angle);
+
+ lx:= X + int2hwfloat(round(GetLaunchX(CurAmmoType, hwSign(dX), Angle)));
+ ly:= Y + int2hwfloat(round(GetLaunchY(CurAmmoType, Angle)));
+
+ if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then xx:= - xx;
+ if Ammoz[CurAmmoType].Ammo.AttackVoice <> sndNone then
+ AddVoice(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
+
+// Initiating alt attack
+ if (CurAmmoGear <> nil) and
+ ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) and
+ ((Gear^.Message and gmLJump) <> 0) and
+ ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
+ begin
+ newDx:= dX / _2;
+ newDy:= dY / _2;
+ altUse:= true;
+ end
+ else
+ begin
+ newDx:= xx*Power/cPowerDivisor;
+ newDy:= yy*Power/cPowerDivisor;
+ altUse:= false
+ end;
+
+ case CurAmmoType of
+ amGrenade: newGear:= AddGear(hwRound(lx), hwRound(ly), gtGrenade, 0, newDx, newDy, CurWeapon^.Timer);
+ amMolotov: newGear:= AddGear(hwRound(lx), hwRound(ly), gtMolotov, 0, newDx, newDy, 0);
+ amClusterBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtClusterBomb, 0, newDx, newDy, CurWeapon^.Timer);
+ amGasBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtGasBomb, 0, newDx, newDy, CurWeapon^.Timer);
+ amBazooka: newGear:= AddGear(hwRound(lx), hwRound(ly), gtShell, 0, newDx, newDy, 0);
+ amSnowball: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSnowball, 0, newDx, newDy, 0);
+ amBee: newGear:= AddGear(hwRound(lx), hwRound(ly), gtBee, 0, newDx, newDy, 0);
+ amShotgun: begin
+ PlaySound(sndShotgunReload);
+ newGear:= AddGear(hwRound(lx), hwRound(ly), gtShotgunShot, 0, xx * _0_5, yy * _0_5, 0);
+ end;
+ amPickHammer: newGear:= AddGear(hwRound(lx), hwRound(ly) + cHHRadius, gtPickHammer, 0, _0, _0, 0);
+ amSkip: ParseCommand('/skip', true);
+ amRope: newGear:= AddGear(hwRound(lx), hwRound(ly), gtRope, 0, xx, yy, 0);
+ amMine: if altUse then
+ newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtMine, gstWait, newDx, newDy, 3000)
+ else
+ newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtMine, gstWait, SignAs(_0_02, dX), _0, 3000);
+ amSMine: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSMine, 0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
+ amDEagle: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtDEagleShot, 0, xx * _0_5, yy * _0_5, 0);
+ amSineGun: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSineGunShot, 0, xx * _0_5, yy * _0_5, 0);
+ amPortalGun: begin
+ newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtPortal, 0, xx * _0_6, yy * _0_6,
+ // set selected color
+ CurWeapon^.Pos);
+ end;
+ amSniperRifle: begin
+ PlaySound(sndSniperReload);
+ newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSniperRifleShot, 0, xx * _0_5, yy * _0_5, 0);
+ end;
+ amDynamite: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtDynamite, 0, SignAs(_0_03, dX), _0, 5000);
+ amFirePunch: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtFirePunch, 0, xx, _0, 0);
+ amWhip: begin
+ newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtWhip, 0, SignAs(_1, dX), - _0_8, 0);
+ PlaySound(sndWhipCrack)
+ end;
+ amHammer: begin
+ newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtHammer, 0, SignAs(_1, dX), - _0_8, 0);
+ PlaySound(sndWhack)
+ end;
+ amBaseballBat: begin
+ newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtShover, gsttmpFlag, xx * _0_5, yy * _0_5, 0);
+ PlaySound(sndBaseballBat) // TODO: Only play if something is hit?
+ end;
+ amParachute: begin
+ newGear:= AddGear(hwRound(lx), hwRound(ly), gtParachute, 0, _0, _0, 0);
+ PlaySound(sndParachute)
+ end;
+ // we save CurWeapon^.Pos (in this case: cursor direction) by using it as (otherwise irrelevant) X value of the new gear.
+ amAirAttack: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 0, _0, _0, 0);
+ amMineStrike: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 1, _0, _0, 0);
+ amDrillStrike: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 3, _0, _0, CurWeapon^.Timer);
+ amNapalm: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 2, _0, _0, 0);
+ amBlowTorch: newGear:= AddGear(hwRound(lx), hwRound(ly), gtBlowTorch, 0, SignAs(_0_5, dX), _0, 0);
+ amGirder: newGear:= AddGear(0, 0, gtGirder, CurWeapon^.Pos, _0, _0, 0);
+ amTeleport: newGear:= AddGear(CurWeapon^.Pos, 0, gtTeleport, 0, _0, _0, 0);
+ amSwitch: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSwitcher, 0, _0, _0, 0);
+ amMortar: begin
+ playSound(sndMortar);
+ newGear:= AddGear(hwRound(lx), hwRound(ly), gtMortar, 0, xx*cMaxPower/cPowerDivisor, yy*cMaxPower/cPowerDivisor, 0);
+ end;
+ amRCPlane: begin
+ newGear:= AddGear(hwRound(lx), hwRound(ly), gtRCPlane, 0, xx * cMaxPower / cPowerDivisor / 4, yy * cMaxPower / cPowerDivisor / 4, 0);
+ newGear^.SoundChannel:= LoopSound(sndRCPlane, nil)
+ end;
+ amKamikaze: newGear:= AddGear(hwRound(lx), hwRound(ly), gtKamikaze, 0, xx * _0_5, yy * _0_5, 0);
+ amCake: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 3, hwRound(ly), gtCake, 0, xx, _0, 0);
+ amSeduction: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSeduction, 0, _0, _0, 0);
+ amWatermelon: newGear:= AddGear(hwRound(lx), hwRound(ly), gtWatermelon, 0, newDx, newDy, CurWeapon^.Timer);
+ amHellishBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtHellishBomb, 0, newDx, newDy, 0);
+ amDrill: newGear:= AddGear(hwRound(lx), hwRound(ly), gtDrill, 0, newDx, newDy, 0);
+ amBallgun: newGear:= AddGear(hwRound(X), hwRound(Y), gtBallgun, 0, xx * _0_5, yy * _0_5, 0);
+ amJetpack: newGear:= AddGear(hwRound(lx), hwRound(ly), gtJetpack, 0, _0, _0, 0);
+ amBirdy: begin
+ PlaySound(sndWhistle);
+ newGear:= AddGear(hwRound(lx), hwRound(ly) - 32, gtBirdy, 0, _0, _0, 0);
+ end;
+ amLowGravity: begin
+ PlaySound(sndLowGravity);
+ cGravity:= cMaxWindSpeed;
+ cGravityf:= 0.00025
+ end;
+ amExtraDamage:begin
+ PlaySound(sndHellishImpact4);
+ cDamageModifier:= _1_5
+ end;
+ amInvulnerable: Invulnerable:= true;
+ amExtraTime: begin
+ PlaySound(sndSwitchHog);
+ TurnTimeLeft:= TurnTimeLeft + 30000
+ end;
+ amLaserSight: cLaserSighting:= true;
+ amVampiric: begin
+ PlaySound(sndOw1, Team^.voicepack);
+ cVampiric:= true;
+ end;
+ amPiano: begin
+ // Tuck the hedgehog away until the piano attack is completed
+ Unplaced:= true;
+ X:= _0;
+ Y:= _0;
+ newGear:= AddGear(TargetPoint.X, 0, gtPiano, 0, _0, _0, 0);
+ PauseMusic
+ end;
+ amFlamethrower: newGear:= AddGear(hwRound(X), hwRound(Y), gtFlamethrower, 0, xx * _0_5, yy * _0_5, 0);
+ amLandGun: newGear:= AddGear(hwRound(X), hwRound(Y), gtLandGun, 0, xx * _0_5, yy * _0_5, 0);
+ amResurrector: begin
+ newGear:= AddGear(hwRound(lx), hwRound(ly),
+ gtResurrector, 0, _0, _0, 0);
+ newGear^.SoundChannel := LoopSound(sndResurrector);
+ end;
+ //amMelonStrike: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 4, _0, _0, 0);
+ amStructure: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtStructure, gstWait, SignAs(_0_02, dX), _0, 3000);
+ amTardis: newGear:= AddGear(hwRound(X), hwRound(Y), gtTardis, 0, _0, _0, 5000);
+ end;
+ case CurAmmoType of
+ amGrenade, amMolotov,
+ amClusterBomb, amGasBomb,
+ amBazooka, amSnowball,
+ amBee, amSMine,
+ amMortar, amWatermelon,
+ amHellishBomb, amDrill: FollowGear:= newGear;
+
+ amShotgun, amPickHammer,
+ amRope, amDEagle,
+ amSineGun, amSniperRifle,
+ amFirePunch, amWhip,
+ amHammer, amBaseballBat,
+ amParachute, amBlowTorch,
+ amGirder, amTeleport,
+ amSwitch, amRCPlane,
+ amKamikaze, amCake,
+ amSeduction, amBallgun,
+ amJetpack, amBirdy,
+ amFlamethrower, amLandGun,
+ amResurrector, amStructure,
+ amTardis, amPiano: CurAmmoGear:= newGear;
+ end;
+ if (CurAmmoType = amMine) or (CurAmmoType = amSMine) and (GameFlags and gfInfAttack <> 0) then newGear^.FlightTime:= GameTicks + 1000;
+ if Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then
+ begin
+ newGear^.Target.X:= TargetPoint.X;
+ newGear^.Target.Y:= TargetPoint.Y
+ end;
+
+ // Clear FollowGear if using on a rope/parachute/saucer etc so focus stays with the hog's movement
+ if altUse then FollowGear:= nil;
+
+ if (newGear <> nil) and ((Ammoz[newGear^.AmmoType].Ammo.Propz and ammoprop_SetBounce) <> 0) then
+ begin
+ elastic:= int2hwfloat(CurWeapon^.Bounciness) / _1000;
+
+ if elastic < _1 then newGear^.Elasticity:= newGear^.Elasticity * elastic
+ else if elastic > _1 then newGear^.Elasticity:= _1 - ((_1-newGear^.Elasticity) / elastic);
+(* Experimented with friction modifier. Didn't seem helpful
+ fric:= int2hwfloat(CurWeapon^.Bounciness) / _250;
+ if fric < _1 then newGear^.Friction:= newGear^.Friction * fric
+ else if fric > _1 then newGear^.Friction:= _1 - ((_1-newGear^.Friction) / fric)*)
+ end;
+
+
+ uStats.AmmoUsed(CurAmmoType);
+
+ if not (SpeechText = '') then
+ begin
+ speech:= AddVisualGear(0, 0, vgtSpeechBubble);
+ if speech <> nil then
+ begin
+ speech^.Text:= SpeechText;
+ speech^.Hedgehog:= Gear^.Hedgehog;
+ speech^.FrameTicks:= SpeechType;
+ end;
+ SpeechText:= ''
+ end;
+
+ Power:= 0;
+ if (CurAmmoGear <> nil)
+ and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) = 0){check for dropping ammo from rope} then
+ begin
+ Message:= Message or gmAttack;
+ CurAmmoGear^.Message:= Message
+ end else begin
+ if not CurrentTeam^.ExtDriven and
+ ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0) then SendIPC('a');
+ AfterAttack;
+ end
+ end else Message:= Message and (not gmAttack);
+ end;
+ TargetPoint.X := NoPointX;
+ ScriptCall('onHogAttack');
+end;
+
+procedure AfterAttack;
+var s: shortstring;
+ a: TAmmoType;
+begin
+with CurrentHedgehog^.Gear^,
+ CurrentHedgehog^ do
+ begin
+ a:= CurAmmoType;
+ State:= State and (not gstAttacking);
+ if (Ammoz[a].Ammo.Propz and ammoprop_Effect) = 0 then
+ begin
+ Inc(MultiShootAttacks);
+
+ if (Ammoz[a].Ammo.NumPerTurn >= MultiShootAttacks) then
+ begin
+ s:= inttostr(Ammoz[a].Ammo.NumPerTurn - MultiShootAttacks + 1);
+ AddCaption(format(trmsg[sidRemaining], s), cWhiteColor, capgrpAmmostate);
+ end;
+
+ if (Ammoz[a].Ammo.NumPerTurn >= MultiShootAttacks) or
+ ((GameFlags and gfMultiWeapon) <> 0) then
+ begin
+ isInMultiShoot:= true
+ end
+ else
+ begin
+ OnUsedAmmo(CurrentHedgehog^);
+ if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) = 0) and (((GameFlags and gfInfAttack) = 0) or PlacingHogs) then
+ begin
+ if TagTurnTimeLeft = 0 then TagTurnTimeLeft:= TurnTimeLeft;
+ TurnTimeLeft:=(Ammoz[a].TimeAfterTurn * cGetAwayTime) div 100;
+ end;
+ if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) = 0) then State:= State or gstAttacked;
+ if (Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) <> 0 then ApplyAmmoChanges(CurrentHedgehog^)
+ end;
+ end
+ else
+ begin
+ OnUsedAmmo(CurrentHedgehog^);
+ ApplyAmmoChanges(CurrentHedgehog^);
+ end;
+ AttackBar:= 0
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHedgehogDead(Gear: PGear);
+const frametime = 200;
+ timertime = frametime * 6;
+begin
+if Gear^.Hedgehog^.Unplaced then exit;
+if Gear^.Timer > 1 then
+ begin
+ AllInactive:= false;
+ dec(Gear^.Timer);
+ if (Gear^.Timer mod frametime) = 0 then inc(Gear^.Pos)
+ end
+else if Gear^.Timer = 1 then
+ begin
+ Gear^.State:= Gear^.State or gstNoDamage;
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, CurrentHedgehog, EXPLAutoSound);
+ AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtGrave, 0, _0, _0, 0)^.Hedgehog:= Gear^.Hedgehog;
+ DeleteGear(Gear);
+ SetAllToActive
+ end
+else // Gear^.Timer = 0
+ begin
+ AllInactive:= false;
+ Gear^.Z:= cCurrHHZ;
+ RemoveGearFromList(Gear);
+ InsertGearToList(Gear);
+ PlaySound(sndByeBye, Gear^.Hedgehog^.Team^.voicepack);
+ Gear^.Pos:= 0;
+ Gear^.Timer:= timertime
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHedgehogGone(Gear: PGear);
+const frametime = 65;
+ timertime = frametime * 11;
+begin
+if Gear^.Hedgehog^.Unplaced then exit;
+if Gear^.Timer > 1 then
+ begin
+ AllInactive:= false;
+ dec(Gear^.Timer);
+ if (Gear^.Timer mod frametime) = 0 then inc(Gear^.Pos)
+ end else
+if Gear^.Timer = 1 then
+ begin
+ DeleteGear(Gear);
+ SetAllToActive
+ end else // Gear^.Timer = 0
+ begin
+ AllInactive:= false;
+ Gear^.Z:= cCurrHHZ;
+ RemoveGearFromList(Gear);
+ InsertGearToList(Gear);
+ PlaySound(sndByeBye, Gear^.Hedgehog^.Team^.voicepack);
+ PlaySound(sndWarp);
+ Gear^.Pos:= 0;
+ Gear^.Timer:= timertime
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure PickUp(HH, Gear: PGear);
+var s: shortstring;
+ a: TAmmoType;
+ i: LongInt;
+ vga: PVisualGear;
+begin
+Gear^.Message:= gmDestroy;
+PlaySound(sndShotgunReload);
+if (Gear^.Pos and posCaseExplode) <> 0 then
+ if (Gear^.Pos and posCasePoison) <> 0 then
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound + EXPLPoisoned)
+ else
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound)
+else if (Gear^.Pos and posCasePoison) <> 0 then
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound + EXPLPoisoned + EXPLNoDamage)
+else
+case Gear^.Pos of
+ posCaseUtility,
+ posCaseAmmo: begin
+ if Gear^.AmmoType <> amNothing then a:= Gear^.AmmoType
+ else
+ begin
+ for i:= 0 to GameTicks and $7F do GetRandom(2); // Burn some random numbers
+ if Gear^.Pos = posCaseUtility then a:= GetUtility
+ else a:= GetAmmo
+ end;
+ AddAmmo(HH^.Hedgehog^, a);
+// Possibly needs to check shared clan ammo game flag once added.
+// On the other hand, no obvious reason that clan members shouldn't know what ammo another clan member picked up
+ if (not (HH^.Hedgehog^.Team^.ExtDriven
+ or (HH^.Hedgehog^.BotLevel > 0)))
+ or (HH^.Hedgehog^.Team^.Clan^.ClanIndex = LocalClan)
+ or (GameType = gmtDemo) then
+ begin
+ s:= trammo[Ammoz[a].NameId] + ' (+' + IntToStr(Ammoz[a].NumberInCase) + ')';
+ AddCaption(s, HH^.Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo);
+
+ // show ammo icon
+ vga:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtAmmo);
+ if vga <> nil then
+ vga^.Frame:= Longword(a);
+ end;
+
+ end;
+ posCaseHealth: begin
+ inc(HH^.Health, Gear^.Health);
+ HH^.Hedgehog^.Effects[hePoisoned] := false;
+ str(Gear^.Health, s);
+ s:= '+' + s;
+ AddCaption(s, HH^.Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo);
+ RenderHealth(HH^.Hedgehog^);
+ RecountTeamHealth(HH^.Hedgehog^.Team);
+
+ i:= 0;
+ while i < Gear^.Health do
+ begin
+ vga:= AddVisualGear(hwRound(HH^.X), hwRound(HH^.Y), vgtStraightShot);
+ if vga <> nil then
+ with vga^ do
+ begin
+ Tint:= $00FF00FF;
+ State:= ord(sprHealth)
+ end;
+ inc(i, 5);
+ end;
+ end;
+ end
+end;
+
+const StepTicks: LongWord = 0;
+
+procedure HedgehogStep(Gear: PGear);
+var PrevdX: LongInt;
+ CurWeapon: PAmmo;
+begin
+CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^);
+if ((Gear^.State and (gstAttacking or gstMoving)) = 0) then
+ begin
+ if isCursorVisible then
+ with Gear^.Hedgehog^ do
+ with CurWeapon^ do
+ begin
+ if (Gear^.Message and gmLeft ) <> 0 then
+ Pos:= (Pos - 1 + Ammoz[AmmoType].PosCount) mod Ammoz[AmmoType].PosCount
+ else
+ if (Gear^.Message and gmRight ) <> 0 then
+ Pos:= (Pos + 1) mod Ammoz[AmmoType].PosCount
+ else exit;
+ StepTicks:= 200;
+ exit
+ end;
+
+ if ((Gear^.Message and gmAnimate) <> 0) then
+ begin
+ Gear^.Message:= 0;
+ Gear^.State:= Gear^.State or gstAnimation;
+ Gear^.Tag:= Gear^.MsgParam;
+ Gear^.Timer:= 0;
+ Gear^.Pos:= 0
+ end;
+
+ if ((Gear^.Message and gmLJump ) <> 0) then
+ begin
+ Gear^.Message:= Gear^.Message and (not gmLJump);
+ DeleteCI(Gear);
+ if TestCollisionYwithGear(Gear, -1) = 0 then
+ if not TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) then Gear^.Y:= Gear^.Y - _2 else
+ if not TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) then Gear^.Y:= Gear^.Y - _1;
+ if not (TestCollisionXwithGear(Gear, hwSign(Gear^.dX))
+ or (TestCollisionYwithGear(Gear, -1) <> 0)) then
+ begin
+ Gear^.dY:= -_0_15;
+ if not cArtillery then Gear^.dX:= SignAs(_0_15, Gear^.dX);
+ Gear^.State:= Gear^.State or gstMoving or gstHHJumping;
+ PlaySound(sndJump1, Gear^.Hedgehog^.Team^.voicepack);
+ exit
+ end;
+ end;
+
+ if ((Gear^.Message and gmHJump ) <> 0) then
+ begin
+ DeleteCI(Gear);
+ Gear^.Message:= Gear^.Message and (not gmHJump);
+
+ Gear^.dY:= -_0_2;
+ SetLittle(Gear^.dX);
+ Gear^.State:= Gear^.State or gstMoving or gstHHJumping;
+ PlaySound(sndJump3, Gear^.Hedgehog^.Team^.voicepack);
+ exit
+ end;
+
+ PrevdX:= hwSign(Gear^.dX);
+ if (Gear^.Message and gmLeft )<>0 then Gear^.dX:= -cLittle else
+ if (Gear^.Message and gmRight )<>0 then Gear^.dX:= cLittle else exit;
+
+ if (Gear^.Message and (gmLeft or gmRight)) <> 0 then
+ begin
+ StepSoundTimer:= cHHStepTicks;
+ end;
+
+ StepTicks:= cHHStepTicks;
+ if PrevdX <> hwSign(Gear^.dX) then
+ begin
+ FollowGear:= Gear;
+ exit
+ end;
+ DeleteCI(Gear); // must be after exit!! (see previous line)
+
+ Gear^.Hedgehog^.visStepPos:= (Gear^.Hedgehog^.visStepPos + 1) and 7;
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
+ begin
+ if not (TestCollisionXwithXYShift(Gear, _0, -6, hwSign(Gear^.dX))
+ or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
+ if not (TestCollisionXwithXYShift(Gear, _0, -5, hwSign(Gear^.dX))
+ or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
+ if not (TestCollisionXwithXYShift(Gear, _0, -4, hwSign(Gear^.dX))
+ or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
+ if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))
+ or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
+ if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX))
+ or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
+ if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX))
+ or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
+ end;
+
+ if (not cArtillery) and ((Gear^.Message and gmPrecise) = 0) and (not TestCollisionXwithGear(Gear, hwSign(Gear^.dX))) then
+ Gear^.X:= Gear^.X + SignAs(_1, Gear^.dX);
+
+ SetAllHHToActive;
+
+ if TestCollisionYwithGear(Gear, 1) = 0 then
+ begin
+ Gear^.Y:= Gear^.Y + _1;
+ if TestCollisionYwithGear(Gear, 1) = 0 then
+ begin
+ Gear^.Y:= Gear^.Y + _1;
+ if TestCollisionYwithGear(Gear, 1) = 0 then
+ begin
+ Gear^.Y:= Gear^.Y + _1;
+ if TestCollisionYwithGear(Gear, 1) = 0 then
+ begin
+ Gear^.Y:= Gear^.Y + _1;
+ if TestCollisionYwithGear(Gear, 1) = 0 then
+ begin
+ Gear^.Y:= Gear^.Y + _1;
+ if TestCollisionYwithGear(Gear, 1) = 0 then
+ begin
+ Gear^.Y:= Gear^.Y + _1;
+ if TestCollisionYwithGear(Gear, 1) = 0 then
+ begin
+ Gear^.Y:= Gear^.Y - _6;
+ Gear^.dY:= _0;
+ Gear^.State:= Gear^.State or gstMoving;
+ exit
+ end;
+ end
+ end
+ end
+ end
+ end
+ end;
+ AddGearCI(Gear)
+ end
+end;
+
+procedure HedgehogChAngle(HHGear: PGear);
+var da: LongWord;
+begin
+with HHGear^.Hedgehog^ do
+ if ((CurAmmoType = amRope) and
+ ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving)) or
+ ((CurAmmoType = amPortalGun) and
+ ((HHGear^.State and gstMoving) <> 0)) then da:= 2
+ else da:= 1;
+
+if (((HHGear^.Message and gmPrecise) = 0) or ((GameTicks mod 5) = 1)) then
+ if ((HHGear^.Message and gmUp) <> 0) and (HHGear^.Angle >= CurMinAngle + da) then dec(HHGear^.Angle, da)
+ else
+ if ((HHGear^.Message and gmDown) <> 0) and (HHGear^.Angle + da <= CurMaxAngle) then inc(HHGear^.Angle, da)
+end;
+
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHedgehogMoving(Gear: PGear);
+var isFalling, isUnderwater: boolean;
+ land: Word;
+begin
+land:= 0;
+isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
+if Gear^.dX.QWordValue > 8160437862 then Gear^.dX.QWordValue:= 8160437862;
+if Gear^.dY.QWordValue > 8160437862 then Gear^.dY.QWordValue:= 8160437862;
+
+if Gear^.Hedgehog^.Unplaced then
+ begin
+ Gear^.dY:= _0;
+ Gear^.dX:= _0;
+ Gear^.State:= Gear^.State and (not gstMoving);
+ exit
+ end;
+isFalling:= (Gear^.dY.isNegative) or not TestCollisionYKick(Gear, 1);
+if isFalling then
+ begin
+ if (Gear^.dY.isNegative) and TestCollisionYKick(Gear, -1) then Gear^.dY:= _0;
+ Gear^.State:= Gear^.State or gstMoving;
+ if (CurrentHedgehog^.Gear = Gear)
+ and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then
+ begin
+ FollowGear:= Gear;
+ end;
+ if isUnderwater then Gear^.dY:= Gear^.dY + cGravity / _2
+ else
+ begin
+ Gear^.dY:= Gear^.dY + cGravity;
+// this set of circumstances could be less complex if jumping was more clearly identified
+ if ((GameFlags and gfMoreWind) <> 0) and
+ (((Gear^.Damage <> 0) or
+ ((CurAmmoGear <> nil) and
+ ((CurAmmoGear^.AmmoType = amJetpack) or
+ (CurAmmoGear^.AmmoType = amBirdy))) or
+ ((Gear^.dY.QWordValue + Gear^.dX.QWordValue) > _0_55.QWordValue)))
+ then Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
+ end
+ end
+else
+ begin
+ land:= TestCollisionYwithGear(Gear, 1);
+ if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_55.QWordValue) and ((land and lfIce) = 0)
+ and ((Gear^.State and gstHHJumping) <> 0) then SetLittle(Gear^.dX);
+
+ if not Gear^.dY.isNegative then
+ begin
+ CheckHHDamage(Gear);
+
+ if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) and
+ (Gear^.dX.QWordValue < _0_02.QWordValue) then Gear^.dX.isNegative:= not Gear^.dX.isNegative; // landing after high jump
+
+ Gear^.State:= Gear^.State and (not (gstHHJumping or gstHHHJump));
+ Gear^.dY:= _0;
+ end else Gear^.dY:= Gear^.dY + cGravity;
+
+ if ((Gear^.State and gstMoving) <> 0) then
+ begin
+ if land and lfIce <> 0 then
+ begin
+ Gear^.dX:= Gear^.dX * (_1 - (_1 - Gear^.Friction) / _2)
+ end
+ else Gear^.dX:= Gear^.dX * Gear^.Friction;
+ end
+ end;
+
+if (Gear^.State <> 0) then DeleteCI(Gear);
+
+if isUnderwater then
+ begin
+ Gear^.dY:= Gear^.dY * _0_999;
+ Gear^.dX:= Gear^.dX * _0_999;
+ end;
+
+if (Gear^.State and gstMoving) <> 0 then
+ if TestCollisionXKick(Gear, hwSign(Gear^.dX)) then
+ if not isFalling then
+ if hwAbs(Gear^.dX) > _0_01 then
+ if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -1, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_96; Gear^.Y:= Gear^.Y - _1 end else
+ if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -2, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_93; Gear^.Y:= Gear^.Y - _2 end else
+ if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -3, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_9 ; Gear^.Y:= Gear^.Y - _3 end else
+ if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -4, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_87; Gear^.Y:= Gear^.Y - _4 end else
+ if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -5, hwSign(Gear^.dX)) then begin Gear^.X:= Gear^.X + Gear^.dX; Gear^.dX:= Gear^.dX * _0_84; Gear^.Y:= Gear^.Y - _5 end else
+ if hwAbs(Gear^.dX) > _0_02 then Gear^.dX:= -Gear^.Elasticity * Gear^.dX
+ else begin
+ Gear^.State:= Gear^.State and (not gstMoving);
+ while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
+ SetLittle(Gear^.dX)
+ end
+ else begin
+ Gear^.State:= Gear^.State and (not gstMoving);
+ while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
+ SetLittle(Gear^.dX)
+ end
+ else if (hwAbs(Gear^.dX) > cLittle)
+ and ((Gear^.State and gstHHJumping) = 0)
+ then Gear^.dX:= -Gear^.Elasticity * Gear^.dX
+ else SetLittle(Gear^.dX);
+
+if (not isFalling) and
+ (hwAbs(Gear^.dX) + hwAbs(Gear^.dY) < _0_03) then
+ begin
+ Gear^.State:= Gear^.State and (not gstWinner);
+ Gear^.State:= Gear^.State and (not gstMoving);
+ while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
+ SetLittle(Gear^.dX);
+ Gear^.dY:= _0
+ end else Gear^.State:= Gear^.State or gstMoving;
+
+if (Gear^.State and gstMoving) <> 0 then
+ begin
+ Gear^.State:= Gear^.State and (not gstAnimation);
+// ARTILLERY but not being moved by explosions
+ Gear^.X:= Gear^.X + Gear^.dX;
+ Gear^.Y:= Gear^.Y + Gear^.dY;
+ if (not Gear^.dY.isNegative) and
+ (not TestCollisionYKick(Gear, 1)) and
+ TestCollisionYwithXYShift(Gear, 0, 1, 1) then
+ begin
+ CheckHHDamage(Gear);
+ Gear^.dY:= _0;
+ Gear^.Y:= Gear^.Y + _1
+ end;
+ CheckGearDrowning(Gear);
+ // hide target cursor if current hog is drowning
+ if (Gear^.State and gstDrowning) <> 0 then
+ if (CurrentHedgehog^.Gear = Gear) then
+ isCursorVisible:= false
+ end;
+
+if (hwAbs(Gear^.dY) > _0) and (Gear^.FlightTime > 0) and ((GameFlags and gfLowGravity) = 0) then
+ begin
+ inc(Gear^.FlightTime);
+ if Gear^.FlightTime = 3000 then
+ begin
+ AddCaption(GetEventString(eidHomerun), cWhiteColor, capgrpMessage);
+ PlaySound(sndHomerun)
+ end;
+ end
+else
+ begin
+ uStats.hedgehogFlight(Gear, Gear^.FlightTime);
+ Gear^.FlightTime:= 0;
+ end;
+
+end;
+
+procedure doStepHedgehogDriven(HHGear: PGear);
+var t: PGear;
+ wasJumping: boolean;
+ Hedgehog: PHedgehog;
+begin
+Hedgehog:= HHGear^.Hedgehog;
+if isInMultiShoot then
+ HHGear^.Message:= 0;
+
+if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_Utility) <> 0) and isInMultiShoot then
+ AllInactive:= true
+else if not isInMultiShoot then AllInactive:= false;
+
+if (TurnTimeLeft = 0) or (HHGear^.Damage > 0) then
+ begin
+ if TagTurnTimeLeft = 0 then TagTurnTimeLeft:= TurnTimeLeft;
+ TurnTimeLeft:= 0;
+ isCursorVisible:= false;
+ HHGear^.State:= HHGear^.State and (not (gstHHDriven or gstAnimation or gstAttacking));
+ AttackBar:= 0;
+ if HHGear^.Damage > 0 then
+ HHGear^.State:= HHGear^.State and (not (gstHHJumping or gstHHHJump));
+ exit
+ end;
+
+if (HHGear^.State and gstAnimation) <> 0 then
+ begin
+ HHGear^.Message:= 0;
+ if (HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].VoiceDelay) and (HHGear^.Timer = 0) then PlaySound(Wavez[TWave(HHGear^.Tag)].Voice, Hedgehog^.Team^.voicepack);
+ inc(HHGear^.Timer);
+ if HHGear^.Timer = Wavez[TWave(HHGear^.Tag)].Interval then
+ begin
+ HHGear^.Timer:= 0;
+ inc(HHGear^.Pos);
+ if HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].FramesCount then
+ HHGear^.State:= HHGear^.State and (not gstAnimation)
+ end;
+ exit
+ end;
+
+if ((HHGear^.State and gstMoving) <> 0)
+ or (StepTicks = cHHStepTicks)
+ or (CurAmmoGear <> nil) then // we are moving
+ begin
+ with Hedgehog^ do
+ if (CurAmmoGear = nil)
+ and (HHGear^.dY > _0_39)
+ and (CurAmmoType = amParachute) then HHGear^.Message:= HHGear^.Message or gmAttack;
+ // check for case with ammo
+ t:= CheckGearNear(HHGear, gtCase, 36, 36);
+ if t <> nil then
+ PickUp(HHGear, t)
+ end;
+
+if (CurAmmoGear = nil) then
+ if (((HHGear^.Message and gmAttack) <> 0)
+ or ((HHGear^.State and gstAttacking) <> 0)) then
+ Attack(HHGear) // should be before others to avoid desync with '/put' msg and changing weapon msgs
+ else
+else
+ with Hedgehog^ do
+ if ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
+ and ((HHGear^.Message and gmLJump) <> 0)
+ and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
+ begin
+ Attack(HHGear);
+ HHGear^.Message:= HHGear^.Message and (not gmLJump)
+ end;
+
+if (CurAmmoGear = nil)
+ or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
+ or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) then
+ begin
+ if ((HHGear^.Message and gmSlot) <> 0) then
+ if ChangeAmmo(HHGear) then ApplyAmmoChanges(Hedgehog^);
+
+ if ((HHGear^.Message and gmWeapon) <> 0) then HHSetWeapon(HHGear);
+
+ if ((HHGear^.Message and gmTimer) <> 0) then HHSetTimer(HHGear);
+ end;
+
+if CurAmmoGear <> nil then
+ begin
+ CurAmmoGear^.Message:= HHGear^.Message;
+ exit
+ end;
+
+if not isInMultiShoot then
+ HedgehogChAngle(HHGear);
+
+if (HHGear^.State and gstMoving) <> 0 then
+ begin
+ wasJumping:= ((HHGear^.State and gstHHJumping) <> 0);
+
+ if ((HHGear^.Message and gmHJump) <> 0) and
+ wasJumping and
+ ((HHGear^.State and gstHHHJump) = 0) then
+ if (not (hwAbs(HHGear^.dX) > cLittle)) and (HHGear^.dY < -_0_02) then
+ begin
+ HHGear^.State:= HHGear^.State or gstHHHJump;
+ HHGear^.dY:= -_0_25;
+ if not cArtillery then HHGear^.dX:= -SignAs(_0_02, HHGear^.dX);
+ PlaySound(sndJump2, Hedgehog^.Team^.voicepack)
+ end;
+
+ HHGear^.Message:= HHGear^.Message and (not (gmLJump or gmHJump));
+
+ if (not cArtillery) and wasJumping and
+ TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
+
+ if Hedgehog^.Gear <> nil then doStepHedgehogMoving(HHGear);
+
+ if ((HHGear^.State and (gstMoving or gstDrowning)) = 0) then
+ begin
+ AddGearCI(HHGear);
+ if wasJumping then
+ StepTicks:= 410
+ else
+ StepTicks:= 95
+ end;
+ exit
+ end;
+
+ if not isInMultiShoot and (Hedgehog^.Gear <> nil) then
+ begin
+ if StepTicks > 0 then dec(StepTicks);
+ if (StepTicks = 0) then HedgehogStep(HHGear)
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHedgehogFree(Gear: PGear);
+var prevState: Longword;
+begin
+prevState:= Gear^.State;
+
+doStepHedgehogMoving(Gear);
+
+if (Gear^.State and (gstMoving or gstDrowning)) <> 0 then
+ begin
+ if Gear^.Damage > 0 then CalcRotationDirAngle(Gear);
+ AllInactive:= false;
+ exit
+ end;
+
+if (Gear^.Health = 0) then
+ begin
+ if PrvInactive or ((GameFlags and gfInfAttack) <> 0) then
+ begin
+ Gear^.Timer:= 0;
+ FollowGear:= Gear;
+ PrvInactive:= false;
+ AllInactive:= false;
+
+ if (Gear^.State and gstHHGone) = 0 then
+ begin
+ Gear^.Hedgehog^.Effects[hePoisoned] := false;
+ if Gear^.Hedgehog^.Effects[heResurrectable] then begin
+ ResurrectHedgehog(Gear);
+ end else
+ begin
+ Gear^.State:= (Gear^.State or gstHHDeath) and (not gstAnimation);
+ Gear^.doStep:= @doStepHedgehogDead;
+ // Death message
+ AddCaption(Format(GetEventString(eidDied), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
+ end;
+ end
+ else
+ begin
+ Gear^.State:= Gear^.State and (not gstAnimation);
+ Gear^.doStep:= @doStepHedgehogGone;
+
+ // Gone message
+ AddCaption(Format(GetEventString(eidGone), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
+ end
+ end;
+ exit
+ end;
+
+if ((Gear^.State and gstWait) = 0) and
+ (prevState <> Gear^.State) then
+ begin
+ Gear^.State:= Gear^.State or gstWait;
+ Gear^.Timer:= 150
+ end else
+ begin
+ if Gear^.Timer = 0 then
+ begin
+ Gear^.State:= Gear^.State and (not (gstWait or gstLoser or gstWinner or gstAttacked or gstNotKickable or gstHHChooseTarget));
+ Gear^.Active:= false;
+ AddGearCI(Gear);
+ exit
+ end else dec(Gear^.Timer)
+ end;
+
+AllInactive:= false
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHedgehog(Gear: PGear);
+(*
+var x,y,tx,ty: LongInt;
+ tdX, tdY, slope: hwFloat;
+ land: Word; *)
+var slope: hwFloat;
+begin
+if (Gear^.Message and gmDestroy) <> 0 then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+
+if (Gear^.State and gstHHDriven) = 0 then
+ doStepHedgehogFree(Gear)
+else
+ begin
+ with Gear^.Hedgehog^ do
+ if Team^.hasGone then
+ TeamGoneEffect(Team^)
+ else
+ doStepHedgehogDriven(Gear)
+ end;
+if (Gear^.Message and (gmAllStoppable or gmLJump or gmHJump) = 0) and
+ (Gear^.State and (gstHHJumping or gstHHHJump or gstAttacking) = 0) and
+ (not Gear^.dY.isNegative) and
+ (GameTicks mod (100*LongWOrd(hwRound(cMaxWindSpeed*2/cGravity))) = 0) and
+ (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
+ begin
+ slope:= CalcSlopeBelowGear(Gear);
+ Gear^.dX:=Gear^.dX+slope*_0_07;
+ if slope.QWordValue <> 0 then Gear^.State:= Gear^.State or gstMoving;
+(*
+ x:= hwRound(Gear^.X);
+ y:= hwRound(Gear^.Y);
+ AddVisualGear(x, y, vgtSmokeTrace);
+ AddVisualGear(x - hwRound(_5*slope), y + hwRound(_5*slope), vgtSmokeTrace);
+ AddVisualGear(x + hwRound(_5*slope), y - hwRound(_5*slope), vgtSmokeTrace);
+ AddVisualGear(x - hwRound(_20 * slope), y + hwRound(_20 * slope), vgtSmokeTrace);
+ AddVisualGear(x + hwRound(_20 * slope), y - hwRound(_20 * slope), vgtSmokeTrace);
+ AddVisualGear(x - hwRound(_30 * slope), y + hwRound(_30 * slope), vgtSmokeTrace);
+ AddVisualGear(x + hwRound(_30 * slope), y - hwRound(_30 * slope), vgtSmokeTrace);
+ AddVisualGear(x - hwRound(_40 * slope), y + hwRound(_40 * slope), vgtSmokeTrace);
+ AddVisualGear(x + hwRound(_40 * slope), y - hwRound(_40 * slope), vgtSmokeTrace);
+ AddVisualGear(x - hwRound(_50 * slope), y + hwRound(_50 * slope), vgtSmokeTrace);
+ AddVisualGear(x + hwRound(_50 * slope), y - hwRound(_50 * slope), vgtSmokeTrace); *)
+ end
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uGearsList.pas Fri Dec 30 13:54:39 2011 +0400
@@ -0,0 +1,540 @@
+(*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2011 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *)
+
+{$INCLUDE "options.inc"}
+unit uGearsList;
+
+interface
+uses uFloat, uTypes;
+
+function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
+procedure DeleteGear(Gear: PGear);
+
+implementation
+
+uses uDebug, uRandom, uUtils, uConsts, uVariables, uAmmos, uTeams, uStats,
+ uTextures, uScript, uRenderUtils, uAI, uCollisions, uGearsHedgehog;
+
+procedure InsertGearToList(Gear: PGear);
+var tmp, ptmp: PGear;
+begin
+ tmp:= GearsList;
+ ptmp:= GearsList;
+ while (tmp <> nil) and (tmp^.Z <= Gear^.Z) do
+ begin
+ ptmp:= tmp;
+ tmp:= tmp^.NextGear
+ end;
+
+ if ptmp <> tmp then
+ begin
+ Gear^.NextGear:= ptmp^.NextGear;
+ Gear^.PrevGear:= ptmp;
+ if ptmp^.NextGear <> nil then ptmp^.NextGear^.PrevGear:= Gear;
+ ptmp^.NextGear:= Gear
+ end
+ else
+ begin
+ Gear^.NextGear:= GearsList;
+ if Gear^.NextGear <> nil then Gear^.NextGear^.PrevGear:= Gear;
+ GearsList:= Gear;
+ end;
+end;
+
+procedure RemoveGearFromList(Gear: PGear);
+begin
+if Gear^.NextGear <> nil then Gear^.NextGear^.PrevGear:= Gear^.PrevGear;
+if Gear^.PrevGear <> nil then
+ Gear^.PrevGear^.NextGear:= Gear^.NextGear
+else
+ GearsList:= Gear^.NextGear
+end;
+
+function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
+const Counter: Longword = 0;
+var gear: PGear;
+begin
+inc(Counter);
+AddFileLog('AddGear: #' + inttostr(Counter) + ' (' + inttostr(x) + ',' + inttostr(y) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
+
+New(gear);
+FillChar(gear^, sizeof(TGear), 0);
+gear^.X:= int2hwFloat(X);
+gear^.Y:= int2hwFloat(Y);
+gear^.Target.X:= NoPointX;
+gear^.Kind := Kind;
+gear^.State:= State;
+gear^.Active:= true;
+gear^.dX:= dX;
+gear^.dY:= dY;
+gear^.doStep:= doStepHandlers[Kind];
+gear^.CollisionIndex:= -1;
+gear^.Timer:= Timer;
+gear^.FlightTime:= 0;
+gear^.uid:= Counter;
+gear^.SoundChannel:= -1;
+gear^.ImpactSound:= sndNone;
+gear^.nImpactSounds:= 0;
+gear^.Density:= _1;
+// Define ammo association, if any.
+gear^.AmmoType:= GearKindAmmoTypeMap[Kind];
+if Ammoz[Gear^.AmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then gear^.Z:= cHHZ+1
+else gear^.Z:= cUsualZ;
+
+if CurrentHedgehog <> nil then
+ begin
+ gear^.Hedgehog:= CurrentHedgehog;
+ gear^.IntersectGear:= CurrentHedgehog^.Gear
+ end;
+
+case Kind of
+ gtGrenade,
+ gtClusterBomb,
+ gtGasBomb: begin
+ gear^.ImpactSound:= sndGrenadeImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.AdvBounce:= 1;
+ gear^.Radius:= 5;
+ gear^.Elasticity:= _0_8;
+ gear^.Friction:= _0_8;
+ gear^.Density:= _1_5;
+ gear^.RenderTimer:= true;
+ if gear^.Timer = 0 then gear^.Timer:= 3000
+ end;
+ gtWatermelon: begin
+ gear^.ImpactSound:= sndMelonImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.AdvBounce:= 1;
+ gear^.Radius:= 6;
+ gear^.Elasticity:= _0_8;
+ gear^.Friction:= _0_995;
+ gear^.Density:= _2;
+ gear^.RenderTimer:= true;
+ if gear^.Timer = 0 then gear^.Timer:= 3000
+ end;
+ gtMelonPiece: begin
+ gear^.Density:= _2;
+ end;
+ gtHedgehog: begin
+ gear^.AdvBounce:= 1;
+ gear^.Radius:= cHHRadius;
+ gear^.Elasticity:= _0_35;
+ gear^.Friction:= _0_999;
+ gear^.Angle:= cMaxAngle div 2;
+ gear^.Density:= _3;
+ gear^.Z:= cHHZ;
+ if (GameFlags and gfAISurvival) <> 0 then
+ if gear^.Hedgehog^.BotLevel > 0 then
+ gear^.Hedgehog^.Effects[heResurrectable] := true;
+ end;
+ gtShell: begin
+ gear^.Radius:= 4;
+ gear^.Density:= _1;
+ end;
+ gtSnowball: begin
+ gear^.ImpactSound:= sndMudballImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.Radius:= 4;
+ gear^.Elasticity:= _1;
+ gear^.Friction:= _1;
+ gear^.Density:= _0_5;
+ end;
+
+ gtFlake: begin
+ with Gear^ do
+ begin
+ Pos:= 0;
+ Radius:= 1;
+ DirAngle:= random * 360;
+ if State and gstTmpFlag = 0 then
+ begin
+ dx.isNegative:= GetRandom(2) = 0;
+ dx.QWordValue:= GetRandom(100000000);
+ dy.isNegative:= false;
+ dy.QWordValue:= GetRandom(70000000);
+ if GetRandom(2) = 0 then dx := -dx
+ end;
+ State:= State or gstInvisible;
+ Health:= random(vobFrameTicks);
+ Timer:= random(vobFramesCount);
+ Angle:= (random(2) * 2 - 1) * (1 + random(10000)) * vobVelocity
+ end
+ end;
+ gtGrave: begin
+ gear^.ImpactSound:= sndGraveImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.Radius:= 10;
+ gear^.Elasticity:= _0_6;
+ end;
+ gtBee: begin
+ gear^.Radius:= 5;
+ gear^.Timer:= 500;
+ gear^.RenderTimer:= true;
+ gear^.Elasticity:= _0_9;
+ gear^.Tag:= 0;
+ end;
+ gtSeduction: begin
+ gear^.Radius:= 250;
+ end;
+ gtShotgunShot: begin
+ gear^.Timer:= 900;
+ gear^.Radius:= 2
+ end;
+ gtPickHammer: begin
+ gear^.Radius:= 10;
+ gear^.Timer:= 4000
+ end;
+ gtHammerHit: begin
+ gear^.Radius:= 8;
+ gear^.Timer:= 125
+ end;
+ gtRope: begin
+ gear^.Radius:= 3;
+ gear^.Friction:= _450 * _0_01 * cRopePercent;
+ RopePoints.Count:= 0;
+ end;
+ gtMine: begin
+ gear^.ImpactSound:= sndMineImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.Health:= 10;
+ gear^.State:= gear^.State or gstMoving;
+ gear^.Radius:= 2;
+ gear^.Elasticity:= _0_55;
+ gear^.Friction:= _0_995;
+ gear^.Density:= _0_9;
+ if cMinesTime < 0 then
+ gear^.Timer:= getrandom(51)*100
+ else
+ gear^.Timer:= cMinesTime;
+ end;
+ gtSMine: begin
+ gear^.Health:= 10;
+ gear^.State:= gear^.State or gstMoving;
+ gear^.Radius:= 2;
+ gear^.Elasticity:= _0_55;
+ gear^.Friction:= _0_995;
+ gear^.Density:= _0_9;
+ gear^.Timer:= 500;
+ end;
+ gtCase: begin
+ gear^.ImpactSound:= sndGraveImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.Radius:= 16;
+ gear^.Elasticity:= _0_3
+ end;
+ gtExplosives: begin
+ gear^.ImpactSound:= sndGrenadeImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.Radius:= 16;
+ gear^.Elasticity:= _0_4;
+ gear^.Friction:= _0_995;
+ gear^.Density:= _6;
+ gear^.Health:= cBarrelHealth;
+ gear^.Z:= cHHZ-1
+ end;
+ gtDEagleShot: begin
+ gear^.Radius:= 1;
+ gear^.Health:= 50
+ end;
+ gtSniperRifleShot: begin
+ gear^.Radius:= 1;
+ gear^.Health:= 50
+ end;
+ gtDynamite: begin
+ gear^.Radius:= 3;
+ gear^.Elasticity:= _0_55;
+ gear^.Friction:= _0_03;
+ gear^.Density:= _2;
+ gear^.Timer:= 5000;
+ end;
+ gtCluster: begin
+ gear^.Radius:= 2;
+ gear^.Density:= _1_5;
+ gear^.RenderTimer:= true
+ end;
+ gtShover: gear^.Radius:= 20;
+ gtFlame: begin
+ gear^.Tag:= GetRandom(32);
+ gear^.Radius:= 1;
+ gear^.Health:= 5;
+ gear^.Density:= _1;
+ if (gear^.dY.QWordValue = 0) and (gear^.dX.QWordValue = 0) then
+ begin
+ gear^.dY:= (getrandom - _0_8) * _0_03;
+ gear^.dX:= (getrandom - _0_5) * _0_4
+ end
+ end;
+ gtFirePunch: begin
+ gear^.Radius:= 15;
+ gear^.Tag:= Y
+ end;
+ gtAirBomb: begin
+ gear^.Radius:= 5;
+ gear^.Density:= _2;
+ end;
+ gtBlowTorch: begin
+ gear^.Radius:= cHHRadius + cBlowTorchC;
+ gear^.Timer:= 7500
+ end;
+ gtSwitcher: begin
+ gear^.Z:= cCurrHHZ
+ end;
+ gtTarget: begin
+ gear^.ImpactSound:= sndGrenadeImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.Radius:= 10;
+ gear^.Elasticity:= _0_3;
+ gear^.Timer:= 0
+ end;
+ gtTardis: begin
+ gear^.Timer:= 0;
+ gear^.Pos:= 1;
+ gear^.Z:= cCurrHHZ+1;
+ end;
+ gtMortar: begin
+ gear^.Radius:= 4;
+ gear^.Elasticity:= _0_2;
+ gear^.Friction:= _0_08;
+ gear^.Density:= _1;
+ end;
+ gtWhip: gear^.Radius:= 20;
+ gtHammer: gear^.Radius:= 20;
+ gtKamikaze: begin
+ gear^.Health:= 2048;
+ gear^.Radius:= 20
+ end;
+ gtCake: begin
+ gear^.Health:= 2048;
+ gear^.Radius:= 7;
+ gear^.Z:= cOnHHZ;
+ gear^.RenderTimer:= true;
+ gear^.DirAngle:= -90 * hwSign(Gear^.dX);
+ if not dX.isNegative then gear^.Angle:= 1 else gear^.Angle:= 3
+ end;
+ gtHellishBomb: begin
+ gear^.ImpactSound:= sndHellishImpact1;
+ gear^.nImpactSounds:= 4;
+ gear^.AdvBounce:= 1;
+ gear^.Radius:= 4;
+ gear^.Elasticity:= _0_5;
+ gear^.Friction:= _0_96;
+ gear^.Density:= _1_5;
+ gear^.RenderTimer:= true;
+ gear^.Timer:= 5000
+ end;
+ gtDrill: begin
+ if gear^.Timer = 0 then gear^.Timer:= 5000;
+ // Tag for drill strike. if 1 then first impact occured already
+ gear^.Tag := 0;
+ gear^.Radius:= 4;
+ gear^.Density:= _1;
+ end;
+ gtBall: begin
+ gear^.ImpactSound:= sndGrenadeImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.AdvBounce:= 1;
+ gear^.Radius:= 5;
+ gear^.Tag:= random(8);
+ gear^.Timer:= 5000;
+ gear^.Elasticity:= _0_7;
+ gear^.Friction:= _0_995;
+ gear^.Density:= _1_5;
+ end;
+ gtBallgun: begin
+ gear^.Timer:= 5001;
+ end;
+ gtRCPlane: begin
+ gear^.Timer:= 15000;
+ gear^.Health:= 3;
+ gear^.Radius:= 8
+ end;
+ gtJetpack: begin
+ gear^.Health:= 2000;
+ gear^.Damage:= 100
+ end;
+ gtMolotov: begin
+ gear^.Radius:= 6;
+ gear^.Density:= _2;
+ end;
+ gtBirdy: begin
+ gear^.Radius:= 16; // todo: check
+ gear^.Timer:= 0;
+ gear^.Health := 2000;
+ gear^.FlightTime := 2;
+ end;
+ gtEgg: begin
+ gear^.Radius:= 4;
+ gear^.Elasticity:= _0_6;
+ gear^.Friction:= _0_96;
+ gear^.Density:= _1;
+ if gear^.Timer = 0 then gear^.Timer:= 3000
+ end;
+ gtPortal: begin
+ gear^.ImpactSound:= sndMelonImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.AdvBounce:= 0;
+ gear^.Radius:= 17;
+ // set color
+ gear^.Tag:= 2 * gear^.Timer;
+ gear^.Timer:= 15000;
+ gear^.RenderTimer:= false;
+ gear^.Health:= 100;
+ end;
+ gtPiano: begin
+ gear^.Radius:= 32;
+ gear^.Density:= _50;
+ end;
+ gtSineGunShot: begin
+ gear^.Radius:= 5;
+ gear^.Health:= 6000;
+ end;
+gtFlamethrower: begin
+ gear^.Tag:= 10;
+ gear^.Timer:= 10;
+ gear^.Health:= 500;
+ gear^.Damage:= 100;
+ end;
+ gtLandGun: begin
+ gear^.Tag:= 10;
+ gear^.Timer:= 10;
+ gear^.Health:= 1000;
+ gear^.Damage:= 100;
+ end;
+ gtPoisonCloud: begin
+ gear^.Timer:= 5000;
+ gear^.dY:= int2hwfloat(-4 + longint(getRandom(8))) / 1000;
+ end;
+ gtResurrector: begin
+ gear^.Radius := 100;
+ gear^.Tag := 0
+ end;
+ gtWaterUp: begin
+ gear^.Tag := 47;
+ end;
+ gtNapalmBomb: begin
+ gear^.Timer:= 1000;
+ gear^.Radius:= 5;
+ gear^.Density:= _1_5;
+ end;
+ gtStructure: begin
+ gear^.Elasticity:= _0_55;
+ gear^.Friction:= _0_995;
+ gear^.Density:= _0_9;
+ gear^.Radius:= 13;
+ gear^.Health:= 200;
+ gear^.Tag:= 3;
+ end;
+ end;
+
+InsertGearToList(gear);
+AddGear:= gear;
+
+ScriptCall('onGearAdd', gear^.uid);
+end;
+
+procedure DeleteGear(Gear: PGear);
+var team: PTeam;
+ t,i: Longword;
+ k: boolean;
+begin
+
+ScriptCall('onGearDelete', gear^.uid);
+
+DeleteCI(Gear);
+
+FreeTexture(Gear^.Tex);
+Gear^.Tex:= nil;
+
+// make sure that portals have their link removed before deletion
+if (Gear^.Kind = gtPortal) then
+ begin
+ if (Gear^.IntersectGear <> nil) then
+ if (Gear^.IntersectGear^.IntersectGear = Gear) then
+ Gear^.IntersectGear^.IntersectGear:= nil;
+ end
+else if Gear^.Kind = gtHedgehog then
+ (*
+ This behaviour dates back to revision 4, and I accidentally encountered it with TARDIS. I don't think it must apply to any modern weapon, since if it was actually hit, the best the gear could do would be to destroy itself immediately, and you'd still end up with two graves. I believe it should be removed
+ if (CurAmmoGear <> nil) and (CurrentHedgehog^.Gear = Gear) then
+ begin
+ AttackBar:= 0;
+ Gear^.Message:= gmDestroy;
+ CurAmmoGear^.Message:= gmDestroy;
+ exit
+ end
+ else*)
+ begin
+ if (hwRound(Gear^.Y) >= cWaterLine) then
+ begin
+ t:= max(Gear^.Damage, Gear^.Health);
+ Gear^.Damage:= t;
+ if ((not SuddenDeathDmg and (cWaterOpacity < $FF)) or (SuddenDeathDmg and (cWaterOpacity < $FF))) and (hwRound(Gear^.Y) < cWaterLine + 256) then
+ spawnHealthTagForHH(Gear, t);
+ end;
+
+ team:= Gear^.Hedgehog^.Team;
+ if CurrentHedgehog^.Gear = Gear then
+ begin
+ AttackBar:= 0;
+ FreeActionsList; // to avoid ThinkThread on drawned gear
+ if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (CurrentHedgehog^.MultiShootAttacks > 0) then OnUsedAmmo(CurrentHedgehog^);
+ end;
+
+ Gear^.Hedgehog^.Gear:= nil;
+ if Gear^.Hedgehog^.King then
+ begin
+ // are there any other kings left? Just doing nil check. Presumably a mortally wounded king will get reaped soon enough
+ k:= false;
+ for i:= 0 to Pred(team^.Clan^.TeamsNumber) do
+ if (team^.Clan^.Teams[i]^.Hedgehogs[0].Gear <> nil) then k:= true;
+ if not k then
+ for i:= 0 to Pred(team^.Clan^.TeamsNumber) do
+ begin
+ team^.Clan^.Teams[i]^.hasGone:= true;
+ TeamGoneEffect(team^.Clan^.Teams[i]^)
+ end
+ end;
+
+ // should be not CurrentHedgehog, but hedgehog of the last gear which caused damage to this hog
+ // same stand for CheckHHDamage
+ if (Gear^.LastDamage <> nil) then
+ uStats.HedgehogDamaged(Gear, Gear^.LastDamage, 0, true)
+ else
+ uStats.HedgehogDamaged(Gear, CurrentHedgehog, 0, true);
+
+ inc(KilledHHs);
+ RecountTeamHealth(team);
+ if (CurrentHedgehog <> nil) and CurrentHedgehog^.Effects[heResurrectable] and (not Gear^.Hedgehog^.Effects[heResurrectable]) then
+ with CurrentHedgehog^ do
+ begin
+ inc(Team^.stats.AIKills);
+ FreeTexture(Team^.AIKillsTex);
+ Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16);
+ end
+ end;
+with Gear^ do
+ AddFileLog('Delete: #' + inttostr(uid) + ' (' + inttostr(hwRound(x)) + ',' + inttostr(hwRound(y)) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
+
+if CurAmmoGear = Gear then CurAmmoGear:= nil;
+if FollowGear = Gear then FollowGear:= nil;
+if lastGearByUID = Gear then lastGearByUID := nil;
+RemoveGearFromList(Gear);
+Dispose(Gear)
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uGearsUtils.pas Fri Dec 30 13:54:39 2011 +0400
@@ -0,0 +1,559 @@
+(*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2011 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *)
+
+{$INCLUDE "options.inc"}
+
+unit uGearsUtils;
+interface
+uses uTypes;
+
+procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord = $FFFFFFFF);
+function ModifyDamage(dmg: Longword; Gear: PGear): Longword;
+procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
+procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword);
+procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
+procedure CheckHHDamage(Gear: PGear);
+procedure CalcRotationDirAngle(Gear: PGear);
+procedure ResurrectHedgehog(gear: PGear);
+procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean = false);
+function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear;
+function CheckGearsNear(mX, mY: LongInt; Kind: TGearsType; rX, rY: LongInt): PGear;
+
+
+implementation
+uses uFloat, uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc,
+ uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore,
+ uLocale, uTextures, uRenderUtils, uRandom, uGearsList, SDLh, uDebug;
+
+procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord);
+var Gear: PGear;
+ dmg, dmgRadius, dmgBase: LongInt;
+ fX, fY: hwFloat;
+ vg: PVisualGear;
+ i, cnt: LongInt;
+begin
+ if Radius > 4 then AddFileLog('Explosion: at (' + inttostr(x) + ',' + inttostr(y) + ')');
+ if Radius > 25 then KickFlakes(Radius, X, Y);
+
+ if ((Mask and EXPLNoGfx) = 0) then
+ begin
+ vg:= nil;
+ if Radius > 50 then vg:= AddVisualGear(X, Y, vgtBigExplosion)
+ else if Radius > 10 then vg:= AddVisualGear(X, Y, vgtExplosion);
+ if vg <> nil then
+ vg^.Tint:= Tint;
+ end;
+ if (Mask and EXPLAutoSound) <> 0 then PlaySound(sndExplosion);
+
+ if (Mask and EXPLAllDamageInRadius) = 0 then
+ dmgRadius:= Radius shl 1
+ else
+ dmgRadius:= Radius;
+ dmgBase:= dmgRadius + cHHRadius div 2;
+ fX:= int2hwFloat(X);
+ fY:= int2hwFloat(Y);
+ Gear:= GearsList;
+ while Gear <> nil do
+ begin
+ dmg:= 0;
+ //dmg:= dmgRadius + cHHRadius div 2 - hwRound(Distance(Gear^.X - int2hwFloat(X), Gear^.Y - int2hwFloat(Y)));
+ //if (dmg > 1) and
+ if (Gear^.State and gstNoDamage) = 0 then
+ begin
+ case Gear^.Kind of
+ gtHedgehog,
+ gtMine,
+ gtBall,
+ gtMelonPiece,
+ gtGrenade,
+ gtClusterBomb,
+ // gtCluster, too game breaking I think
+ gtSMine,
+ gtCase,
+ gtTarget,
+ gtFlame,
+ gtExplosives,
+ gtStructure: begin
+ // Run the calcs only once we know we have a type that will need damage
+ if hwRound(hwAbs(Gear^.X-fX)+hwAbs(Gear^.Y-fY)) < dmgBase then
+ dmg:= dmgBase - max(hwRound(Distance(Gear^.X - fX, Gear^.Y - fY)),Gear^.Radius);
+ if dmg > 1 then
+ begin
+ dmg:= ModifyDamage(min(dmg div 2, Radius), Gear);
+ //AddFileLog('Damage: ' + inttostr(dmg));
+ if (Mask and EXPLNoDamage) = 0 then
+ begin
+ if not Gear^.Invulnerable then
+ ApplyDamage(Gear, AttackingHog, dmg, dsExplosion)
+ else
+ Gear^.State:= Gear^.State or gstWinner;
+ end;
+ if ((Mask and EXPLDoNotTouchAny) = 0) and (((Mask and EXPLDoNotTouchHH) = 0) or (Gear^.Kind <> gtHedgehog)) then
+ begin
+ DeleteCI(Gear);
+ if Gear^.Kind <> gtHedgehog then
+ begin
+ Gear^.dX:= Gear^.dX + SignAs(_0_005 * dmg + cHHKick, Gear^.X - fX)/Gear^.Density;
+ Gear^.dY:= Gear^.dY + SignAs(_0_005 * dmg + cHHKick, Gear^.Y - fY)/Gear^.Density;
+ end
+ else
+ begin
+ Gear^.dX:= Gear^.dX + SignAs(_0_005 * dmg + cHHKick, Gear^.X - fX);
+ Gear^.dY:= Gear^.dY + SignAs(_0_005 * dmg + cHHKick, Gear^.Y - fY);
+ end;
+
+ Gear^.State:= (Gear^.State or gstMoving) and (not gstLoser);
+ if not Gear^.Invulnerable then
+ Gear^.State:= (Gear^.State or gstMoving) and (not gstWinner);
+ Gear^.Active:= true;
+ if Gear^.Kind <> gtFlame then FollowGear:= Gear
+ end;
+ if ((Mask and EXPLPoisoned) <> 0) and (Gear^.Kind = gtHedgehog) and (not Gear^.Invulnerable) then
+ Gear^.Hedgehog^.Effects[hePoisoned] := true;
+ end;
+
+ end;
+ gtGrave: begin
+ // Run the calcs only once we know we have a type that will need damage
+ if hwRound(hwAbs(Gear^.X-fX)+hwAbs(Gear^.Y-fY)) < dmgBase then
+ dmg:= dmgBase - hwRound(Distance(Gear^.X - fX, Gear^.Y - fY));
+ if dmg > 1 then
+ begin
+ dmg:= ModifyDamage(min(dmg div 2, Radius), Gear);
+ Gear^.dY:= - _0_004 * dmg;
+ Gear^.Active:= true
+ end
+ end;
+ end;
+ end;
+ Gear:= Gear^.NextGear
+ end;
+
+ if (Mask and EXPLDontDraw) = 0 then
+ if (GameFlags and gfSolidLand) = 0 then
+ begin
+ cnt:= DrawExplosion(X, Y, Radius) div 1608; // approx 2 16x16 circles to erase per chunk
+ if (cnt > 0) and (SpritesData[sprChunk].Texture <> nil) then
+ for i:= 0 to cnt do
+ AddVisualGear(X, Y, vgtChunk)
+ end;
+
+ uAIMisc.AwareOfExplosion(0, 0, 0)
+end;
+
+function ModifyDamage(dmg: Longword; Gear: PGear): Longword;
+var i: hwFloat;
+begin
+(* Invulnerability cannot be placed in here due to still needing kicks
+ Not without a new damage machine.
+ King check should be in here instead of ApplyDamage since Tiy wants them kicked less
+*)
+i:= _1;
+if (CurrentHedgehog <> nil) and CurrentHedgehog^.King then i:= _1_5;
+if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.King) then
+ ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent * _0_5)
+else
+ ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent)
+end;
+
+procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
+var s: shortstring;
+ vampDmg, tmpDmg, i: Longword;
+ vg: PVisualGear;
+begin
+ if Damage = 0 then exit; // nothing to apply
+
+ if (Gear^.Kind = gtHedgehog) then
+ begin
+ Gear^.LastDamage := AttackerHog;
+
+ Gear^.Hedgehog^.Team^.Clan^.Flawless:= false;
+ HHHurt(Gear^.Hedgehog, Source);
+ AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), Damage, Gear^.Hedgehog^.Team^.Clan^.Color);
+ tmpDmg:= min(Damage, max(0,Gear^.Health-Gear^.Damage));
+ if (Gear <> CurrentHedgehog^.Gear) and (CurrentHedgehog^.Gear <> nil) and (tmpDmg >= 1) then
+ begin
+ if cVampiric then
+ begin
+ vampDmg:= hwRound(int2hwFloat(tmpDmg)*_0_8);
+ if vampDmg >= 1 then
+ begin
+ // 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);
+ str(vampDmg, s);
+ s:= '+' + s;
+ AddCaption(s, CurrentHedgehog^.Team^.Clan^.Color, capgrpAmmoinfo);
+ RenderHealth(CurrentHedgehog^);
+ RecountTeamHealth(CurrentHedgehog^.Team);
+ i:= 0;
+ while i < vampDmg 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;
+ end
+ end;
+ if ((GameFlags and gfKarma) <> 0) and
+ ((GameFlags and gfInvulnerable) = 0) and
+ (not CurrentHedgehog^.Gear^.Invulnerable) then
+ begin // this cannot just use Damage or it interrupts shotgun and gets you called stupid
+ inc(CurrentHedgehog^.Gear^.Karma, tmpDmg);
+ CurrentHedgehog^.Gear^.LastDamage := CurrentHedgehog;
+ spawnHealthTagForHH(CurrentHedgehog^.Gear, tmpDmg);
+ end;
+ uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false);
+ end;
+ end else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure
+ begin
+ Gear^.Hedgehog:= AttackerHog;
+ end;
+ inc(Gear^.Damage, Damage);
+
+ ScriptCall('onGearDamage', Gear^.UID, Damage);
+end;
+
+procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword);
+var tag: PVisualGear;
+begin
+tag:= AddVisualGear(hwRound(HHGear^.X), hwRound(HHGear^.Y), vgtHealthTag, dmg);
+if (tag <> nil) then
+ tag^.Hedgehog:= HHGear^.Hedgehog; // the tag needs the tag to determine the text color
+AllInactive:= false;
+HHGear^.Active:= true;
+end;
+
+procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
+begin
+if (Source = dsFall) or (Source = dsExplosion) then
+ case random(3) of
+ 0: PlaySound(sndOoff1, Hedgehog^.Team^.voicepack);
+ 1: PlaySound(sndOoff2, Hedgehog^.Team^.voicepack);
+ 2: PlaySound(sndOoff3, Hedgehog^.Team^.voicepack);
+ end
+else if (Source = dsPoison) then
+ case random(2) of
+ 0: PlaySound(sndPoisonCough, Hedgehog^.Team^.voicepack);
+ 1: PlaySound(sndPoisonMoan, Hedgehog^.Team^.voicepack);
+ end
+else
+ case random(4) of
+ 0: PlaySound(sndOw1, Hedgehog^.Team^.voicepack);
+ 1: PlaySound(sndOw2, Hedgehog^.Team^.voicepack);
+ 2: PlaySound(sndOw3, Hedgehog^.Team^.voicepack);
+ 3: PlaySound(sndOw4, Hedgehog^.Team^.voicepack);
+ end
+end;
+
+procedure CheckHHDamage(Gear: PGear);
+var
+ dmg: Longword;
+ i: LongInt;
+ particle: PVisualGear;
+begin
+ if _0_4 < Gear^.dY then
+ begin
+ dmg := ModifyDamage(1 + hwRound((hwAbs(Gear^.dY) - _0_4) * 70), Gear);
+ PlaySound(sndBump);
+ if dmg < 1 then exit;
+
+ for i:= min(12, (3 + dmg div 10)) downto 0 do
+ begin
+ particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
+ if particle <> nil then particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480);
+ end;
+
+ if (Gear^.Invulnerable) then exit;
+
+ //if _0_6 < Gear^.dY then
+ // PlaySound(sndOw4, Gear^.Hedgehog^.Team^.voicepack)
+ //else
+ // PlaySound(sndOw1, Gear^.Hedgehog^.Team^.voicepack);
+
+ if Gear^.LastDamage <> nil then
+ ApplyDamage(Gear, Gear^.LastDamage, dmg, dsFall)
+ else
+ ApplyDamage(Gear, CurrentHedgehog, dmg, dsFall);
+ end
+end;
+
+
+procedure CalcRotationDirAngle(Gear: PGear);
+var
+ dAngle: real;
+begin
+ dAngle := (Gear^.dX.QWordValue + Gear^.dY.QWordValue) / $80000000;
+ if not Gear^.dX.isNegative then
+ Gear^.DirAngle := Gear^.DirAngle + dAngle
+ else
+ Gear^.DirAngle := Gear^.DirAngle - dAngle;
+
+ if Gear^.DirAngle < 0 then Gear^.DirAngle := Gear^.DirAngle + 360
+ else if 360 < Gear^.DirAngle then Gear^.DirAngle := Gear^.DirAngle - 360
+end;
+
+function CheckGearDrowning(Gear: PGear): boolean;
+var
+ skipSpeed, skipAngle, skipDecay: hwFloat;
+ i, maxDrops, X, Y: LongInt;
+ vdX, vdY: real;
+ particle: PVisualGear;
+ isSubmersible: boolean;
+begin
+ isSubmersible:= (Gear = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amJetpack);
+ // probably needs tweaking. might need to be in a case statement based upon gear type
+ Y:= hwRound(Gear^.Y);
+ if cWaterLine < Y + Gear^.Radius then
+ begin
+ skipSpeed := _0_25;
+ skipAngle := _1_9;
+ skipDecay := _0_87;
+ X:= hwRound(Gear^.X);
+ vdX:= hwFloat2Float(Gear^.dX);
+ vdY:= hwFloat2Float(Gear^.dY);
+ // this could perhaps be a tiny bit higher.
+ if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed) and
+ (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)) then
+ begin
+ Gear^.dY.isNegative := true;
+ Gear^.dY := Gear^.dY * skipDecay;
+ Gear^.dX := Gear^.dX * skipDecay;
+ CheckGearDrowning := false;
+ PlaySound(sndSkip)
+ end
+ else
+ begin
+ if not isSubmersible then
+ begin
+ CheckGearDrowning := true;
+ Gear^.State := gstDrowning;
+ Gear^.RenderTimer := false;
+ if (Gear^.Kind <> gtSniperRifleShot) and (Gear^.Kind <> gtShotgunShot) and
+ (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot) then
+ if Gear^.Kind = gtHedgehog then
+ begin
+ if Gear^.Hedgehog^.Effects[heResurrectable] then
+ ResurrectHedgehog(Gear)
+ else
+ begin
+ Gear^.doStep := @doStepDrowningGear;
+ Gear^.State := Gear^.State and (not gstHHDriven);
+ AddCaption(Format(GetEventString(eidDrowned), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
+ end
+ end
+ else Gear^.doStep := @doStepDrowningGear;
+ if Gear^.Kind = gtFlake then exit // skip splashes
+ end;
+ if ((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius)) or
+ (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) and (CurAmmoGear^.dY < _0_01))) then
+ // don't play splash if they are already way past the surface
+ PlaySound(sndSplash)
+ end;
+
+ if ((cReducedQuality and rqPlainSplash) = 0) and
+ (((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius)) or
+ (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) and (CurAmmoGear^.dY < _0_01)))) then
+ begin
+ AddVisualGear(X, cWaterLine, vgtSplash);
+
+ maxDrops := (Gear^.Radius div 2) + round(vdX * Gear^.Radius * 2) + round(vdY * Gear^.Radius * 2);
+ for i:= max(maxDrops div 3, min(32, Random(maxDrops))) downto 0 do
+ begin
+ particle := AddVisualGear(X - 3 + Random(6), cWaterLine, vgtDroplet);
+ if particle <> nil then
+ begin
+ particle^.dX := particle^.dX - vdX / 10;
+ particle^.dY := particle^.dY - vdY / 5;
+ end
+ end
+ end;
+ if isSubmersible and (CurAmmoGear^.Pos = 0) then CurAmmoGear^.Pos := 1000
+ end
+ else
+ CheckGearDrowning := false;
+end;
+
+
+procedure ResurrectHedgehog(gear: PGear);
+var tempTeam : PTeam;
+begin
+ AttackBar:= 0;
+ gear^.dX := _0;
+ gear^.dY := _0;
+ gear^.Damage := 0;
+ gear^.Health := gear^.Hedgehog^.InitialHealth;
+ gear^.Hedgehog^.Effects[hePoisoned] := false;
+ if not CurrentHedgehog^.Effects[heResurrectable] then
+ with CurrentHedgehog^ do
+ begin
+ inc(Team^.stats.AIKills);
+ FreeTexture(Team^.AIKillsTex);
+ Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16);
+ end;
+ tempTeam := gear^.Hedgehog^.Team;
+ DeleteCI(gear);
+ FindPlace(gear, false, 0, LAND_WIDTH, true);
+ if gear <> nil then begin
+ RenderHealth(gear^.Hedgehog^);
+ ScriptCall('onGearResurrect', gear^.uid);
+ gear^.State := gstWait;
+ end;
+ RecountTeamHealth(tempTeam);
+end;
+
+
+procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean);
+
+ function CountNonZeroz(x, y, r, c: LongInt): LongInt;
+ var i: LongInt;
+ count: LongInt = 0;
+ begin
+ if (y and LAND_HEIGHT_MASK) = 0 then
+ for i:= max(x - r, 0) to min(x + r, LAND_WIDTH - 4) do
+ if Land[y, i] <> 0 then
+ begin
+ inc(count);
+ if count = c then exit(count)
+ end;
+ CountNonZeroz:= count;
+ end;
+
+var x: LongInt;
+ y, sy: LongInt;
+ ar: array[0..511] of TPoint;
+ ar2: array[0..1023] of TPoint;
+ cnt, cnt2: Longword;
+ delta: LongInt;
+ reallySkip, tryAgain: boolean;
+begin
+reallySkip:= false; // try not skipping proximity at first
+tryAgain:= true;
+while tryAgain do
+ begin
+ delta:= 250;
+ cnt2:= 0;
+ repeat
+ x:= Left + LongInt(GetRandom(Delta));
+ repeat
+ inc(x, Delta);
+ cnt:= 0;
+ y:= min(1024, topY) - 2 * Gear^.Radius;
+ while y < cWaterLine do
+ begin
+ repeat
+ inc(y, 2);
+ until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) = 0);
+
+ sy:= y;
+
+ repeat
+ inc(y);
+ until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) <> 0);
+
+ if (y - sy > Gear^.Radius * 2) and
+ (((Gear^.Kind = gtExplosives)
+ and (y < cWaterLine)
+ and (reallySkip or (CheckGearsNear(x, y - Gear^.Radius, [gtFlame, gtHedgehog, gtMine, gtCase, gtExplosives], 60, 60) = nil))
+ and (CountNonZeroz(x, y+1, Gear^.Radius - 1, Gear^.Radius+1) > Gear^.Radius))
+ or
+ ((Gear^.Kind <> gtExplosives)
+ and (y < cWaterLine)
+ and (reallySkip or (CheckGearsNear(x, y - Gear^.Radius, [gtFlame, gtHedgehog, gtMine, gtCase, gtExplosives], 110, 110) = nil)))) then
+ begin
+ ar[cnt].X:= x;
+ if withFall then ar[cnt].Y:= sy + Gear^.Radius
+ else ar[cnt].Y:= y - Gear^.Radius;
+ inc(cnt)
+ end;
+
+ inc(y, 45)
+ end;
+
+ if cnt > 0 then
+ with ar[GetRandom(cnt)] do
+ begin
+ ar2[cnt2].x:= x;
+ ar2[cnt2].y:= y;
+ inc(cnt2)
+ end
+ until (x + Delta > Right);
+
+ dec(Delta, 60)
+ until (cnt2 > 0) or (Delta < 70);
+ if (cnt2 = 0) and skipProximity and (not reallySkip) then tryAgain:= true
+ else tryAgain:= false;
+ reallySkip:= true;
+ end;
+
+if cnt2 > 0 then
+ with ar2[GetRandom(cnt2)] do
+ begin
+ Gear^.X:= int2hwFloat(x);
+ Gear^.Y:= int2hwFloat(y);
+ AddFileLog('Assigned Gear coordinates (' + inttostr(x) + ',' + inttostr(y) + ')');
+ end
+ else
+ begin
+ OutError('Can''t find place for Gear', false);
+ if Gear^.Kind = gtHedgehog then Gear^.Hedgehog^.Effects[heResurrectable] := false;
+ DeleteGear(Gear);
+ Gear:= nil
+ end
+end;
+
+function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear;
+var t: PGear;
+begin
+t:= GearsList;
+rX:= sqr(rX);
+rY:= sqr(rY);
+
+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) then
+ exit(t);
+ t:= t^.NextGear
+ end;
+
+CheckGearNear:= nil
+end;
+
+
+function CheckGearsNear(mX, mY: LongInt; Kind: TGearsType; rX, rY: LongInt): PGear;
+var t: PGear;
+begin
+t:= GearsList;
+rX:= sqr(rX);
+rY:= sqr(rY);
+while t <> nil do
+ begin
+ if t^.Kind in Kind then
+ if not (hwSqr(int2hwFloat(mX) - t^.X) / rX + hwSqr(int2hwFloat(mY) - t^.Y) / rY > _1) then
+ exit(t);
+ t:= t^.NextGear
+ end;
+CheckGearsNear:= nil
+end;
+end.
--- a/hedgewars/uScript.pas Tue Nov 29 17:42:42 2011 +0400
+++ b/hedgewars/uScript.pas Fri Dec 30 13:54:39 2011 +0400
@@ -57,7 +57,7 @@
uConsole,
uConsts,
uVisualGears,
- uGears,
+ uGearsList,
uFloat,
uWorld,
uAmmos,