hedgewars/HHHandlers.inc
branchhedgeroid
changeset 7855 ddcdedd3330b
parent 6350 41b0a9955c47
parent 7854 0b447175594f
child 7857 2bc61f8841a1
equal deleted inserted replaced
6350:41b0a9955c47 7855:ddcdedd3330b
     1 (*
       
     2  * Hedgewars, a free turn based strategy game
       
     3  * Copyright (c) 2004-2011 Andrey Korotaev <unC0Rr@gmail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; version 2 of the License
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
       
    17  *)
       
    18 
       
    19 ////////////////////////////////////////////////////////////////////////////////
       
    20 
       
    21 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
       
    22 begin
       
    23 if (Source = dsFall) or (Source = dsExplosion) then
       
    24     case random(3) of
       
    25         0: PlaySound(sndOoff1, Hedgehog^.Team^.voicepack);
       
    26         1: PlaySound(sndOoff2, Hedgehog^.Team^.voicepack);
       
    27         2: PlaySound(sndOoff3, Hedgehog^.Team^.voicepack);
       
    28     end
       
    29 else if (Source = dsPoison) then
       
    30     case random(2) of
       
    31         0: PlaySound(sndPoisonCough, Hedgehog^.Team^.voicepack);
       
    32         1: PlaySound(sndPoisonMoan, Hedgehog^.Team^.voicepack);
       
    33     end
       
    34 else
       
    35     case random(4) of
       
    36         0: PlaySound(sndOw1, Hedgehog^.Team^.voicepack);
       
    37         1: PlaySound(sndOw2, Hedgehog^.Team^.voicepack);
       
    38         2: PlaySound(sndOw3, Hedgehog^.Team^.voicepack);
       
    39         3: PlaySound(sndOw4, Hedgehog^.Team^.voicepack);
       
    40     end
       
    41 end;
       
    42 
       
    43 // Shouldn't more of this ammo switching stuff be moved to uAmmos ?
       
    44 function ChangeAmmo(HHGear: PGear): boolean;
       
    45 var slot, i: Longword;
       
    46     ammoidx: LongInt;
       
    47 begin
       
    48 ChangeAmmo:= false;
       
    49 slot:= HHGear^.MsgParam;
       
    50 
       
    51 with HHGear^.Hedgehog^ do
       
    52     begin
       
    53     HHGear^.Message:= HHGear^.Message and not gmSlot;
       
    54     ammoidx:= 0;
       
    55     if ((HHGear^.State and (gstAttacking or gstAttacked)) <> 0) or
       
    56        ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0)) or
       
    57        ((HHGear^.State and gstHHDriven) = 0) then exit;
       
    58     ChangeAmmo:= true;
       
    59 
       
    60     while (ammoidx < cMaxSlotAmmoIndex) and (Ammo^[slot, ammoidx].AmmoType <> CurAmmoType) do inc(ammoidx);
       
    61 
       
    62     if ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (MultiShootAttacks > 0) then OnUsedAmmo(HHGear^.Hedgehog^);
       
    63 
       
    64     MultiShootAttacks:= 0;
       
    65     HHGear^.Message:= HHGear^.Message and not (gmLJump or gmHJump);
       
    66     
       
    67     if Ammoz[CurAmmoType].Slot = slot then
       
    68         begin
       
    69         i:= 0;
       
    70         repeat
       
    71         inc(ammoidx);
       
    72         if (ammoidx > cMaxSlotAmmoIndex) then
       
    73             begin
       
    74             inc(i);
       
    75             CurAmmoType:= amNothing;
       
    76             ammoidx:= -1;
       
    77             //TryDo(i < 2, 'Engine bug: no ammo in current slot', true)
       
    78             end;
       
    79         until (i = 1) or ((Ammo^[slot, ammoidx].Count > 0) and (Team^.Clan^.TurnNumber > Ammoz[Ammo^[slot, ammoidx].AmmoType].SkipTurns))
       
    80         end 
       
    81     else
       
    82         begin
       
    83         i:= 0;
       
    84         // check whether there is ammo in slot
       
    85         while (i <= cMaxSlotAmmoIndex)
       
    86           and ((Ammo^[slot, i].Count = 0)
       
    87                or (Team^.Clan^.TurnNumber <= Ammoz[Ammo^[slot, i].AmmoType].SkipTurns)) do inc(i);
       
    88 
       
    89         if i <= cMaxSlotAmmoIndex then ammoidx:= i
       
    90         else ammoidx:= -1
       
    91         end;
       
    92         if ammoidx >= 0 then CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
       
    93     end
       
    94 end;
       
    95 
       
    96 procedure HHSetWeapon(HHGear: PGear);
       
    97 var t: LongInt;
       
    98     weap: TAmmoType;
       
    99     Hedgehog: PHedgehog;
       
   100     s: boolean;
       
   101 begin
       
   102 s:= false;
       
   103 
       
   104 weap:= TAmmoType(HHGear^.MsgParam);
       
   105 Hedgehog:= HHGear^.Hedgehog;
       
   106 
       
   107 if Hedgehog^.Team^.Clan^.TurnNumber <= Ammoz[weap].SkipTurns then exit; // weapon is not activated yet
       
   108 
       
   109 HHGear^.MsgParam:= Ammoz[weap].Slot;
       
   110 
       
   111 t:= cMaxSlotAmmoIndex;
       
   112 
       
   113 HHGear^.Message:= HHGear^.Message and not gmWeapon;
       
   114 
       
   115 with Hedgehog^ do
       
   116     while (CurAmmoType <> weap) and (t >= 0) do
       
   117         begin
       
   118         s:= ChangeAmmo(HHGear);
       
   119         dec(t)
       
   120         end;
       
   121 
       
   122 if s then ApplyAmmoChanges(HHGear^.Hedgehog^)
       
   123 end;
       
   124 
       
   125 procedure HHSetTimer(Gear: PGear);
       
   126 var CurWeapon: PAmmo;
       
   127     color: LongWord;
       
   128 begin
       
   129 Gear^.Message:= Gear^.Message and not gmTimer;
       
   130 CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^);
       
   131 with Gear^.Hedgehog^ do
       
   132     if ((Gear^.Message and gmPrecise) <> 0) and ((CurWeapon^.Propz and ammoprop_SetBounce) <> 0) then
       
   133         begin
       
   134         color:= Gear^.Hedgehog^.Team^.Clan^.Color;
       
   135         case Gear^.MsgParam of
       
   136             1: begin
       
   137                AddCaption(format(trmsg[sidBounce], trmsg[sidBounce1]), color, capgrpAmmostate);
       
   138                CurWeapon^.Bounciness:= 350;
       
   139                end;
       
   140             2: begin
       
   141                AddCaption(format(trmsg[sidBounce], trmsg[sidBounce2]), color, capgrpAmmostate);
       
   142                CurWeapon^.Bounciness:= 700;
       
   143                end;
       
   144             3: begin
       
   145                AddCaption(format(trmsg[sidBounce], trmsg[sidBounce3]), color, capgrpAmmostate);
       
   146                CurWeapon^.Bounciness:= 1000;
       
   147                end;
       
   148             4: begin
       
   149                AddCaption(format(trmsg[sidBounce], trmsg[sidBounce4]), color, capgrpAmmostate);
       
   150                CurWeapon^.Bounciness:= 2000;
       
   151                end;
       
   152             5: begin
       
   153                AddCaption(format(trmsg[sidBounce], trmsg[sidBounce5]), color, capgrpAmmostate);
       
   154                CurWeapon^.Bounciness:= 4000;
       
   155                end
       
   156             end
       
   157         end
       
   158     else if (CurWeapon^.Propz and ammoprop_Timerable) <> 0 then
       
   159         begin
       
   160         CurWeapon^.Timer:= 1000 * Gear^.MsgParam;
       
   161         with CurrentTeam^ do
       
   162             ApplyAmmoChanges(Hedgehogs[CurrHedgehog]);
       
   163         end;
       
   164 end;
       
   165 
       
   166 
       
   167 procedure Attack(Gear: PGear);
       
   168 var xx, yy, newDx, newDy, lx, ly: hwFloat;
       
   169     speech: PVisualGear;
       
   170     newGear:  PGear;
       
   171     CurWeapon: PAmmo;
       
   172     altUse: boolean;
       
   173     elastic: hwFloat;
       
   174 begin
       
   175 newGear:= nil;
       
   176 bShowFinger:= false;
       
   177 CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^);
       
   178 with Gear^,
       
   179      Gear^.Hedgehog^ do
       
   180      begin
       
   181      if ((State and gstHHDriven) <> 0)and
       
   182         ((State and (gstAttacked or gstHHChooseTarget)) = 0) and
       
   183         (((State and gstMoving) = 0) or
       
   184             (Power > 0) or
       
   185             (CurAmmoType = amTeleport) or 
       
   186             // Allow attacks while moving on ammo with AltAttack
       
   187             ((CurAmmoGear <> nil) and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)) or
       
   188             ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AttackInMove) <> 0)) and
       
   189         ((TargetPoint.X <> NoPointX) or ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) = 0)) then
       
   190         begin
       
   191         State:= State or gstAttacking;
       
   192         if Power = cMaxPower then Message:= Message and not gmAttack
       
   193         else if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) = 0 then Message:= Message and not gmAttack
       
   194         else begin
       
   195              if Power = 0 then
       
   196                 begin
       
   197                 AttackBar:= CurrentTeam^.AttackBar;
       
   198                 PlaySound(sndThrowPowerUp)
       
   199                 end;
       
   200              inc(Power)
       
   201              end;
       
   202         if ((Message and gmAttack) <> 0) then exit;
       
   203 
       
   204         if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0 then
       
   205            begin
       
   206            StopSound(sndThrowPowerUp);
       
   207            PlaySound(sndThrowRelease);
       
   208            end;
       
   209 
       
   210         xx:= SignAs(AngleSin(Angle), dX);
       
   211         yy:= -AngleCos(Angle);
       
   212 
       
   213         lx:= X + int2hwfloat(round(GetLaunchX(CurAmmoType, hwSign(dX), Angle)));
       
   214         ly:= Y + int2hwfloat(round(GetLaunchY(CurAmmoType, Angle)));
       
   215 
       
   216         if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then xx:= - xx;
       
   217         if Ammoz[CurAmmoType].Ammo.AttackVoice <> sndNone then
       
   218            AddVoice(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
       
   219 
       
   220 // Initiating alt attack
       
   221         if  (CurAmmoGear <> nil) and
       
   222             ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) and
       
   223             ((Gear^.Message and gmLJump) <> 0) and
       
   224             ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
       
   225             begin
       
   226             newDx:= dX / _2; 
       
   227             newDy:= dY / _2;
       
   228             altUse:= true;
       
   229             end
       
   230         else
       
   231             begin
       
   232             newDx:= xx*Power/cPowerDivisor;
       
   233             newDy:= yy*Power/cPowerDivisor;
       
   234             altUse:= false
       
   235             end;
       
   236 
       
   237              case CurAmmoType of
       
   238                       amGrenade: newGear:= AddGear(hwRound(lx), hwRound(ly), gtGrenade,         0, newDx, newDy, CurWeapon^.Timer);
       
   239                       amMolotov: newGear:= AddGear(hwRound(lx), hwRound(ly), gtMolotov,      0, newDx, newDy, 0);
       
   240                   amClusterBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtClusterBomb,  0, newDx, newDy, CurWeapon^.Timer);
       
   241                       amGasBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtGasBomb,      0, newDx, newDy, CurWeapon^.Timer);
       
   242                       amBazooka: newGear:= AddGear(hwRound(lx), hwRound(ly), gtShell,        0, newDx, newDy, 0);
       
   243                      amSnowball: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSnowball,     0, newDx, newDy, 0);
       
   244                           amBee: newGear:= AddGear(hwRound(lx), hwRound(ly), gtBee,          0, newDx, newDy, 0);
       
   245                       amShotgun: begin
       
   246                                  PlaySound(sndShotgunReload);
       
   247                                  newGear:= AddGear(hwRound(lx), hwRound(ly), gtShotgunShot,  0, xx * _0_5, yy * _0_5, 0);
       
   248                                  end;
       
   249                    amPickHammer: newGear:= AddGear(hwRound(lx), hwRound(ly) + cHHRadius, gtPickHammer, 0, _0, _0, 0);
       
   250                          amSkip: ParseCommand('/skip', true);
       
   251                          amRope: newGear:= AddGear(hwRound(lx), hwRound(ly), gtRope, 0, xx, yy, 0);
       
   252                          amMine: if altUse then
       
   253                                     newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtMine, gstWait, newDx, newDy, 3000)
       
   254                                  else
       
   255                                     newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtMine, gstWait, SignAs(_0_02, dX), _0, 3000);
       
   256                         amSMine: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSMine,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
       
   257                        amDEagle: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtDEagleShot, 0, xx * _0_5, yy * _0_5, 0);
       
   258                       amSineGun: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSineGunShot, 0, xx * _0_5, yy * _0_5, 0);
       
   259                     amPortalGun: begin
       
   260                                  newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtPortal, 0, xx * _0_6, yy * _0_6, 
       
   261                                  // set selected color
       
   262                                  CurWeapon^.Pos);
       
   263                                  end;
       
   264                   amSniperRifle: begin
       
   265                                  PlaySound(sndSniperReload);
       
   266                                  newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSniperRifleShot, 0, xx * _0_5, yy * _0_5, 0);
       
   267                                  end;
       
   268                      amDynamite: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtDynamite, 0, SignAs(_0_03, dX), _0, 5000);
       
   269                     amFirePunch: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtFirePunch, 0, xx, _0, 0);
       
   270                          amWhip: begin
       
   271                                  newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtWhip, 0, SignAs(_1, dX), - _0_8, 0);
       
   272                                  PlaySound(sndWhipCrack)
       
   273                                  end;
       
   274                        amHammer: begin
       
   275                                  newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtHammer, 0, SignAs(_1, dX), - _0_8, 0);
       
   276                                  PlaySound(sndWhack)
       
   277                                  end;
       
   278                   amBaseballBat: begin
       
   279                                  newGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtShover, gsttmpFlag, xx * _0_5, yy * _0_5, 0);
       
   280                                  PlaySound(sndBaseballBat) // TODO: Only play if something is hit?
       
   281                                  end;
       
   282                     amParachute: begin
       
   283                                  newGear:= AddGear(hwRound(lx), hwRound(ly), gtParachute, 0, _0, _0, 0);
       
   284                                  PlaySound(sndParachute)
       
   285                                  end;
       
   286                     // we save CurWeapon^.Pos (in this case: cursor direction) by using it as (otherwise irrelevant) X value of the new gear.
       
   287                     amAirAttack: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 0, _0, _0, 0);
       
   288                    amMineStrike: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 1, _0, _0, 0);
       
   289                   amDrillStrike: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 3, _0, _0, CurWeapon^.Timer);
       
   290                        amNapalm: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 2, _0, _0, 0);
       
   291                     amBlowTorch: newGear:= AddGear(hwRound(lx), hwRound(ly), gtBlowTorch, 0, SignAs(_0_5, dX), _0, 0);
       
   292                        amGirder: newGear:= AddGear(0, 0, gtGirder, CurWeapon^.Pos, _0, _0, 0);
       
   293                      amTeleport: newGear:= AddGear(CurWeapon^.Pos, 0, gtTeleport, 0, _0, _0, 0);
       
   294                        amSwitch: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSwitcher, 0, _0, _0, 0);
       
   295                        amMortar: begin
       
   296                                  playSound(sndMortar);
       
   297                                  newGear:= AddGear(hwRound(lx), hwRound(ly), gtMortar,  0, xx*cMaxPower/cPowerDivisor, yy*cMaxPower/cPowerDivisor, 0);
       
   298                                  end;
       
   299                       amRCPlane: begin
       
   300                                  newGear:= AddGear(hwRound(lx), hwRound(ly), gtRCPlane,  0, xx * cMaxPower / cPowerDivisor / 4, yy * cMaxPower / cPowerDivisor / 4, 0);
       
   301                                  newGear^.SoundChannel:= LoopSound(sndRCPlane, nil)
       
   302                                  end;
       
   303                        amKamikaze: newGear:= AddGear(hwRound(lx), hwRound(ly), gtKamikaze, 0, xx * _0_5, yy * _0_5, 0);
       
   304                          amCake: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 3, hwRound(ly), gtCake, 0, xx, _0, 0);
       
   305                     amSeduction: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSeduction, 0, _0, _0, 0);
       
   306                    amWatermelon: newGear:= AddGear(hwRound(lx), hwRound(ly), gtWatermelon,  0, newDx, newDy, CurWeapon^.Timer);
       
   307                   amHellishBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtHellishBomb,    0, newDx, newDy, 0);
       
   308                         amDrill: newGear:= AddGear(hwRound(lx), hwRound(ly), gtDrill, 0, newDx, newDy, 0);
       
   309                       amBallgun: newGear:= AddGear(hwRound(X), hwRound(Y), gtBallgun,  0, xx * _0_5, yy * _0_5, 0);
       
   310                     amJetpack: newGear:= AddGear(hwRound(lx), hwRound(ly), gtJetpack, 0, _0, _0, 0);
       
   311                     amBirdy: begin
       
   312                              PlaySound(sndWhistle);
       
   313                              newGear:= AddGear(hwRound(lx), hwRound(ly) - 32, gtBirdy, 0, _0, _0, 0);
       
   314                              end;
       
   315                       amLowGravity: begin
       
   316                                     PlaySound(sndLowGravity);
       
   317                                     cGravity:= cMaxWindSpeed;
       
   318                                     cGravityf:= 0.00025
       
   319                                     end;
       
   320                       amExtraDamage:begin 
       
   321                                     PlaySound(sndHellishImpact4);
       
   322                                     cDamageModifier:= _1_5
       
   323                                     end;
       
   324                       amInvulnerable: Invulnerable:= true;
       
   325                       amExtraTime:  begin
       
   326                                     PlaySound(sndSwitchHog);
       
   327                                     TurnTimeLeft:= TurnTimeLeft + 30000
       
   328                                     end;
       
   329                       amLaserSight: cLaserSighting:= true;
       
   330                       amVampiric: begin
       
   331                                   PlaySound(sndOw1, Team^.voicepack);
       
   332                                   cVampiric:= true;
       
   333                                   end;
       
   334                       amPiano: begin
       
   335                                // Tuck the hedgehog away until the piano attack is completed
       
   336                                Unplaced:= true;
       
   337                                X:= _0;
       
   338                                Y:= _0;
       
   339                                newGear:= AddGear(TargetPoint.X, 0, gtPiano, 0, _0, _0, 0);
       
   340                                PauseMusic
       
   341                                end;
       
   342                       amFlamethrower: newGear:= AddGear(hwRound(X), hwRound(Y), gtFlamethrower,  0, xx * _0_5, yy * _0_5, 0);
       
   343                       amLandGun: newGear:= AddGear(hwRound(X), hwRound(Y), gtLandGun,  0, xx * _0_5, yy * _0_5, 0);
       
   344                     amResurrector: begin
       
   345                         newGear:= AddGear(hwRound(lx), hwRound(ly),
       
   346                                 gtResurrector, 0, _0, _0, 0);
       
   347                         newGear^.SoundChannel := LoopSound(sndResurrector);
       
   348                     end;
       
   349                    //amMelonStrike: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 4, _0, _0, 0);
       
   350                      amStructure: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtStructure, gstWait, SignAs(_0_02, dX), _0, 3000);
       
   351                         amTardis: newGear:= AddGear(hwRound(X), hwRound(Y), gtTardis, 0, _0, _0, 5000);
       
   352                   end;
       
   353              case CurAmmoType of
       
   354                       amGrenade, amMolotov, 
       
   355                   amClusterBomb, amGasBomb, 
       
   356                       amBazooka, amSnowball, 
       
   357                           amBee, amSMine,
       
   358                        amMortar, amWatermelon,
       
   359                   amHellishBomb, amDrill: FollowGear:= newGear;
       
   360 
       
   361                       amShotgun, amPickHammer,
       
   362                          amRope, amDEagle,
       
   363                       amSineGun, amSniperRifle,
       
   364                     amFirePunch, amWhip,
       
   365                        amHammer, amBaseballBat,
       
   366                     amParachute, amBlowTorch,
       
   367                        amGirder, amTeleport,
       
   368                        amSwitch, amRCPlane,
       
   369                      amKamikaze, amCake,
       
   370                     amSeduction, amBallgun,
       
   371                       amJetpack, amBirdy,
       
   372                  amFlamethrower, amLandGun,
       
   373                   amResurrector, amStructure,
       
   374                        amTardis, amPiano: CurAmmoGear:= newGear;
       
   375                   end;
       
   376               if (CurAmmoType = amMine) or (CurAmmoType = amSMine) and (GameFlags and gfInfAttack <> 0) then newGear^.FlightTime:= GameTicks + 1000;
       
   377         if Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then
       
   378             begin
       
   379             newGear^.Target.X:= TargetPoint.X;
       
   380             newGear^.Target.Y:= TargetPoint.Y
       
   381             end;
       
   382 
       
   383         // Clear FollowGear if using on a rope/parachute/saucer etc so focus stays with the hog's movement
       
   384         if altUse then FollowGear:= nil;
       
   385 
       
   386         if (newGear <> nil) and ((Ammoz[newGear^.AmmoType].Ammo.Propz and ammoprop_SetBounce) <> 0) then
       
   387             begin
       
   388             elastic:=  int2hwfloat(CurWeapon^.Bounciness) / _1000;
       
   389 
       
   390             if elastic < _1 then newGear^.Elasticity:= newGear^.Elasticity * elastic
       
   391             else if elastic > _1 then newGear^.Elasticity:= _1 - ((_1-newGear^.Elasticity) / elastic);
       
   392 (* Experimented with friction modifier. Didn't seem helpful 
       
   393             fric:= int2hwfloat(CurWeapon^.Bounciness) / _250;
       
   394             if fric < _1 then newGear^.Friction:= newGear^.Friction * fric
       
   395             else if fric > _1 then newGear^.Friction:= _1 - ((_1-newGear^.Friction) / fric)*)
       
   396             end;
       
   397 
       
   398 
       
   399         uStats.AmmoUsed(CurAmmoType);
       
   400 
       
   401         if not (SpeechText = '') then
       
   402             begin
       
   403             speech:= AddVisualGear(0, 0, vgtSpeechBubble);
       
   404             if speech <> nil then
       
   405                begin
       
   406                speech^.Text:= SpeechText;
       
   407                speech^.Hedgehog:= Gear^.Hedgehog;
       
   408                speech^.FrameTicks:= SpeechType;
       
   409                end;
       
   410             SpeechText:= ''
       
   411             end;
       
   412 
       
   413         Power:= 0;
       
   414         if (CurAmmoGear <> nil)
       
   415            and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) = 0){check for dropping ammo from rope} then
       
   416            begin
       
   417            Message:= Message or gmAttack;
       
   418            CurAmmoGear^.Message:= Message
       
   419            end else begin
       
   420            if not CurrentTeam^.ExtDriven and
       
   421              ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0) then SendIPC('a');
       
   422            AfterAttack;
       
   423            end
       
   424         end else Message:= Message and not gmAttack;
       
   425      end;
       
   426      TargetPoint.X := NoPointX;
       
   427      ScriptCall('onHogAttack');	
       
   428 end;
       
   429 
       
   430 procedure AfterAttack;
       
   431 var s: shortstring;
       
   432     a: TAmmoType;
       
   433 begin
       
   434 with CurrentHedgehog^.Gear^,
       
   435         CurrentHedgehog^ do
       
   436     begin
       
   437     a:= CurAmmoType;
       
   438     State:= State and not gstAttacking;
       
   439     if (Ammoz[a].Ammo.Propz and ammoprop_Effect) = 0 then
       
   440         begin
       
   441         Inc(MultiShootAttacks);
       
   442         
       
   443         if (Ammoz[a].Ammo.NumPerTurn >= MultiShootAttacks) then
       
   444             begin
       
   445             s:= inttostr(Ammoz[a].Ammo.NumPerTurn - MultiShootAttacks + 1);
       
   446             AddCaption(format(trmsg[sidRemaining], s), cWhiteColor, capgrpAmmostate);
       
   447             end;
       
   448         
       
   449         if (Ammoz[a].Ammo.NumPerTurn >= MultiShootAttacks) or
       
   450             ((GameFlags and gfMultiWeapon) <> 0) then
       
   451             begin
       
   452             isInMultiShoot:= true
       
   453             end
       
   454         else
       
   455             begin
       
   456             OnUsedAmmo(CurrentHedgehog^);
       
   457             if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) = 0) and (((GameFlags and gfInfAttack) = 0) or PlacingHogs) then
       
   458                 begin
       
   459                 if TagTurnTimeLeft = 0 then TagTurnTimeLeft:= TurnTimeLeft;
       
   460                 TurnTimeLeft:=(Ammoz[a].TimeAfterTurn * cGetAwayTime) div 100;
       
   461                 end;
       
   462             if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) = 0) then State:= State or gstAttacked;
       
   463             if (Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) <> 0 then ApplyAmmoChanges(CurrentHedgehog^)
       
   464             end;
       
   465         end
       
   466     else
       
   467         begin
       
   468         OnUsedAmmo(CurrentHedgehog^);
       
   469         ApplyAmmoChanges(CurrentHedgehog^);
       
   470         end;
       
   471     AttackBar:= 0
       
   472     end
       
   473 end;
       
   474 
       
   475 ////////////////////////////////////////////////////////////////////////////////
       
   476 procedure doStepHedgehogDead(Gear: PGear);
       
   477 const frametime = 200;
       
   478       timertime = frametime * 6;
       
   479 begin
       
   480 if Gear^.Hedgehog^.Unplaced then exit;
       
   481 if Gear^.Timer > 1 then
       
   482     begin
       
   483     AllInactive:= false;
       
   484     dec(Gear^.Timer);
       
   485     if (Gear^.Timer mod frametime) = 0 then inc(Gear^.Pos)
       
   486     end 
       
   487 else if Gear^.Timer = 1 then
       
   488     begin
       
   489     Gear^.State:= Gear^.State or gstNoDamage;
       
   490     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, CurrentHedgehog, EXPLAutoSound);
       
   491     AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtGrave, 0, _0, _0, 0)^.Hedgehog:= Gear^.Hedgehog;
       
   492     DeleteGear(Gear);
       
   493     SetAllToActive
       
   494     end 
       
   495 else // Gear^.Timer = 0
       
   496     begin
       
   497     AllInactive:= false;
       
   498     Gear^.Z:= cCurrHHZ;
       
   499     RemoveGearFromList(Gear);
       
   500     InsertGearToList(Gear);
       
   501     PlaySound(sndByeBye, Gear^.Hedgehog^.Team^.voicepack);
       
   502     Gear^.Pos:= 0;
       
   503     Gear^.Timer:= timertime
       
   504     end
       
   505 end;
       
   506 
       
   507 ////////////////////////////////////////////////////////////////////////////////
       
   508 procedure doStepHedgehogGone(Gear: PGear);
       
   509 const frametime = 65;
       
   510       timertime = frametime * 11;
       
   511 begin
       
   512 if Gear^.Hedgehog^.Unplaced then exit;
       
   513 if Gear^.Timer > 1 then
       
   514     begin
       
   515     AllInactive:= false;
       
   516     dec(Gear^.Timer);
       
   517     if (Gear^.Timer mod frametime) = 0 then inc(Gear^.Pos)
       
   518     end else
       
   519 if Gear^.Timer = 1 then
       
   520     begin
       
   521     DeleteGear(Gear);
       
   522     SetAllToActive
       
   523     end else // Gear^.Timer = 0
       
   524     begin
       
   525     AllInactive:= false;
       
   526     Gear^.Z:= cCurrHHZ;
       
   527     RemoveGearFromList(Gear);
       
   528     InsertGearToList(Gear);
       
   529     PlaySound(sndByeBye, Gear^.Hedgehog^.Team^.voicepack);
       
   530     PlaySound(sndWarp);
       
   531     Gear^.Pos:= 0;
       
   532     Gear^.Timer:= timertime
       
   533     end
       
   534 end;
       
   535 
       
   536 ////////////////////////////////////////////////////////////////////////////////
       
   537 procedure PickUp(HH, Gear: PGear);
       
   538 var s: shortstring;
       
   539     a: TAmmoType;
       
   540     i: LongInt;
       
   541     vga: PVisualGear;
       
   542 begin
       
   543 Gear^.Message:= gmDestroy;
       
   544 PlaySound(sndShotgunReload);
       
   545 if (Gear^.Pos and posCaseExplode) <> 0 then
       
   546     if (Gear^.Pos and posCasePoison) <> 0 then
       
   547         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound + EXPLPoisoned)
       
   548     else
       
   549         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound)
       
   550 else if (Gear^.Pos and posCasePoison) <> 0 then
       
   551     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound + EXPLPoisoned + EXPLNoDamage)
       
   552 else
       
   553 case Gear^.Pos of
       
   554        posCaseUtility,
       
   555        posCaseAmmo: begin
       
   556                     if Gear^.AmmoType <> amNothing then a:= Gear^.AmmoType 
       
   557                     else
       
   558                         begin
       
   559                         for i:= 0 to GameTicks and $7F do GetRandom(2); // Burn some random numbers
       
   560                         if Gear^.Pos = posCaseUtility then a:= GetUtility
       
   561                         else a:= GetAmmo
       
   562                         end;
       
   563                     AddAmmo(HH^.Hedgehog^, a);
       
   564 // Possibly needs to check shared clan ammo game flag once added.
       
   565 // On the other hand, no obvious reason that clan members shouldn't know what ammo another clan member picked up
       
   566                     if (not (HH^.Hedgehog^.Team^.ExtDriven 
       
   567                       or (HH^.Hedgehog^.BotLevel > 0)))
       
   568                       or (HH^.Hedgehog^.Team^.Clan^.ClanIndex = LocalClan)
       
   569                       or (GameType = gmtDemo)  then
       
   570                         begin
       
   571                         s:= trammo[Ammoz[a].NameId] + ' (+' + IntToStr(Ammoz[a].NumberInCase) + ')';
       
   572                         AddCaption(s, HH^.Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo);
       
   573 
       
   574                         // show ammo icon
       
   575                         vga:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtAmmo);
       
   576                         if vga <> nil then
       
   577                             vga^.Frame:= Longword(a);
       
   578                         end;
       
   579 
       
   580                     end;
       
   581      posCaseHealth: begin
       
   582                     inc(HH^.Health, Gear^.Health);
       
   583                     HH^.Hedgehog^.Effects[hePoisoned] := false;
       
   584                     str(Gear^.Health, s);
       
   585                     s:= '+' + s;
       
   586                     AddCaption(s, HH^.Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo);
       
   587                     RenderHealth(HH^.Hedgehog^);
       
   588                     RecountTeamHealth(HH^.Hedgehog^.Team);
       
   589 
       
   590                     i:= 0;
       
   591                     while i < Gear^.Health do
       
   592                         begin
       
   593                         vga:= AddVisualGear(hwRound(HH^.X), hwRound(HH^.Y), vgtStraightShot);
       
   594                         if vga <> nil then
       
   595                             with vga^ do
       
   596                                 begin
       
   597                                 Tint:= $00FF00FF;
       
   598                                 State:= ord(sprHealth)
       
   599                                 end;
       
   600                         inc(i, 5);
       
   601                         end;
       
   602                     end;
       
   603      end
       
   604 end;
       
   605 
       
   606 const StepTicks: LongWord = 0;
       
   607 
       
   608 procedure HedgehogStep(Gear: PGear);
       
   609 var PrevdX: LongInt;
       
   610     CurWeapon: PAmmo;
       
   611 begin
       
   612 CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^);
       
   613 if ((Gear^.State and (gstAttacking or gstMoving)) = 0) then
       
   614    begin
       
   615    if isCursorVisible then
       
   616       with Gear^.Hedgehog^ do
       
   617         with CurWeapon^ do
       
   618           begin
       
   619           if (Gear^.Message and gmLeft  ) <> 0 then
       
   620              Pos:= (Pos - 1 + Ammoz[AmmoType].PosCount) mod Ammoz[AmmoType].PosCount
       
   621           else
       
   622           if (Gear^.Message and gmRight ) <> 0 then
       
   623              Pos:= (Pos + 1) mod Ammoz[AmmoType].PosCount
       
   624           else exit;
       
   625           StepTicks:= 200;
       
   626           exit
       
   627           end;
       
   628 
       
   629     if ((Gear^.Message and gmAnimate) <> 0) then
       
   630         begin
       
   631         Gear^.Message:= 0;
       
   632         Gear^.State:= Gear^.State or gstAnimation;
       
   633         Gear^.Tag:= Gear^.MsgParam;
       
   634         Gear^.Timer:= 0;
       
   635         Gear^.Pos:= 0
       
   636         end;
       
   637 
       
   638    if ((Gear^.Message and gmLJump ) <> 0) then
       
   639       begin
       
   640       Gear^.Message:= Gear^.Message and not gmLJump;
       
   641       DeleteCI(Gear);
       
   642       if TestCollisionYwithGear(Gear, -1) = 0 then
       
   643          if not TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) then Gear^.Y:= Gear^.Y - _2 else
       
   644          if not TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) then Gear^.Y:= Gear^.Y - _1;
       
   645       if not (TestCollisionXwithGear(Gear, hwSign(Gear^.dX))
       
   646          or   (TestCollisionYwithGear(Gear, -1) <> 0)) then
       
   647          begin
       
   648          Gear^.dY:= -_0_15;
       
   649          if not cArtillery then Gear^.dX:= SignAs(_0_15, Gear^.dX);
       
   650          Gear^.State:= Gear^.State or gstMoving or gstHHJumping;
       
   651          PlaySound(sndJump1, Gear^.Hedgehog^.Team^.voicepack);
       
   652          exit
       
   653          end;
       
   654       end;
       
   655 
       
   656    if ((Gear^.Message and gmHJump ) <> 0) then
       
   657       begin
       
   658       DeleteCI(Gear);
       
   659       Gear^.Message:= Gear^.Message and not gmHJump;
       
   660 
       
   661       Gear^.dY:= -_0_2;
       
   662       SetLittle(Gear^.dX);
       
   663       Gear^.State:= Gear^.State or gstMoving or gstHHJumping;
       
   664       PlaySound(sndJump3, Gear^.Hedgehog^.Team^.voicepack);
       
   665       exit
       
   666       end;
       
   667 
       
   668    PrevdX:= hwSign(Gear^.dX);
       
   669    if (Gear^.Message and gmLeft  )<>0 then Gear^.dX:= -cLittle else
       
   670    if (Gear^.Message and gmRight )<>0 then Gear^.dX:=  cLittle else exit;
       
   671 
       
   672    if (Gear^.Message and (gmLeft or gmRight)) <> 0 then
       
   673       begin
       
   674       StepSoundTimer:= cHHStepTicks;
       
   675       end;
       
   676    
       
   677    StepTicks:= cHHStepTicks;
       
   678    if PrevdX <> hwSign(Gear^.dX) then
       
   679       begin
       
   680       FollowGear:= Gear;
       
   681       exit
       
   682       end;
       
   683    DeleteCI(Gear); // must be after exit!! (see previous line)
       
   684 
       
   685    Gear^.Hedgehog^.visStepPos:= (Gear^.Hedgehog^.visStepPos + 1) and 7;
       
   686    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
       
   687       begin
       
   688       if not (TestCollisionXwithXYShift(Gear, _0, -6, hwSign(Gear^.dX))
       
   689          or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
       
   690       if not (TestCollisionXwithXYShift(Gear, _0, -5, hwSign(Gear^.dX))
       
   691          or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
       
   692       if not (TestCollisionXwithXYShift(Gear, _0, -4, hwSign(Gear^.dX))
       
   693          or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
       
   694       if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))
       
   695          or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
       
   696       if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX))
       
   697          or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
       
   698       if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX))
       
   699          or (TestCollisionYwithGear(Gear, -1) <> 0)) then Gear^.Y:= Gear^.Y - _1;
       
   700       end;
       
   701 
       
   702    if (not cArtillery) and ((Gear^.Message and gmPrecise) = 0) and (not TestCollisionXwithGear(Gear, hwSign(Gear^.dX))) then
       
   703       Gear^.X:= Gear^.X + SignAs(_1, Gear^.dX);
       
   704 
       
   705    SetAllHHToActive;
       
   706 
       
   707    if TestCollisionYwithGear(Gear, 1) = 0 then
       
   708    begin
       
   709    Gear^.Y:= Gear^.Y + _1;
       
   710    if TestCollisionYwithGear(Gear, 1) = 0 then
       
   711    begin
       
   712    Gear^.Y:= Gear^.Y + _1;
       
   713    if TestCollisionYwithGear(Gear, 1) = 0 then
       
   714    begin
       
   715    Gear^.Y:= Gear^.Y + _1;
       
   716    if TestCollisionYwithGear(Gear, 1) = 0 then
       
   717    begin
       
   718    Gear^.Y:= Gear^.Y + _1;
       
   719    if TestCollisionYwithGear(Gear, 1) = 0 then
       
   720    begin
       
   721    Gear^.Y:= Gear^.Y + _1;
       
   722    if TestCollisionYwithGear(Gear, 1) = 0 then
       
   723    begin
       
   724    Gear^.Y:= Gear^.Y + _1;
       
   725    if TestCollisionYwithGear(Gear, 1) = 0 then
       
   726       begin
       
   727       Gear^.Y:= Gear^.Y - _6;
       
   728       Gear^.dY:= _0;
       
   729       Gear^.State:= Gear^.State or gstMoving;
       
   730       exit
       
   731       end;
       
   732    end
       
   733    end
       
   734    end
       
   735    end
       
   736    end
       
   737    end;
       
   738    AddGearCI(Gear)
       
   739    end
       
   740 end;
       
   741 
       
   742 procedure HedgehogChAngle(HHGear: PGear);
       
   743 var da: LongWord;
       
   744 begin
       
   745 with HHGear^.Hedgehog^ do
       
   746     if ((CurAmmoType = amRope) and 
       
   747         ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving)) or
       
   748        ((CurAmmoType = amPortalGun) and 
       
   749         ((HHGear^.State and gstMoving) <> 0)) then da:= 2
       
   750     else da:= 1;
       
   751 
       
   752 if (((HHGear^.Message and gmPrecise) = 0) or ((GameTicks mod 5) = 1)) then
       
   753     if ((HHGear^.Message and gmUp) <> 0) and (HHGear^.Angle >= CurMinAngle + da) then dec(HHGear^.Angle, da)
       
   754     else
       
   755     if ((HHGear^.Message and gmDown) <> 0) and (HHGear^.Angle + da <= CurMaxAngle) then inc(HHGear^.Angle, da)
       
   756 end;
       
   757 
       
   758 procedure doStepHedgehog(Gear: PGear); forward;
       
   759 ////////////////////////////////////////////////////////////////////////////////
       
   760 procedure doStepHedgehogMoving(Gear: PGear);
       
   761 var isFalling, isUnderwater: boolean;
       
   762     land: Word;
       
   763 begin
       
   764 land:= 0;
       
   765 isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
       
   766 if Gear^.dX.QWordValue > 8160437862 then Gear^.dX.QWordValue:= 8160437862;
       
   767 if Gear^.dY.QWordValue > 8160437862 then Gear^.dY.QWordValue:= 8160437862;
       
   768 
       
   769 if Gear^.Hedgehog^.Unplaced then
       
   770    begin
       
   771    Gear^.dY:= _0;
       
   772    Gear^.dX:= _0;
       
   773    Gear^.State:= Gear^.State and not gstMoving;
       
   774    while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
       
   775    exit
       
   776    end;
       
   777 isFalling:= (Gear^.dY.isNegative) or not TestCollisionYKick(Gear, 1);
       
   778 if isFalling then
       
   779    begin
       
   780    if (Gear^.dY.isNegative) and TestCollisionYKick(Gear, -1) then Gear^.dY:= _0;
       
   781    Gear^.State:= Gear^.State or gstMoving;
       
   782    if (CurrentHedgehog^.Gear = Gear)
       
   783         and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then 
       
   784         begin
       
   785         FollowGear:= Gear;
       
   786         end;
       
   787    if isUnderwater then Gear^.dY:= Gear^.dY + cGravity / _2
       
   788    else
       
   789        begin
       
   790        Gear^.dY:= Gear^.dY + cGravity;
       
   791 // this set of circumstances could be less complex if jumping was more clearly identified
       
   792        if ((GameFlags and gfMoreWind) <> 0) and 
       
   793           (((Gear^.Damage <> 0) or
       
   794           ((CurAmmoGear <> nil) and
       
   795             ((CurAmmoGear^.AmmoType = amJetpack) or
       
   796             (CurAmmoGear^.AmmoType = amBirdy))) or
       
   797           ((Gear^.dY.QWordValue + Gear^.dX.QWordValue) > _0_55.QWordValue)))
       
   798           then Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
       
   799        end
       
   800    end 
       
   801 else
       
   802    begin
       
   803    land:= TestCollisionYwithGear(Gear, 1);
       
   804    if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_55.QWordValue) and ((land and lfIce) = 0)
       
   805       and ((Gear^.State and gstHHJumping) <> 0) then SetLittle(Gear^.dX);
       
   806 
       
   807    if not Gear^.dY.isNegative then
       
   808       begin
       
   809       CheckHHDamage(Gear);
       
   810 
       
   811       if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) and
       
   812          (Gear^.dX.QWordValue < _0_02.QWordValue) then Gear^.dX.isNegative:= not Gear^.dX.isNegative; // landing after high jump
       
   813 
       
   814       Gear^.State:= Gear^.State and not (gstHHJumping or gstHHHJump);
       
   815       Gear^.dY:= _0;
       
   816       end else Gear^.dY:= Gear^.dY + cGravity;
       
   817 
       
   818    if ((Gear^.State and gstMoving) <> 0) then
       
   819        begin
       
   820        if land and lfIce <> 0 then
       
   821            begin
       
   822            Gear^.dX:= Gear^.dX * (_1 - (_1 - Gear^.Friction) / _2)
       
   823            end
       
   824        else Gear^.dX:= Gear^.dX * Gear^.Friction;
       
   825        end
       
   826    end;
       
   827 
       
   828 if (Gear^.State <> 0) then DeleteCI(Gear);
       
   829 
       
   830 if isUnderwater then
       
   831    begin
       
   832    Gear^.dY:= Gear^.dY * _0_999;
       
   833    Gear^.dX:= Gear^.dX * _0_999;
       
   834    end;
       
   835 
       
   836 if (Gear^.State and gstMoving) <> 0 then
       
   837    if TestCollisionXKick(Gear, hwSign(Gear^.dX)) then
       
   838       if not isFalling then
       
   839          if hwAbs(Gear^.dX) > _0_01 then
       
   840             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
       
   841             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
       
   842             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
       
   843             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
       
   844             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
       
   845             if hwAbs(Gear^.dX) > _0_02 then Gear^.dX:= -Gear^.Elasticity * Gear^.dX
       
   846                                    else begin
       
   847                                         Gear^.State:= Gear^.State and not gstMoving;
       
   848                                         while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
       
   849                                         SetLittle(Gear^.dX)
       
   850                                         end
       
   851             else begin
       
   852                  Gear^.State:= Gear^.State and not gstMoving;
       
   853                  while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
       
   854                  SetLittle(Gear^.dX)
       
   855                  end
       
   856          else if (hwAbs(Gear^.dX) > cLittle)
       
   857                 and ((Gear^.State and gstHHJumping) = 0)
       
   858                 then Gear^.dX:= -Gear^.Elasticity * Gear^.dX
       
   859                 else SetLittle(Gear^.dX);
       
   860 
       
   861 if (not isFalling) and
       
   862    (hwAbs(Gear^.dX) + hwAbs(Gear^.dY) < _0_03) then
       
   863    begin
       
   864    Gear^.State:= Gear^.State and not gstWinner;
       
   865    Gear^.State:= Gear^.State and not gstMoving;
       
   866    while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
       
   867    SetLittle(Gear^.dX);
       
   868    Gear^.dY:= _0
       
   869    end else Gear^.State:= Gear^.State or gstMoving;
       
   870 
       
   871 if (Gear^.State and gstMoving) <> 0 then
       
   872    begin
       
   873    Gear^.State:= Gear^.State and not gstAnimation;
       
   874 // ARTILLERY but not being moved by explosions
       
   875    Gear^.X:= Gear^.X + Gear^.dX;
       
   876    Gear^.Y:= Gear^.Y + Gear^.dY;
       
   877    if (not Gear^.dY.isNegative) and
       
   878       (not TestCollisionYKick(Gear, 1)) and
       
   879        TestCollisionYwithXYShift(Gear, 0, 1, 1) then
       
   880       begin
       
   881       CheckHHDamage(Gear);
       
   882       Gear^.dY:= _0;
       
   883       Gear^.Y:= Gear^.Y + _1
       
   884       end;
       
   885    CheckGearDrowning(Gear);
       
   886    // hide target cursor if current hog is drowning
       
   887    if (Gear^.State and gstDrowning) <> 0 then
       
   888        if (CurrentHedgehog^.Gear = Gear) then
       
   889           isCursorVisible:= false
       
   890    end;
       
   891 
       
   892 if (hwAbs(Gear^.dY) > _0) and (Gear^.FlightTime > 0) and ((GameFlags and gfLowGravity) = 0) then
       
   893     begin
       
   894     inc(Gear^.FlightTime);
       
   895     if Gear^.FlightTime = 3000 then
       
   896         begin
       
   897         AddCaption(GetEventString(eidHomerun), cWhiteColor, capgrpMessage);
       
   898         PlaySound(sndHomerun)
       
   899         end;
       
   900     end
       
   901 else
       
   902     begin
       
   903     uStats.hedgehogFlight(Gear, Gear^.FlightTime);
       
   904     Gear^.FlightTime:= 0;
       
   905     end;
       
   906 
       
   907 end;
       
   908 
       
   909 procedure doStepHedgehogDriven(HHGear: PGear);
       
   910 var t: PGear;
       
   911     wasJumping: boolean;
       
   912     Hedgehog: PHedgehog;
       
   913 begin
       
   914 Hedgehog:= HHGear^.Hedgehog;
       
   915 if isInMultiShoot then
       
   916    HHGear^.Message:= 0;
       
   917 
       
   918 if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_Utility) <> 0) and isInMultiShoot then 
       
   919     AllInactive:= true
       
   920 else if not isInMultiShoot then AllInactive:= false;
       
   921 
       
   922 if (TurnTimeLeft = 0) or (HHGear^.Damage > 0) then
       
   923     begin
       
   924     if TagTurnTimeLeft = 0 then TagTurnTimeLeft:= TurnTimeLeft;
       
   925     TurnTimeLeft:= 0;
       
   926     isCursorVisible:= false;
       
   927     HHGear^.State:= HHGear^.State and not (gstHHDriven or gstAnimation or gstAttacking);
       
   928     AttackBar:= 0;
       
   929     if HHGear^.Damage > 0 then
       
   930         HHGear^.State:= HHGear^.State and not (gstHHJumping or gstHHHJump);
       
   931     exit
       
   932     end;
       
   933 
       
   934 if (HHGear^.State and gstAnimation) <> 0 then
       
   935     begin
       
   936     HHGear^.Message:= 0;
       
   937     if (HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].VoiceDelay) and (HHGear^.Timer = 0) then PlaySound(Wavez[TWave(HHGear^.Tag)].Voice, Hedgehog^.Team^.voicepack);
       
   938     inc(HHGear^.Timer);
       
   939     if HHGear^.Timer = Wavez[TWave(HHGear^.Tag)].Interval then
       
   940         begin
       
   941         HHGear^.Timer:= 0;
       
   942         inc(HHGear^.Pos);
       
   943         if HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].FramesCount then
       
   944             HHGear^.State:= HHGear^.State and not gstAnimation
       
   945         end;
       
   946     exit
       
   947     end;
       
   948 
       
   949 if ((HHGear^.State and gstMoving) <> 0)
       
   950     or (StepTicks = cHHStepTicks)
       
   951     or (CurAmmoGear <> nil) then // we are moving
       
   952     begin
       
   953     with Hedgehog^ do
       
   954         if (CurAmmoGear = nil)
       
   955         and (HHGear^.dY > _0_39)
       
   956         and (CurAmmoType = amParachute) then HHGear^.Message:= HHGear^.Message or gmAttack;
       
   957     // check for case with ammo
       
   958     t:= CheckGearNear(HHGear, gtCase, 36, 36);
       
   959     if t <> nil then
       
   960         PickUp(HHGear, t)
       
   961     end;
       
   962 
       
   963 if (CurAmmoGear = nil) then
       
   964     if (((HHGear^.Message and gmAttack) <> 0)
       
   965         or ((HHGear^.State and gstAttacking) <> 0)) then
       
   966         Attack(HHGear) // should be before others to avoid desync with '/put' msg and changing weapon msgs
       
   967     else
       
   968 else 
       
   969     with Hedgehog^ do
       
   970         if ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
       
   971             and ((HHGear^.Message and gmLJump) <> 0)
       
   972             and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
       
   973             begin
       
   974             Attack(HHGear);
       
   975             HHGear^.Message:= HHGear^.Message and not gmLJump
       
   976             end;
       
   977 
       
   978 if (CurAmmoGear = nil)
       
   979     or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) 
       
   980     or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) then
       
   981     begin
       
   982     if ((HHGear^.Message and gmSlot) <> 0) then
       
   983         if ChangeAmmo(HHGear) then ApplyAmmoChanges(Hedgehog^);
       
   984 
       
   985     if ((HHGear^.Message and gmWeapon) <> 0) then HHSetWeapon(HHGear);
       
   986 
       
   987     if ((HHGear^.Message and gmTimer) <> 0) then HHSetTimer(HHGear);
       
   988     end;
       
   989 
       
   990 if CurAmmoGear <> nil then
       
   991    begin
       
   992    CurAmmoGear^.Message:= HHGear^.Message;
       
   993    exit
       
   994    end;
       
   995 
       
   996 if not isInMultiShoot then
       
   997    HedgehogChAngle(HHGear);
       
   998 
       
   999 if (HHGear^.State and gstMoving) <> 0 then
       
  1000     begin
       
  1001     wasJumping:= ((HHGear^.State and gstHHJumping) <> 0);
       
  1002 
       
  1003     if ((HHGear^.Message and gmHJump) <> 0) and
       
  1004         wasJumping and
       
  1005         ((HHGear^.State and gstHHHJump) = 0) then
       
  1006         if (not (hwAbs(HHGear^.dX) > cLittle)) and (HHGear^.dY < -_0_02) then
       
  1007             begin
       
  1008             HHGear^.State:= HHGear^.State or gstHHHJump;
       
  1009             HHGear^.dY:= -_0_25;
       
  1010             if not cArtillery then HHGear^.dX:= -SignAs(_0_02, HHGear^.dX);
       
  1011             PlaySound(sndJump2, Hedgehog^.Team^.voicepack)
       
  1012             end;
       
  1013 
       
  1014     HHGear^.Message:= HHGear^.Message and not (gmLJump or gmHJump);
       
  1015 
       
  1016     if (not cArtillery) and wasJumping and
       
  1017         TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
       
  1018 
       
  1019     if Hedgehog^.Gear <> nil then doStepHedgehogMoving(HHGear);
       
  1020 
       
  1021     if ((HHGear^.State and (gstMoving or gstDrowning)) = 0) then
       
  1022         begin
       
  1023         AddGearCI(HHGear);
       
  1024         if wasJumping then
       
  1025             StepTicks:= 410
       
  1026         else
       
  1027             StepTicks:= 95
       
  1028         end;
       
  1029     exit
       
  1030     end;
       
  1031 
       
  1032     if not isInMultiShoot and (Hedgehog^.Gear <> nil) then
       
  1033         begin
       
  1034         if StepTicks > 0 then dec(StepTicks);
       
  1035         if (StepTicks = 0) then HedgehogStep(HHGear)
       
  1036         end
       
  1037 end;
       
  1038 
       
  1039 ////////////////////////////////////////////////////////////////////////////////
       
  1040 procedure doStepHedgehogFree(Gear: PGear);
       
  1041 var prevState: Longword;
       
  1042 begin
       
  1043 prevState:= Gear^.State;
       
  1044 
       
  1045 doStepHedgehogMoving(Gear);
       
  1046 
       
  1047 if (Gear^.State and (gstMoving or gstDrowning)) <> 0 then
       
  1048     begin
       
  1049     if Gear^.Damage > 0 then CalcRotationDirAngle(Gear);
       
  1050     AllInactive:= false;
       
  1051     exit
       
  1052     end;
       
  1053 
       
  1054 if (Gear^.Health = 0) then
       
  1055     begin
       
  1056     if PrvInactive or ((GameFlags and gfInfAttack) <> 0) then
       
  1057         begin
       
  1058         Gear^.Timer:= 0;
       
  1059         FollowGear:= Gear;
       
  1060         PrvInactive:= false;
       
  1061         AllInactive:= false;
       
  1062 
       
  1063         if (Gear^.State and gstHHGone) = 0 then
       
  1064             begin
       
  1065             Gear^.Hedgehog^.Effects[hePoisoned] := false;
       
  1066             if Gear^.Hedgehog^.Effects[heResurrectable] then begin
       
  1067                 ResurrectHedgehog(Gear);
       
  1068             end else 
       
  1069                 begin
       
  1070                 Gear^.State:= (Gear^.State or gstHHDeath) and not gstAnimation;
       
  1071                 Gear^.doStep:= @doStepHedgehogDead;
       
  1072                 // Death message
       
  1073                 AddCaption(Format(GetEventString(eidDied), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
       
  1074                 end;
       
  1075             end
       
  1076         else
       
  1077             begin
       
  1078             Gear^.State:= Gear^.State and not gstAnimation;
       
  1079             Gear^.doStep:= @doStepHedgehogGone;
       
  1080 
       
  1081             // Gone message
       
  1082             AddCaption(Format(GetEventString(eidGone), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
       
  1083             end
       
  1084         end;
       
  1085     exit
       
  1086     end;
       
  1087 
       
  1088 if ((Gear^.State and gstWait) = 0) and
       
  1089     (prevState <> Gear^.State) then
       
  1090     begin
       
  1091     Gear^.State:= Gear^.State or gstWait;
       
  1092     Gear^.Timer:= 150
       
  1093     end else
       
  1094     begin
       
  1095     if Gear^.Timer = 0 then
       
  1096         begin
       
  1097         Gear^.State:= Gear^.State and not (gstWait or gstLoser or gstWinner or gstAttacked or gstNotKickable);
       
  1098         Gear^.Active:= false;
       
  1099         AddGearCI(Gear);
       
  1100         exit
       
  1101         end else dec(Gear^.Timer)
       
  1102     end;
       
  1103 
       
  1104 AllInactive:= false
       
  1105 end;
       
  1106 
       
  1107 ////////////////////////////////////////////////////////////////////////////////
       
  1108 procedure doStepHedgehog(Gear: PGear);
       
  1109 (*
       
  1110 var x,y,tx,ty: LongInt;
       
  1111     tdX, tdY, slope: hwFloat; 
       
  1112     land: Word; *)
       
  1113 var slope: hwFloat; 
       
  1114 begin
       
  1115 if (Gear^.Message and gmDestroy) <> 0 then
       
  1116     begin
       
  1117     DeleteGear(Gear);
       
  1118     exit
       
  1119     end;
       
  1120 
       
  1121 if (Gear^.State and gstHHDriven) = 0 then
       
  1122     doStepHedgehogFree(Gear)
       
  1123 else
       
  1124     begin
       
  1125     with Gear^.Hedgehog^ do
       
  1126         if Team^.hasGone then
       
  1127             TeamGoneEffect(Team^)
       
  1128         else
       
  1129             doStepHedgehogDriven(Gear)
       
  1130     end;
       
  1131 if (Gear^.Message and (gmAllStoppable or gmLJump or gmHJump) = 0) and
       
  1132    (Gear^.State and (gstHHJumping or gstHHHJump or gstAttacking) = 0) and
       
  1133    not Gear^.dY.isNegative and
       
  1134    (GameTicks mod (100*hwRound(cMaxWindSpeed/(cGravity/2))) = 0) and 
       
  1135    (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
       
  1136     begin
       
  1137     slope:= CalcSlopeBelowGear(Gear);
       
  1138     Gear^.dX:=Gear^.dX+slope*_0_07;
       
  1139     if slope.QWordValue <> 0 then Gear^.State:= Gear^.State or gstMoving;
       
  1140 (*
       
  1141     x:= hwRound(Gear^.X);
       
  1142     y:= hwRound(Gear^.Y);
       
  1143     AddVisualGear(x, y, vgtSmokeTrace);
       
  1144     AddVisualGear(x - hwRound(_5*slope), y + hwRound(_5*slope), vgtSmokeTrace);
       
  1145     AddVisualGear(x + hwRound(_5*slope), y - hwRound(_5*slope), vgtSmokeTrace);
       
  1146     AddVisualGear(x - hwRound(_20 * slope), y + hwRound(_20 * slope), vgtSmokeTrace);
       
  1147     AddVisualGear(x + hwRound(_20 * slope), y - hwRound(_20 * slope), vgtSmokeTrace);
       
  1148     AddVisualGear(x - hwRound(_30 * slope), y + hwRound(_30 * slope), vgtSmokeTrace);
       
  1149     AddVisualGear(x + hwRound(_30 * slope), y - hwRound(_30 * slope), vgtSmokeTrace);
       
  1150     AddVisualGear(x - hwRound(_40 * slope), y + hwRound(_40 * slope), vgtSmokeTrace);
       
  1151     AddVisualGear(x + hwRound(_40 * slope), y - hwRound(_40 * slope), vgtSmokeTrace);
       
  1152     AddVisualGear(x - hwRound(_50 * slope), y + hwRound(_50 * slope), vgtSmokeTrace);
       
  1153     AddVisualGear(x + hwRound(_50 * slope), y - hwRound(_50 * slope), vgtSmokeTrace); *)
       
  1154     end
       
  1155 end;