diff -r 090269e528df -r da1e7fe7cff7 hedgewars/uGearsHedgehog.pas --- /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 + * + * 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.