hedgewars/HHHandlers.inc
changeset 6468 da1e7fe7cff7
parent 6453 11c578d30bd3
child 6700 e04da46ee43c
equal deleted inserted replaced
6467:090269e528df 6468:da1e7fe7cff7
    15  * along with this program; if not, write to the Free Software
    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
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    17  *)
    17  *)
    18 
    18 
    19 ////////////////////////////////////////////////////////////////////////////////
    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    exit
       
   775    end;
       
   776 isFalling:= (Gear^.dY.isNegative) or not TestCollisionYKick(Gear, 1);
       
   777 if isFalling then
       
   778    begin
       
   779    if (Gear^.dY.isNegative) and TestCollisionYKick(Gear, -1) then Gear^.dY:= _0;
       
   780    Gear^.State:= Gear^.State or gstMoving;
       
   781    if (CurrentHedgehog^.Gear = Gear)
       
   782         and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then 
       
   783         begin
       
   784         FollowGear:= Gear;
       
   785         end;
       
   786    if isUnderwater then Gear^.dY:= Gear^.dY + cGravity / _2
       
   787    else
       
   788        begin
       
   789        Gear^.dY:= Gear^.dY + cGravity;
       
   790 // this set of circumstances could be less complex if jumping was more clearly identified
       
   791        if ((GameFlags and gfMoreWind) <> 0) and 
       
   792           (((Gear^.Damage <> 0) or
       
   793           ((CurAmmoGear <> nil) and
       
   794             ((CurAmmoGear^.AmmoType = amJetpack) or
       
   795             (CurAmmoGear^.AmmoType = amBirdy))) or
       
   796           ((Gear^.dY.QWordValue + Gear^.dX.QWordValue) > _0_55.QWordValue)))
       
   797           then Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
       
   798        end
       
   799    end 
       
   800 else
       
   801    begin
       
   802    land:= TestCollisionYwithGear(Gear, 1);
       
   803    if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_55.QWordValue) and ((land and lfIce) = 0)
       
   804       and ((Gear^.State and gstHHJumping) <> 0) then SetLittle(Gear^.dX);
       
   805 
       
   806    if not Gear^.dY.isNegative then
       
   807       begin
       
   808       CheckHHDamage(Gear);
       
   809 
       
   810       if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) and
       
   811          (Gear^.dX.QWordValue < _0_02.QWordValue) then Gear^.dX.isNegative:= not Gear^.dX.isNegative; // landing after high jump
       
   812 
       
   813       Gear^.State:= Gear^.State and (not (gstHHJumping or gstHHHJump));
       
   814       Gear^.dY:= _0;
       
   815       end else Gear^.dY:= Gear^.dY + cGravity;
       
   816 
       
   817    if ((Gear^.State and gstMoving) <> 0) then
       
   818        begin
       
   819        if land and lfIce <> 0 then
       
   820            begin
       
   821            Gear^.dX:= Gear^.dX * (_1 - (_1 - Gear^.Friction) / _2)
       
   822            end
       
   823        else Gear^.dX:= Gear^.dX * Gear^.Friction;
       
   824        end
       
   825    end;
       
   826 
       
   827 if (Gear^.State <> 0) then DeleteCI(Gear);
       
   828 
       
   829 if isUnderwater then
       
   830    begin
       
   831    Gear^.dY:= Gear^.dY * _0_999;
       
   832    Gear^.dX:= Gear^.dX * _0_999;
       
   833    end;
       
   834 
       
   835 if (Gear^.State and gstMoving) <> 0 then
       
   836    if TestCollisionXKick(Gear, hwSign(Gear^.dX)) then
       
   837       if not isFalling then
       
   838          if hwAbs(Gear^.dX) > _0_01 then
       
   839             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
       
   840             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
       
   841             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
       
   842             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
       
   843             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
       
   844             if hwAbs(Gear^.dX) > _0_02 then Gear^.dX:= -Gear^.Elasticity * Gear^.dX
       
   845                                    else begin
       
   846                                         Gear^.State:= Gear^.State and (not gstMoving);
       
   847                                         while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
       
   848                                         SetLittle(Gear^.dX)
       
   849                                         end
       
   850             else begin
       
   851                  Gear^.State:= Gear^.State and (not gstMoving);
       
   852                  while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
       
   853                  SetLittle(Gear^.dX)
       
   854                  end
       
   855          else if (hwAbs(Gear^.dX) > cLittle)
       
   856                 and ((Gear^.State and gstHHJumping) = 0)
       
   857                 then Gear^.dX:= -Gear^.Elasticity * Gear^.dX
       
   858                 else SetLittle(Gear^.dX);
       
   859 
       
   860 if (not isFalling) and
       
   861    (hwAbs(Gear^.dX) + hwAbs(Gear^.dY) < _0_03) then
       
   862    begin
       
   863    Gear^.State:= Gear^.State and (not gstWinner);
       
   864    Gear^.State:= Gear^.State and (not gstMoving);
       
   865    while TestCollisionYWithGear(Gear,1) = 0 do Gear^.Y:= Gear^.Y+_1;
       
   866    SetLittle(Gear^.dX);
       
   867    Gear^.dY:= _0
       
   868    end else Gear^.State:= Gear^.State or gstMoving;
       
   869 
       
   870 if (Gear^.State and gstMoving) <> 0 then
       
   871    begin
       
   872    Gear^.State:= Gear^.State and (not gstAnimation);
       
   873 // ARTILLERY but not being moved by explosions
       
   874    Gear^.X:= Gear^.X + Gear^.dX;
       
   875    Gear^.Y:= Gear^.Y + Gear^.dY;
       
   876    if (not Gear^.dY.isNegative) and
       
   877       (not TestCollisionYKick(Gear, 1)) and
       
   878        TestCollisionYwithXYShift(Gear, 0, 1, 1) then
       
   879       begin
       
   880       CheckHHDamage(Gear);
       
   881       Gear^.dY:= _0;
       
   882       Gear^.Y:= Gear^.Y + _1
       
   883       end;
       
   884    CheckGearDrowning(Gear);
       
   885    // hide target cursor if current hog is drowning
       
   886    if (Gear^.State and gstDrowning) <> 0 then
       
   887        if (CurrentHedgehog^.Gear = Gear) then
       
   888           isCursorVisible:= false
       
   889    end;
       
   890 
       
   891 if (hwAbs(Gear^.dY) > _0) and (Gear^.FlightTime > 0) and ((GameFlags and gfLowGravity) = 0) then
       
   892     begin
       
   893     inc(Gear^.FlightTime);
       
   894     if Gear^.FlightTime = 3000 then
       
   895         begin
       
   896         AddCaption(GetEventString(eidHomerun), cWhiteColor, capgrpMessage);
       
   897         PlaySound(sndHomerun)
       
   898         end;
       
   899     end
       
   900 else
       
   901     begin
       
   902     uStats.hedgehogFlight(Gear, Gear^.FlightTime);
       
   903     Gear^.FlightTime:= 0;
       
   904     end;
       
   905 
       
   906 end;
       
   907 
       
   908 procedure doStepHedgehogDriven(HHGear: PGear);
       
   909 var t: PGear;
       
   910     wasJumping: boolean;
       
   911     Hedgehog: PHedgehog;
       
   912 begin
       
   913 Hedgehog:= HHGear^.Hedgehog;
       
   914 if isInMultiShoot then
       
   915    HHGear^.Message:= 0;
       
   916 
       
   917 if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_Utility) <> 0) and isInMultiShoot then 
       
   918     AllInactive:= true
       
   919 else if not isInMultiShoot then AllInactive:= false;
       
   920 
       
   921 if (TurnTimeLeft = 0) or (HHGear^.Damage > 0) then
       
   922     begin
       
   923     if TagTurnTimeLeft = 0 then TagTurnTimeLeft:= TurnTimeLeft;
       
   924     TurnTimeLeft:= 0;
       
   925     isCursorVisible:= false;
       
   926     HHGear^.State:= HHGear^.State and (not (gstHHDriven or gstAnimation or gstAttacking));
       
   927     AttackBar:= 0;
       
   928     if HHGear^.Damage > 0 then
       
   929         HHGear^.State:= HHGear^.State and (not (gstHHJumping or gstHHHJump));
       
   930     exit
       
   931     end;
       
   932 
       
   933 if (HHGear^.State and gstAnimation) <> 0 then
       
   934     begin
       
   935     HHGear^.Message:= 0;
       
   936     if (HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].VoiceDelay) and (HHGear^.Timer = 0) then PlaySound(Wavez[TWave(HHGear^.Tag)].Voice, Hedgehog^.Team^.voicepack);
       
   937     inc(HHGear^.Timer);
       
   938     if HHGear^.Timer = Wavez[TWave(HHGear^.Tag)].Interval then
       
   939         begin
       
   940         HHGear^.Timer:= 0;
       
   941         inc(HHGear^.Pos);
       
   942         if HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].FramesCount then
       
   943             HHGear^.State:= HHGear^.State and (not gstAnimation)
       
   944         end;
       
   945     exit
       
   946     end;
       
   947 
       
   948 if ((HHGear^.State and gstMoving) <> 0)
       
   949     or (StepTicks = cHHStepTicks)
       
   950     or (CurAmmoGear <> nil) then // we are moving
       
   951     begin
       
   952     with Hedgehog^ do
       
   953         if (CurAmmoGear = nil)
       
   954         and (HHGear^.dY > _0_39)
       
   955         and (CurAmmoType = amParachute) then HHGear^.Message:= HHGear^.Message or gmAttack;
       
   956     // check for case with ammo
       
   957     t:= CheckGearNear(HHGear, gtCase, 36, 36);
       
   958     if t <> nil then
       
   959         PickUp(HHGear, t)
       
   960     end;
       
   961 
       
   962 if (CurAmmoGear = nil) then
       
   963     if (((HHGear^.Message and gmAttack) <> 0)
       
   964         or ((HHGear^.State and gstAttacking) <> 0)) then
       
   965         Attack(HHGear) // should be before others to avoid desync with '/put' msg and changing weapon msgs
       
   966     else
       
   967 else 
       
   968     with Hedgehog^ do
       
   969         if ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
       
   970             and ((HHGear^.Message and gmLJump) <> 0)
       
   971             and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
       
   972             begin
       
   973             Attack(HHGear);
       
   974             HHGear^.Message:= HHGear^.Message and (not gmLJump)
       
   975             end;
       
   976 
       
   977 if (CurAmmoGear = nil)
       
   978     or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) 
       
   979     or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) then
       
   980     begin
       
   981     if ((HHGear^.Message and gmSlot) <> 0) then
       
   982         if ChangeAmmo(HHGear) then ApplyAmmoChanges(Hedgehog^);
       
   983 
       
   984     if ((HHGear^.Message and gmWeapon) <> 0) then HHSetWeapon(HHGear);
       
   985 
       
   986     if ((HHGear^.Message and gmTimer) <> 0) then HHSetTimer(HHGear);
       
   987     end;
       
   988 
       
   989 if CurAmmoGear <> nil then
       
   990    begin
       
   991    CurAmmoGear^.Message:= HHGear^.Message;
       
   992    exit
       
   993    end;
       
   994 
       
   995 if not isInMultiShoot then
       
   996    HedgehogChAngle(HHGear);
       
   997 
       
   998 if (HHGear^.State and gstMoving) <> 0 then
       
   999     begin
       
  1000     wasJumping:= ((HHGear^.State and gstHHJumping) <> 0);
       
  1001 
       
  1002     if ((HHGear^.Message and gmHJump) <> 0) and
       
  1003         wasJumping and
       
  1004         ((HHGear^.State and gstHHHJump) = 0) then
       
  1005         if (not (hwAbs(HHGear^.dX) > cLittle)) and (HHGear^.dY < -_0_02) then
       
  1006             begin
       
  1007             HHGear^.State:= HHGear^.State or gstHHHJump;
       
  1008             HHGear^.dY:= -_0_25;
       
  1009             if not cArtillery then HHGear^.dX:= -SignAs(_0_02, HHGear^.dX);
       
  1010             PlaySound(sndJump2, Hedgehog^.Team^.voicepack)
       
  1011             end;
       
  1012 
       
  1013     HHGear^.Message:= HHGear^.Message and (not (gmLJump or gmHJump));
       
  1014 
       
  1015     if (not cArtillery) and wasJumping and
       
  1016         TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
       
  1017 
       
  1018     if Hedgehog^.Gear <> nil then doStepHedgehogMoving(HHGear);
       
  1019 
       
  1020     if ((HHGear^.State and (gstMoving or gstDrowning)) = 0) then
       
  1021         begin
       
  1022         AddGearCI(HHGear);
       
  1023         if wasJumping then
       
  1024             StepTicks:= 410
       
  1025         else
       
  1026             StepTicks:= 95
       
  1027         end;
       
  1028     exit
       
  1029     end;
       
  1030 
       
  1031     if not isInMultiShoot and (Hedgehog^.Gear <> nil) then
       
  1032         begin
       
  1033         if StepTicks > 0 then dec(StepTicks);
       
  1034         if (StepTicks = 0) then HedgehogStep(HHGear)
       
  1035         end
       
  1036 end;
       
  1037 
       
  1038 ////////////////////////////////////////////////////////////////////////////////
       
  1039 procedure doStepHedgehogFree(Gear: PGear);
       
  1040 var prevState: Longword;
       
  1041 begin
       
  1042 prevState:= Gear^.State;
       
  1043 
       
  1044 doStepHedgehogMoving(Gear);
       
  1045 
       
  1046 if (Gear^.State and (gstMoving or gstDrowning)) <> 0 then
       
  1047     begin
       
  1048     if Gear^.Damage > 0 then CalcRotationDirAngle(Gear);
       
  1049     AllInactive:= false;
       
  1050     exit
       
  1051     end;
       
  1052 
       
  1053 if (Gear^.Health = 0) then
       
  1054     begin
       
  1055     if PrvInactive or ((GameFlags and gfInfAttack) <> 0) then
       
  1056         begin
       
  1057         Gear^.Timer:= 0;
       
  1058         FollowGear:= Gear;
       
  1059         PrvInactive:= false;
       
  1060         AllInactive:= false;
       
  1061 
       
  1062         if (Gear^.State and gstHHGone) = 0 then
       
  1063             begin
       
  1064             Gear^.Hedgehog^.Effects[hePoisoned] := false;
       
  1065             if Gear^.Hedgehog^.Effects[heResurrectable] then begin
       
  1066                 ResurrectHedgehog(Gear);
       
  1067             end else 
       
  1068                 begin
       
  1069                 Gear^.State:= (Gear^.State or gstHHDeath) and (not gstAnimation);
       
  1070                 Gear^.doStep:= @doStepHedgehogDead;
       
  1071                 // Death message
       
  1072                 AddCaption(Format(GetEventString(eidDied), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
       
  1073                 end;
       
  1074             end
       
  1075         else
       
  1076             begin
       
  1077             Gear^.State:= Gear^.State and (not gstAnimation);
       
  1078             Gear^.doStep:= @doStepHedgehogGone;
       
  1079 
       
  1080             // Gone message
       
  1081             AddCaption(Format(GetEventString(eidGone), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage);
       
  1082             end
       
  1083         end;
       
  1084     exit
       
  1085     end;
       
  1086 
       
  1087 if ((Gear^.State and gstWait) = 0) and
       
  1088     (prevState <> Gear^.State) then
       
  1089     begin
       
  1090     Gear^.State:= Gear^.State or gstWait;
       
  1091     Gear^.Timer:= 150
       
  1092     end else
       
  1093     begin
       
  1094     if Gear^.Timer = 0 then
       
  1095         begin
       
  1096         Gear^.State:= Gear^.State and (not (gstWait or gstLoser or gstWinner or gstAttacked or gstNotKickable or gstHHChooseTarget));
       
  1097         Gear^.Active:= false;
       
  1098         AddGearCI(Gear);
       
  1099         exit
       
  1100         end else dec(Gear^.Timer)
       
  1101     end;
       
  1102 
       
  1103 AllInactive:= false
       
  1104 end;
       
  1105 
       
  1106 ////////////////////////////////////////////////////////////////////////////////
       
  1107 procedure doStepHedgehog(Gear: PGear);
       
  1108 (*
       
  1109 var x,y,tx,ty: LongInt;
       
  1110     tdX, tdY, slope: hwFloat; 
       
  1111     land: Word; *)
       
  1112 var slope: hwFloat; 
       
  1113 begin
       
  1114 if (Gear^.Message and gmDestroy) <> 0 then
       
  1115     begin
       
  1116     DeleteGear(Gear);
       
  1117     exit
       
  1118     end;
       
  1119 
       
  1120 if (Gear^.State and gstHHDriven) = 0 then
       
  1121     doStepHedgehogFree(Gear)
       
  1122 else
       
  1123     begin
       
  1124     with Gear^.Hedgehog^ do
       
  1125         if Team^.hasGone then
       
  1126             TeamGoneEffect(Team^)
       
  1127         else
       
  1128             doStepHedgehogDriven(Gear)
       
  1129     end;
       
  1130 if (Gear^.Message and (gmAllStoppable or gmLJump or gmHJump) = 0) and
       
  1131    (Gear^.State and (gstHHJumping or gstHHHJump or gstAttacking) = 0) and
       
  1132    (not Gear^.dY.isNegative) and
       
  1133    (GameTicks mod (100*LongWOrd(hwRound(cMaxWindSpeed*2/cGravity))) = 0) and
       
  1134    (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
       
  1135     begin
       
  1136     slope:= CalcSlopeBelowGear(Gear);
       
  1137     Gear^.dX:=Gear^.dX+slope*_0_07;
       
  1138     if slope.QWordValue <> 0 then Gear^.State:= Gear^.State or gstMoving;
       
  1139 (*
       
  1140     x:= hwRound(Gear^.X);
       
  1141     y:= hwRound(Gear^.Y);
       
  1142     AddVisualGear(x, y, vgtSmokeTrace);
       
  1143     AddVisualGear(x - hwRound(_5*slope), y + hwRound(_5*slope), vgtSmokeTrace);
       
  1144     AddVisualGear(x + hwRound(_5*slope), y - hwRound(_5*slope), vgtSmokeTrace);
       
  1145     AddVisualGear(x - hwRound(_20 * slope), y + hwRound(_20 * slope), vgtSmokeTrace);
       
  1146     AddVisualGear(x + hwRound(_20 * slope), y - hwRound(_20 * slope), vgtSmokeTrace);
       
  1147     AddVisualGear(x - hwRound(_30 * slope), y + hwRound(_30 * slope), vgtSmokeTrace);
       
  1148     AddVisualGear(x + hwRound(_30 * slope), y - hwRound(_30 * slope), vgtSmokeTrace);
       
  1149     AddVisualGear(x - hwRound(_40 * slope), y + hwRound(_40 * slope), vgtSmokeTrace);
       
  1150     AddVisualGear(x + hwRound(_40 * slope), y - hwRound(_40 * slope), vgtSmokeTrace);
       
  1151     AddVisualGear(x - hwRound(_50 * slope), y + hwRound(_50 * slope), vgtSmokeTrace);
       
  1152     AddVisualGear(x + hwRound(_50 * slope), y - hwRound(_50 * slope), vgtSmokeTrace); *)
       
  1153     end
       
  1154 end;