hedgewars/uGearsList.pas
changeset 16049 9be943326d9c
parent 15869 2839b68a3732
equal deleted inserted replaced
16048:eb015d6b4a2a 16049:9be943326d9c
    20 unit uGearsList;
    20 unit uGearsList;
    21 
    21 
    22 interface
    22 interface
    23 uses uFloat, uTypes, SDLh;
    23 uses uFloat, uTypes, SDLh;
    24 
    24 
       
    25 procedure initializeGear(gear: PGear; X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer, newUid: LongWord);
    25 function  AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
    26 function  AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
    26 function  AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer, newUid: LongWord): PGear;
    27 function  AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer, newUid: LongWord): PGear;
    27 procedure DeleteGear(Gear: PGear);
    28 procedure DeleteGear(Gear: PGear);
    28 procedure InsertGearToList(Gear: PGear);
    29 procedure InsertGearToList(Gear: PGear);
    29 procedure RemoveGearFromList(Gear: PGear);
    30 procedure RemoveGearFromList(Gear: PGear);
   165 
   166 
   166 Gear^.NextGear:= nil;
   167 Gear^.NextGear:= nil;
   167 Gear^.PrevGear:= nil
   168 Gear^.PrevGear:= nil
   168 end;
   169 end;
   169 
   170 
       
   171 procedure initializeGear(gear: PGear; X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer, newUid: LongWord);
       
   172 var cakeData: PCakeData;
       
   173 begin
       
   174     FillChar(gear^, sizeof(TGear), 0);
       
   175     gear^.X:= int2hwFloat(X);
       
   176     gear^.Y:= int2hwFloat(Y);
       
   177     gear^.Target.X:= NoPointX;
       
   178     gear^.Kind := Kind;
       
   179     gear^.State:= State;
       
   180     gear^.Active:= true;
       
   181     gear^.dX:= dX;
       
   182     gear^.dY:= dY;
       
   183     gear^.doStep:= doStepHandlers[Kind];
       
   184     gear^.CollisionIndex:= -1;
       
   185     gear^.Timer:= Timer;
       
   186     if newUid = 0 then
       
   187          gear^.uid:= GCounter
       
   188     else gear^.uid:= newUid;
       
   189     gear^.SoundChannel:= -1;
       
   190     gear^.ImpactSound:= sndNone;
       
   191     gear^.Density:= _1;
       
   192     // Define ammo association, if any.
       
   193     gear^.AmmoType:= GearKindAmmoTypeMap[Kind];
       
   194     gear^.CollisionMask:= lfAll;
       
   195     gear^.Tint:= $FFFFFFFF;
       
   196     gear^.Data:= nil;
       
   197     gear^.Sticky:= false;
       
   198 
       
   199     if CurrentHedgehog <> nil then
       
   200         begin
       
   201         gear^.Hedgehog:= CurrentHedgehog;
       
   202         if (CurrentHedgehog^.Gear <> nil) and (hwRound(CurrentHedgehog^.Gear^.X) = X) and (hwRound(CurrentHedgehog^.Gear^.Y) = Y) then
       
   203             gear^.CollisionMask:= lfNotCurHogCrate
       
   204         end;
       
   205 
       
   206     if (Ammoz[Gear^.AmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0) then
       
   207         gear^.Z:= cHHZ+1
       
   208     else gear^.Z:= cUsualZ;
       
   209 
       
   210     // set gstInBounceEdge if gear spawned inside the bounce world edge
       
   211     if WorldEdge = weBounce then
       
   212         if (hwRound(gear^.X) - Gear^.Radius < leftX) or (hwRound(gear^.X) + Gear^.Radius > rightX) then
       
   213             case gear^.Kind of
       
   214                 // list all gears here that could collide with the bounce world edge
       
   215                 gtHedgehog,
       
   216                 gtFlame,
       
   217                 gtMine,
       
   218                 gtAirBomb,
       
   219                 gtDrill,
       
   220                 gtNapalmBomb,
       
   221                 gtCase,
       
   222                 gtAirMine,
       
   223                 gtExplosives,
       
   224                 gtGrenade,
       
   225                 gtShell,
       
   226                 gtBee,
       
   227                 gtDynamite,
       
   228                 gtClusterBomb,
       
   229                 gtMelonPiece,
       
   230                 gtCluster,
       
   231                 gtMortar,
       
   232                 gtKamikaze,
       
   233                 gtCake,
       
   234                 gtWatermelon,
       
   235                 gtGasBomb,
       
   236                 gtHellishBomb,
       
   237                 gtBall,
       
   238                 gtRCPlane,
       
   239                 gtSniperRifleShot,
       
   240                 gtShotgunShot,
       
   241                 gtDEagleShot,
       
   242                 gtSineGunShot,
       
   243                 gtMinigunBullet,
       
   244                 gtEgg,
       
   245                 gtPiano,
       
   246                 gtSMine,
       
   247                 gtSnowball,
       
   248                 gtKnife,
       
   249                 gtCreeper,
       
   250                 gtSentry,
       
   251                 gtMolotov,
       
   252                 gtFlake,
       
   253                 gtGrave,
       
   254                 gtPortal,
       
   255                 gtTarget:
       
   256                 gear^.State := gear^.State or gstInBounceEdge;
       
   257             end;
       
   258 
       
   259     case Kind of
       
   260               gtFlame: Gear^.Boom := 2;  // some additional expl in there are x3, x4 this
       
   261            gtHedgehog: Gear^.Boom := 30;
       
   262                gtMine: Gear^.Boom := 50;
       
   263                gtCase: Gear^.Boom := 25;
       
   264             gtAirMine: Gear^.Boom := 30;
       
   265          gtExplosives: Gear^.Boom := 75;
       
   266             gtGrenade: Gear^.Boom := 50;
       
   267               gtShell: Gear^.Boom := 50;
       
   268                 gtBee: Gear^.Boom := 50;
       
   269         gtShotgunShot: Gear^.Boom := 25;
       
   270          gtPickHammer: Gear^.Boom := 6;
       
   271     //           gtRope: Gear^.Boom := 2; could be funny to have rope attaching to hog deal small amount of dmg?
       
   272          gtDEagleShot: Gear^.Boom := 7;
       
   273            gtDynamite: Gear^.Boom := 75;
       
   274         gtClusterBomb: Gear^.Boom := 20;
       
   275          gtMelonPiece,
       
   276             gtCluster: Gear^.Boom := Timer;
       
   277              gtShover: Gear^.Boom := 30;
       
   278           gtFirePunch: Gear^.Boom := 30;
       
   279             gtAirBomb: Gear^.Boom := 30;
       
   280           gtBlowTorch: Gear^.Boom := 2;
       
   281              gtMortar: Gear^.Boom := 20;
       
   282                gtWhip: Gear^.Boom := 30;
       
   283            gtKamikaze: Gear^.Boom := 30; // both shove and explosion
       
   284                gtCake: Gear^.Boom := cakeDmg; // why is cake damage a global constant
       
   285          gtWatermelon: Gear^.Boom := 75;
       
   286         gtHellishBomb: Gear^.Boom := 90;
       
   287               gtDrill: if Gear^.State and gsttmpFlag = 0 then
       
   288                             Gear^.Boom := 50
       
   289                        else Gear^.Boom := 30;
       
   290                gtBall: Gear^.Boom := 40;
       
   291             gtRCPlane: Gear^.Boom := 25;
       
   292     // sniper rifle is distance linked, this Boom is just an arbitrary scaling factor applied to timer-based-damage
       
   293     // because, eh, why not..
       
   294     gtSniperRifleShot: Gear^.Boom := 100000;
       
   295                 gtEgg: Gear^.Boom := 10;
       
   296               gtPiano: Gear^.Boom := 80;
       
   297             gtGasBomb: Gear^.Boom := 20;
       
   298         gtSineGunShot: Gear^.Boom := 35;
       
   299               gtSMine: Gear^.Boom := 30;
       
   300         gtSnowball: Gear^.Boom := 200000; // arbitrary scaling for the shove
       
   301              gtHammer: if cDamageModifier > _1 then // scale it based on cDamageModifier?
       
   302                              Gear^.Boom := 2
       
   303                         else Gear^.Boom := 3;
       
   304         gtPoisonCloud: Gear^.Boom := 20;
       
   305               gtKnife: Gear^.Boom := 40000; // arbitrary scaling factor since impact-based
       
   306             gtCreeper: Gear^.Boom := 100;
       
   307       gtMinigunBullet: Gear^.Boom := 2;
       
   308              gtSentry: Gear^.Boom := 40;
       
   309         end;
       
   310 
       
   311     case Kind of
       
   312          gtGrenade,
       
   313          gtClusterBomb,
       
   314          gtGasBomb: begin
       
   315                     gear^.ImpactSound:= sndGrenadeImpact;
       
   316                     gear^.nImpactSounds:= 1;
       
   317                     gear^.AdvBounce:= 1;
       
   318                     gear^.Radius:= 5;
       
   319                     gear^.Elasticity:= _0_8;
       
   320                     gear^.Friction:= _0_8;
       
   321                     gear^.Density:= _1_5;
       
   322                     gear^.RenderTimer:= true;
       
   323                     if gear^.Timer = 0 then
       
   324                         gear^.Timer:= 3000
       
   325                     end;
       
   326       gtWatermelon: begin
       
   327                     gear^.ImpactSound:= sndMelonImpact;
       
   328                     gear^.nImpactSounds:= 1;
       
   329                     gear^.AdvBounce:= 1;
       
   330                     gear^.Radius:= 6;
       
   331                     gear^.Elasticity:= _0_8;
       
   332                     gear^.Friction:= _0_995;
       
   333                     gear^.Density:= _2;
       
   334                     gear^.RenderTimer:= true;
       
   335                     if gear^.Timer = 0 then
       
   336                         gear^.Timer:= 3000
       
   337                     end;
       
   338       gtMelonPiece: begin
       
   339                     gear^.AdvBounce:= 1;
       
   340                     gear^.Density:= _2;
       
   341                     gear^.Elasticity:= _0_8;
       
   342                     gear^.Friction:= _0_995;
       
   343                     gear^.Radius:= 4
       
   344                     end;
       
   345         gtHedgehog: begin
       
   346                     gear^.AdvBounce:= 1;
       
   347                     gear^.Radius:= cHHRadius;
       
   348                     gear^.Elasticity:= _0_35;
       
   349                     gear^.Friction:= _0_999;
       
   350                     gear^.Angle:= cMaxAngle div 2;
       
   351                     gear^.Density:= _3;
       
   352                     gear^.Z:= cHHZ;
       
   353                     if (GameFlags and gfAISurvival) <> 0 then
       
   354                         if gear^.Hedgehog^.BotLevel > 0 then
       
   355                             gear^.Hedgehog^.Effects[heResurrectable] := 1;
       
   356                     if (GameFlags and gfArtillery) <> 0 then
       
   357                         gear^.Hedgehog^.Effects[heArtillery] := 1;
       
   358                     // this would presumably be set in the frontend
       
   359                     // if we weren't going to do that yet, would need to reinit GetRandom
       
   360                     // oh, and, randomising slightly R and B might be nice too.
       
   361                     //gear^.Tint:= $fa00efff or ((random(80)+128) shl 16)
       
   362                     //gear^.Tint:= $faa4efff
       
   363                     //gear^.Tint:= (($e0+random(32)) shl 24) or
       
   364                     //             ((random(80)+128) shl 16) or
       
   365                     //             (($d5+random(32)) shl 8) or $ff
       
   366                     {c:= GetRandom(32);
       
   367                     gear^.Tint:= (($e0+c) shl 24) or
       
   368                                  ((GetRandom(90)+128) shl 16) or
       
   369                                  (($d5+c) shl 8) or $ff}
       
   370                     end;
       
   371        gtParachute: begin
       
   372                     gear^.Tag:= 1; // hog face dir. 1 = right, -1 = left
       
   373                     gear^.Z:= cCurrHHZ;
       
   374                     end;
       
   375            gtShell: begin
       
   376                     gear^.Elasticity:= _0_8;
       
   377                     gear^.Friction:= _0_8;
       
   378                     gear^.Radius:= 4;
       
   379                     gear^.Density:= _1;
       
   380                     gear^.AdvBounce:= 1;
       
   381                     end;
       
   382            gtSnowball: begin
       
   383                     gear^.ImpactSound:= sndMudballImpact;
       
   384                     gear^.nImpactSounds:= 1;
       
   385                     gear^.Radius:= 4;
       
   386                     gear^.Density:= _0_5;
       
   387                     gear^.AdvBounce:= 1;
       
   388                     gear^.Elasticity:= _0_8;
       
   389                     gear^.Friction:= _0_8;
       
   390                     end;
       
   391 
       
   392          gtFlake: begin
       
   393                     with Gear^ do
       
   394                         begin
       
   395                         Pos:= 0;
       
   396                         Radius:= 1;
       
   397                         DirAngle:= random(360);
       
   398                         Sticky:= true;
       
   399                         if State and gstTmpFlag = 0 then
       
   400                             begin
       
   401                             dx.isNegative:= GetRandom(2) = 0;
       
   402                             dx.QWordValue:= QWord($40DA) * GetRandom(10000) * 8;
       
   403                             dy.isNegative:= false;
       
   404                             dy.QWordValue:= QWord($3AD3) * GetRandom(7000) * 8;
       
   405                             if GetRandom(2) = 0 then
       
   406                                 dx := -dx;
       
   407                             Tint:= $FFFFFFFF
       
   408                             end
       
   409                         else
       
   410                             Tint:= (ExplosionBorderColor shr RShift and $FF shl 24) or
       
   411                                    (ExplosionBorderColor shr GShift and $FF shl 16) or
       
   412                                    (ExplosionBorderColor shr BShift and $FF shl 8) or $FF;
       
   413                         State:= State or gstInvisible;
       
   414                         // use health field to store current frameticks
       
   415                         if vobFrameTicks > 0 then
       
   416                             Health:= random(vobFrameTicks)
       
   417                         else
       
   418                             Health:= 0;
       
   419                         // use timer to store currently displayed frame index
       
   420                         if gear^.Timer = 0 then Timer:= random(vobFramesCount);
       
   421                         Damage:= (random(2) * 2 - 1) * (vobVelocity + random(vobVelocity)) * 8
       
   422                         end
       
   423                     end;
       
   424            gtGrave: begin
       
   425                     gear^.ImpactSound:= sndGraveImpact;
       
   426                     gear^.nImpactSounds:= 1;
       
   427                     gear^.Radius:= 10;
       
   428                     gear^.Elasticity:= _0_6;
       
   429                     gear^.Z:= 1;
       
   430                     end;
       
   431              gtBee: begin
       
   432                     gear^.Radius:= 5;
       
   433                     if gear^.Timer = 0 then gear^.Timer:= 500;
       
   434                     gear^.RenderTimer:= true;
       
   435                     gear^.Elasticity:= _0_9;
       
   436                     gear^.Tag:= 0;
       
   437                     gear^.State:= Gear^.State or gstSubmersible
       
   438                     end;
       
   439        gtSeduction: begin
       
   440                     gear^.Radius:= cSeductionDist;
       
   441                     end;
       
   442      gtShotgunShot: begin
       
   443                     if gear^.Timer = 0 then gear^.Timer:= 900;
       
   444                     gear^.Radius:= 2
       
   445                     end;
       
   446       gtPickHammer: begin
       
   447                     gear^.Radius:= 10;
       
   448                     if gear^.Timer = 0 then gear^.Timer:= 4000
       
   449                     end;
       
   450        gtHammerHit: begin
       
   451                     gear^.Radius:= 8;
       
   452                     if gear^.Timer = 0 then gear^.Timer:= 125
       
   453                     end;
       
   454             gtRope: begin
       
   455                     gear^.Radius:= 3;
       
   456                     gear^.Friction:= _450 * _0_01 * cRopePercent;
       
   457                     RopePoints.Count:= 0;
       
   458                     gear^.Tint:= $D8D8D8FF;
       
   459                     gear^.Tag:= 0; // normal rope render
       
   460                     gear^.CollisionMask:= lfNotCurHogCrate //lfNotObjMask or lfNotHHObjMask;
       
   461                     end;
       
   462             gtMine: begin
       
   463                     gear^.ImpactSound:= sndMineImpact;
       
   464                     gear^.nImpactSounds:= 1;
       
   465                     gear^.Health:= 10;
       
   466                     gear^.State:= gear^.State or gstMoving;
       
   467                     gear^.Radius:= 2;
       
   468                     gear^.Elasticity:= _0_55;
       
   469                     gear^.Friction:= _0_995;
       
   470                     gear^.Density:= _1;
       
   471                     if gear^.Timer = 0 then
       
   472                         begin
       
   473                         if cMinesTime < 0 then
       
   474                             begin
       
   475                             gear^.Timer:= getrandom(51)*100;
       
   476                             gear^.Karma:= 1;
       
   477                             end
       
   478                         else
       
   479                             gear^.Timer:= cMinesTime;
       
   480                         end;
       
   481                     gear^.RenderTimer:= true;
       
   482                     end;
       
   483          gtAirMine: begin
       
   484                     gear^.AdvBounce:= 1;
       
   485                     gear^.ImpactSound:= sndAirMineImpact;
       
   486                     gear^.nImpactSounds:= 1;
       
   487                     gear^.Health:= 30;
       
   488                     gear^.State:= gear^.State or gstMoving or gstNoGravity or gstSubmersible;
       
   489                     gear^.Radius:= 8;
       
   490                     gear^.Elasticity:= _0_55;
       
   491                     gear^.Friction:= _0_995;
       
   492                     gear^.Density:= _1;
       
   493                     gear^.Angle:= 175; // Radius at which air bombs will start "seeking". $FFFFFFFF = unlimited. check is skipped.
       
   494                     gear^.Power:= cMaxWindSpeed.QWordValue div 2; // hwFloat converted. 1/2 g default. defines the "seek" speed when a gear is in range.
       
   495                     gear^.Pos:= cMaxWindSpeed.QWordValue * 3 div 2; // air friction. slows it down when not hitting stuff
       
   496                     gear^.Tag:= 0;
       
   497                     if gear^.Timer = 0 then
       
   498                         begin
       
   499                         if cMinesTime < 0 then
       
   500                             begin
       
   501                             gear^.Timer:= getrandom(13)*100;
       
   502                             gear^.Karma:= 1;
       
   503                             end
       
   504                         else
       
   505                             gear^.Timer:= cMinesTime div 4;
       
   506                         end;
       
   507                     gear^.RenderTimer:= true;
       
   508                     gear^.WDTimer:= gear^.Timer
       
   509                     end;
       
   510            gtSMine: begin
       
   511                     gear^.Health:= 10;
       
   512                     gear^.State:= gear^.State or gstMoving;
       
   513                     gear^.Radius:= 2;
       
   514                     gear^.Elasticity:= _0_55;
       
   515                     gear^.Friction:= _0_995;
       
   516                     gear^.Density:= _1_6;
       
   517                     gear^.AdvBounce:= 1;
       
   518                     gear^.Sticky:= true;
       
   519                     if gear^.Timer = 0 then gear^.Timer:= 500;
       
   520                     gear^.RenderTimer:= true;
       
   521                     end;
       
   522            gtKnife: begin
       
   523                     gear^.ImpactSound:= sndKnifeImpact;
       
   524                     gear^.AdvBounce:= 1;
       
   525                     gear^.Elasticity:= _0_8;
       
   526                     gear^.Friction:= _0_8;
       
   527                     gear^.Density:= _4;
       
   528                     gear^.Radius:= 7;
       
   529                     gear^.Sticky:= true;
       
   530                     end;
       
   531             gtCase: begin
       
   532                     gear^.ImpactSound:= sndCaseImpact;
       
   533                     gear^.nImpactSounds:= 1;
       
   534                     gear^.Radius:= 16;
       
   535                     gear^.Elasticity:= _0_3;
       
   536                     if gear^.Timer = 0 then gear^.Timer:= 500
       
   537                     end;
       
   538       gtExplosives: begin
       
   539                     gear^.AdvBounce:= 1;
       
   540                     if GameType in [gmtDemo, gmtRecord] then
       
   541                         gear^.RenderHealth:= true;
       
   542                     gear^.ImpactSound:= sndGrenadeImpact;
       
   543                     gear^.nImpactSounds:= 1;
       
   544                     gear^.Radius:= 16;
       
   545                     gear^.Elasticity:= _0_4;
       
   546                     gear^.Friction:= _0_995;
       
   547                     gear^.Density:= _6;
       
   548                     gear^.Health:= cBarrelHealth;
       
   549                     gear^.Z:= cHHZ-1
       
   550                     end;
       
   551       gtDEagleShot: begin
       
   552                     gear^.Radius:= 1;
       
   553                     gear^.Health:= 50;
       
   554                     gear^.Data:= nil;
       
   555                     end;
       
   556       gtSniperRifleShot: begin
       
   557                     gear^.Radius:= 1;
       
   558                     gear^.Health:= 50
       
   559                     end;
       
   560         gtDynamite: begin
       
   561                     gear^.ImpactSound:= sndDynamiteImpact;
       
   562                     gear^.nImpactSounds:= 1;
       
   563                     gear^.Radius:= 3;
       
   564                     gear^.Elasticity:= _0_55;
       
   565                     gear^.Friction:= _0_03;
       
   566                     gear^.Density:= _2;
       
   567                     if gear^.Timer = 0 then gear^.Timer:= 5000;
       
   568                     end;
       
   569          gtCluster: begin
       
   570                     gear^.AdvBounce:= 1;
       
   571                     gear^.Elasticity:= _0_8;
       
   572                     gear^.Friction:= _0_8;
       
   573                     gear^.Radius:= 2;
       
   574                     gear^.Density:= _1_5;
       
   575                     gear^.RenderTimer:= true
       
   576                     end;
       
   577           gtShover: begin
       
   578                     gear^.Radius:= 20;
       
   579                     gear^.Tag:= 0;
       
   580                     gear^.Timer:= 50;
       
   581                     end;
       
   582            gtFlame: begin
       
   583                     gear^.Tag:= GetRandom(32);
       
   584                     gear^.Radius:= 1;
       
   585                     gear^.Health:= 5;
       
   586                     gear^.Density:= _1;
       
   587                     gear^.FlightTime:= 9999999; // determines whether in-air flames do damage. disabled by default
       
   588                     if (gear^.dY.QWordValue = 0) and (gear^.dX.QWordValue = 0) then
       
   589                         begin
       
   590                         gear^.dY:= (getrandomf - _0_8) * _0_03;
       
   591                         gear^.dX:= (getrandomf - _0_5) * _0_4
       
   592                         end
       
   593                     end;
       
   594        gtFirePunch: begin
       
   595                     if gear^.Timer = 0 then gear^.Timer:= 3000;
       
   596                     gear^.Radius:= 15;
       
   597                     gear^.Tag:= Y
       
   598                     end;
       
   599        gtAirAttack: begin
       
   600                     gear^.Health:= 6;
       
   601                     gear^.Damage:= 30;
       
   602                     gear^.Z:= cHHZ+2;
       
   603                     gear^.Karma:= 0; // for sound effect: 0 = normal, 1 = underwater
       
   604                     gear^.Radius:= 150;
       
   605                     gear^.FlightTime:= 0; // for timeout in weWrap
       
   606                     gear^.Power:= 0; // count number of wraps in weWrap
       
   607                     gear^.WDTimer:= 0; // number of required wraps
       
   608                     gear^.Density:= _19;
       
   609                     gear^.Tint:= gear^.Hedgehog^.Team^.Clan^.Color shl 8 or $FF
       
   610                     end;
       
   611          gtAirBomb: begin
       
   612                     gear^.AdvBounce:= 1;
       
   613                     gear^.Radius:= 5;
       
   614                     gear^.Density:= _2;
       
   615                     gear^.Elasticity:= _0_55;
       
   616                     gear^.Friction:= _0_995
       
   617                     end;
       
   618        gtBlowTorch: begin
       
   619                     gear^.Radius:= cHHRadius + cBlowTorchC - 1;
       
   620                     if gear^.Timer = 0 then gear^.Timer:= 7500
       
   621                     end;
       
   622         gtSwitcher: begin
       
   623                     gear^.Z:= cCurrHHZ
       
   624                     end;
       
   625           gtTarget: begin
       
   626                     gear^.ImpactSound:= sndGrenadeImpact;
       
   627                     gear^.nImpactSounds:= 1;
       
   628                     gear^.Radius:= 10;
       
   629                     gear^.Elasticity:= _0_3;
       
   630                     end;
       
   631           gtTardis: begin
       
   632                     gear^.Pos:= 1; // tardis phase
       
   633                     gear^.Tag:= 0; // 1 = hedgehog died, disappeared, took damage or moved
       
   634                     gear^.Z:= cCurrHHZ+1;
       
   635                     end;
       
   636           gtMortar: begin
       
   637                     gear^.AdvBounce:= 1;
       
   638                     gear^.Radius:= 4;
       
   639                     gear^.Elasticity:= _0_2;
       
   640                     gear^.Friction:= _0_08;
       
   641                     gear^.Density:= _1;
       
   642                     end;
       
   643             gtWhip: gear^.Radius:= 20;
       
   644           gtHammer: gear^.Radius:= 20;
       
   645         gtKamikaze: begin
       
   646                     gear^.Health:= 2048;
       
   647                     gear^.Radius:= 20
       
   648                     end;
       
   649             gtCake: begin
       
   650                     gear^.Health:= 2048;
       
   651                     gear^.Radius:= 7;
       
   652                     gear^.Z:= cOnHHZ;
       
   653                     gear^.RenderTimer:= false;
       
   654                     gear^.DirAngle:= -90 * hwSign(Gear^.dX);
       
   655                     gear^.FlightTime:= 100; // (roughly) ticks spent dropping, used to skip getting up anim when stuck.
       
   656                                             // Initially set to a high value so cake has at least one getting up anim.
       
   657                     if not dX.isNegative then
       
   658                         gear^.Angle:= 1
       
   659                     else
       
   660                         gear^.Angle:= 3;
       
   661                     New(cakeData);
       
   662                     gear^.Data:= Pointer(cakeData);
       
   663                     end;
       
   664      gtHellishBomb: begin
       
   665                     gear^.ImpactSound:= sndHellishImpact1;
       
   666                     gear^.nImpactSounds:= 4;
       
   667                     gear^.AdvBounce:= 1;
       
   668                     gear^.Radius:= 4;
       
   669                     gear^.Elasticity:= _0_5;
       
   670                     gear^.Friction:= _0_96;
       
   671                     gear^.Density:= _1_5;
       
   672                     gear^.RenderTimer:= true;
       
   673                     if gear^.Timer = 0 then gear^.Timer:= 5000
       
   674                     end;
       
   675            gtDrill: begin
       
   676                     gear^.AdvBounce:= 1;
       
   677                     gear^.Elasticity:= _0_8;
       
   678                     gear^.Friction:= _0_8;
       
   679                     if gear^.Timer = 0 then
       
   680                         gear^.Timer:= 5000;
       
   681                     // Tag for drill strike. if 1 then first impact occured already
       
   682                     gear^.Tag := 0;
       
   683                     // Pos for state. If 1, drill is drilling
       
   684                     gear^.Pos := 0;
       
   685                     gear^.Radius:= 4;
       
   686                     gear^.Density:= _1;
       
   687                     end;
       
   688             gtBall: begin
       
   689                     gear^.ImpactSound:= sndGrenadeImpact;
       
   690                     gear^.nImpactSounds:= 1;
       
   691                     gear^.AdvBounce:= 1;
       
   692                     gear^.Radius:= 5;
       
   693                     gear^.Tag:= random(8);
       
   694                     if gear^.Timer = 0 then gear^.Timer:= 5000;
       
   695                     gear^.Elasticity:= _0_7;
       
   696                     gear^.Friction:= _0_995;
       
   697                     gear^.Density:= _1_5;
       
   698                     end;
       
   699          gtBallgun: begin
       
   700                     if gear^.Timer = 0 then gear^.Timer:= 5001;
       
   701                     end;
       
   702          gtRCPlane: begin
       
   703                     if gear^.Timer = 0 then gear^.Timer:= 15000;
       
   704                     gear^.Health:= 3;
       
   705                     gear^.Radius:= 8;
       
   706                     gear^.Tint:= gear^.Hedgehog^.Team^.Clan^.Color shl 8 or $FF
       
   707                     end;
       
   708          gtJetpack: begin
       
   709                     gear^.Health:= 2000;
       
   710                     gear^.Damage:= 100;
       
   711                     gear^.State:= Gear^.State or gstSubmersible
       
   712                     end;
       
   713          gtMolotov: begin
       
   714                     gear^.AdvBounce:= 1;
       
   715                     gear^.Radius:= 6;
       
   716                     gear^.Elasticity:= _0_8;
       
   717                     gear^.Friction:= _0_8;
       
   718                     gear^.Density:= _2
       
   719                     end;
       
   720            gtBirdy: begin
       
   721                     gear^.Radius:= 16; // todo: check
       
   722                     gear^.Health := 2000;
       
   723                     gear^.FlightTime := 2;
       
   724                     gear^.Z:= cCurrHHZ;
       
   725                     end;
       
   726              gtEgg: begin
       
   727                     gear^.AdvBounce:= 1;
       
   728                     gear^.Radius:= 4;
       
   729                     gear^.Elasticity:= _0_6;
       
   730                     gear^.Friction:= _0_96;
       
   731                     gear^.Density:= _1;
       
   732                     if gear^.Timer = 0 then
       
   733                         gear^.Timer:= 3000
       
   734                     end;
       
   735           gtPortal: begin
       
   736                     gear^.ImpactSound:= sndMelonImpact;
       
   737                     gear^.nImpactSounds:= 1;
       
   738                     gear^.Radius:= 17;
       
   739                     // set color
       
   740                     gear^.Tag:= 2 * gear^.Timer;
       
   741                     gear^.Timer:= 15000;
       
   742                     gear^.RenderTimer:= false;
       
   743                     gear^.Health:= 100;
       
   744                     gear^.Sticky:= true;
       
   745                     end;
       
   746            gtPiano: begin
       
   747                     gear^.Radius:= 32;
       
   748                     gear^.Density:= _50;
       
   749                     end;
       
   750      gtSineGunShot: begin
       
   751                     gear^.Radius:= 5;
       
   752                     gear^.Health:= 6000;
       
   753                     end;
       
   754     gtFlamethrower: begin
       
   755                     gear^.Tag:= 10;
       
   756                     if gear^.Timer = 0 then gear^.Timer:= 10;
       
   757                     gear^.Health:= 500;
       
   758                     gear^.Damage:= 100;
       
   759                     end;
       
   760          gtLandGun: begin
       
   761                     gear^.Tag:= 10;
       
   762                     if gear^.Timer = 0 then gear^.Timer:= 10;
       
   763                     gear^.Health:= 1000;
       
   764                     gear^.Damage:= 100;
       
   765                     end;
       
   766      gtPoisonCloud: begin
       
   767                     if gear^.Timer = 0 then gear^.Timer:= 5000;
       
   768                     gear^.WDTimer:= gear^.Timer; // initial timer
       
   769                     gear^.dY:= int2hwfloat(-4 + longint(getRandom(8))) / 1000;
       
   770                     gear^.Tint:= $C0C000C0
       
   771                     end;
       
   772      gtResurrector: begin
       
   773                     gear^.Radius := cResurrectorDist;
       
   774                     gear^.Tag := 0;
       
   775                     gear^.Tint:= $F5DB35FF
       
   776                     end;
       
   777          gtWaterUp: begin
       
   778                     gear^.Tag := 47;
       
   779                     end;
       
   780       gtNapalmBomb: begin
       
   781                     gear^.Elasticity:= _0_8;
       
   782                     gear^.Friction:= _0_8;
       
   783                     if gear^.Timer = 0 then gear^.Timer:= 1000;
       
   784                     gear^.Radius:= 5;
       
   785                     gear^.Density:= _1_5;
       
   786                     end;
       
   787           gtIceGun: begin
       
   788                     gear^.Health:= 1000;
       
   789                     gear^.Radius:= 8;
       
   790                     gear^.Density:= _0;
       
   791                     gear^.Tag:= 0; // sound state: 0 = no sound, 1 = ice beam sound, 2 = idle sound
       
   792                     end;
       
   793          gtCreeper: begin
       
   794                     // TODO: Finish creeper initialization implementation
       
   795                     gear^.Radius:= cHHRadius;
       
   796                     gear^.Elasticity:= _0_35;
       
   797                     gear^.Friction:= _0_93;
       
   798                     gear^.Density:= _5;
       
   799 
       
   800                     gear^.AdvBounce:= 1;
       
   801                     gear^.ImpactSound:= sndAirMineImpact;
       
   802                     gear^.nImpactSounds:= 1;
       
   803                     gear^.Health:= 30;
       
   804                     gear^.Radius:= 8;
       
   805                     gear^.Angle:= 175; // Radius at which it will start "seeking". $FFFFFFFF = unlimited. check is skipped.
       
   806                     gear^.Power:= cMaxWindSpeed.QWordValue div 2; // hwFloat converted. 1/2 g default. defines the "seek" speed when a gear is in range.
       
   807                     gear^.Pos:= cMaxWindSpeed.QWordValue * 3 div 2; // air friction. slows it down when not hitting stuff
       
   808                     if gear^.Timer = 0 then
       
   809                         gear^.Timer:= 5000;
       
   810                     gear^.WDTimer:= gear^.Timer
       
   811                     end;
       
   812          gtMinigun: begin
       
   813                     // Timer. First, it's the timer before shooting. Then it will become the shooting timer and is set to Karma
       
   814                     if gear^.Timer = 0 then
       
   815                         gear^.Timer:= 601;
       
   816                     // minigun shooting time. 1 bullet is fired every 50ms
       
   817                     gear^.Karma:= 3451;
       
   818                     end;
       
   819      gtMinigunBullet: begin
       
   820                     gear^.Radius:= 1;
       
   821                     gear^.Health:= 2;
       
   822                     gear^.Karma:= 5; //impact radius
       
   823                     gear^.Pos:= 0; //uses non-global hit order
       
   824                     gear^.Data:= nil;
       
   825                     end;
       
   826             gtSentry: begin
       
   827                     gear^.Radius:= cHHRadius;
       
   828                     gear^.Health:= cSentryHealth;
       
   829                     gear^.Friction:= _0_999;
       
   830                     gear^.Elasticity:= _0_35;
       
   831                     gear^.Density:= _3;
       
   832                     gear^.Tag:= 0;
       
   833                     gear^.Timer:= 1000;
       
   834                     gear^.WDTimer:= 0;
       
   835                     end;
       
   836     gtGenericFaller:begin
       
   837                     gear^.AdvBounce:= 1;
       
   838                     gear^.Radius:= 1;
       
   839                     gear^.Elasticity:= _0_9;
       
   840                     gear^.Friction:= _0_995;
       
   841                     gear^.Density:= _1;
       
   842                     end;
       
   843         end;
       
   844 end;
   170 
   845 
   171 function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
   846 function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
   172 begin
   847 begin
   173 AddGear:= AddGear(X, Y, Kind, State, dX, dY, Timer, 0);
   848 AddGear:= AddGear(X, Y, Kind, State, dX, dY, Timer, 0);
   174 end;
   849 end;
   175 function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer, newUid: LongWord): PGear;
   850 function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer, newUid: LongWord): PGear;
   176 var gear: PGear;
   851 var gear: PGear;
   177     //c: byte;
   852     //c: byte;
   178     cakeData: PCakeData;
       
   179 begin
   853 begin
   180 if newUid = 0 then
   854 if newUid = 0 then
   181     inc(GCounter);
   855     inc(GCounter);
   182 
   856 
   183 AddFileLog('AddGear: #' + inttostr(GCounter) + ' (' + inttostr(x) + ',' + inttostr(y) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
   857 AddFileLog('AddGear: #' + inttostr(GCounter) + ' (' + inttostr(x) + ',' + inttostr(y) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
   184 
   858 
   185 
       
   186 New(gear);
   859 New(gear);
   187 FillChar(gear^, sizeof(TGear), 0);
   860 
   188 gear^.X:= int2hwFloat(X);
   861 initializeGear(gear, X, Y, Kind, State, dX, dY, Timer, newUid);
   189 gear^.Y:= int2hwFloat(Y);
       
   190 gear^.Target.X:= NoPointX;
       
   191 gear^.Kind := Kind;
       
   192 gear^.State:= State;
       
   193 gear^.Active:= true;
       
   194 gear^.dX:= dX;
       
   195 gear^.dY:= dY;
       
   196 gear^.doStep:= doStepHandlers[Kind];
       
   197 gear^.CollisionIndex:= -1;
       
   198 gear^.Timer:= Timer;
       
   199 if newUid = 0 then
       
   200      gear^.uid:= GCounter
       
   201 else gear^.uid:= newUid;
       
   202 gear^.SoundChannel:= -1;
       
   203 gear^.ImpactSound:= sndNone;
       
   204 gear^.Density:= _1;
       
   205 // Define ammo association, if any.
       
   206 gear^.AmmoType:= GearKindAmmoTypeMap[Kind];
       
   207 gear^.CollisionMask:= lfAll;
       
   208 gear^.Tint:= $FFFFFFFF;
       
   209 gear^.Data:= nil;
       
   210 gear^.Sticky:= false;
       
   211 
       
   212 if CurrentHedgehog <> nil then
       
   213     begin
       
   214     gear^.Hedgehog:= CurrentHedgehog;
       
   215     if (CurrentHedgehog^.Gear <> nil) and (hwRound(CurrentHedgehog^.Gear^.X) = X) and (hwRound(CurrentHedgehog^.Gear^.Y) = Y) then
       
   216         gear^.CollisionMask:= lfNotCurHogCrate
       
   217     end;
       
   218 
       
   219 if (Ammoz[Gear^.AmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0) then
       
   220     gear^.Z:= cHHZ+1
       
   221 else gear^.Z:= cUsualZ;
       
   222 
       
   223 // set gstInBounceEdge if gear spawned inside the bounce world edge
       
   224 if WorldEdge = weBounce then
       
   225     if (hwRound(gear^.X) - Gear^.Radius < leftX) or (hwRound(gear^.X) + Gear^.Radius > rightX) then
       
   226         case gear^.Kind of
       
   227             // list all gears here that could collide with the bounce world edge
       
   228             gtHedgehog,
       
   229             gtFlame,
       
   230             gtMine,
       
   231             gtAirBomb,
       
   232             gtDrill,
       
   233             gtNapalmBomb,
       
   234             gtCase,
       
   235             gtAirMine,
       
   236             gtExplosives,
       
   237             gtGrenade,
       
   238             gtShell,
       
   239             gtBee,
       
   240             gtDynamite,
       
   241             gtClusterBomb,
       
   242             gtMelonPiece,
       
   243             gtCluster,
       
   244             gtMortar,
       
   245             gtKamikaze,
       
   246             gtCake,
       
   247             gtWatermelon,
       
   248             gtGasBomb,
       
   249             gtHellishBomb,
       
   250             gtBall,
       
   251             gtRCPlane,
       
   252             gtSniperRifleShot,
       
   253             gtShotgunShot,
       
   254             gtDEagleShot,
       
   255             gtSineGunShot,
       
   256             gtMinigunBullet,
       
   257             gtEgg,
       
   258             gtPiano,
       
   259             gtSMine,
       
   260             gtSnowball,
       
   261             gtKnife,
       
   262             gtCreeper,
       
   263             gtSentry,
       
   264             gtMolotov,
       
   265             gtFlake,
       
   266             gtGrave,
       
   267             gtPortal,
       
   268             gtTarget:
       
   269             gear^.State := gear^.State or gstInBounceEdge;
       
   270         end;
       
   271 
       
   272 case Kind of
       
   273           gtFlame: Gear^.Boom := 2;  // some additional expl in there are x3, x4 this
       
   274        gtHedgehog: Gear^.Boom := 30;
       
   275            gtMine: Gear^.Boom := 50;
       
   276            gtCase: Gear^.Boom := 25;
       
   277         gtAirMine: Gear^.Boom := 30;
       
   278      gtExplosives: Gear^.Boom := 75;
       
   279         gtGrenade: Gear^.Boom := 50;
       
   280           gtShell: Gear^.Boom := 50;
       
   281             gtBee: Gear^.Boom := 50;
       
   282     gtShotgunShot: Gear^.Boom := 25;
       
   283      gtPickHammer: Gear^.Boom := 6;
       
   284 //           gtRope: Gear^.Boom := 2; could be funny to have rope attaching to hog deal small amount of dmg?
       
   285      gtDEagleShot: Gear^.Boom := 7;
       
   286        gtDynamite: Gear^.Boom := 75;
       
   287     gtClusterBomb: Gear^.Boom := 20;
       
   288      gtMelonPiece,
       
   289         gtCluster: Gear^.Boom := Timer;
       
   290          gtShover: Gear^.Boom := 30;
       
   291       gtFirePunch: Gear^.Boom := 30;
       
   292         gtAirBomb: Gear^.Boom := 30;
       
   293       gtBlowTorch: Gear^.Boom := 2;
       
   294          gtMortar: Gear^.Boom := 20;
       
   295            gtWhip: Gear^.Boom := 30;
       
   296        gtKamikaze: Gear^.Boom := 30; // both shove and explosion
       
   297            gtCake: Gear^.Boom := cakeDmg; // why is cake damage a global constant
       
   298      gtWatermelon: Gear^.Boom := 75;
       
   299     gtHellishBomb: Gear^.Boom := 90;
       
   300           gtDrill: if Gear^.State and gsttmpFlag = 0 then
       
   301                         Gear^.Boom := 50
       
   302                    else Gear^.Boom := 30;
       
   303            gtBall: Gear^.Boom := 40;
       
   304         gtRCPlane: Gear^.Boom := 25;
       
   305 // sniper rifle is distance linked, this Boom is just an arbitrary scaling factor applied to timer-based-damage
       
   306 // because, eh, why not..
       
   307 gtSniperRifleShot: Gear^.Boom := 100000;
       
   308             gtEgg: Gear^.Boom := 10;
       
   309           gtPiano: Gear^.Boom := 80;
       
   310         gtGasBomb: Gear^.Boom := 20;
       
   311     gtSineGunShot: Gear^.Boom := 35;
       
   312           gtSMine: Gear^.Boom := 30;
       
   313     gtSnowball: Gear^.Boom := 200000; // arbitrary scaling for the shove
       
   314          gtHammer: if cDamageModifier > _1 then // scale it based on cDamageModifier?
       
   315                          Gear^.Boom := 2
       
   316                     else Gear^.Boom := 3;
       
   317     gtPoisonCloud: Gear^.Boom := 20;
       
   318           gtKnife: Gear^.Boom := 40000; // arbitrary scaling factor since impact-based
       
   319         gtCreeper: Gear^.Boom := 100;
       
   320   gtMinigunBullet: Gear^.Boom := 2;
       
   321          gtSentry: Gear^.Boom := 40;
       
   322     end;
       
   323 
       
   324 case Kind of
       
   325      gtGrenade,
       
   326      gtClusterBomb,
       
   327      gtGasBomb: begin
       
   328                 gear^.ImpactSound:= sndGrenadeImpact;
       
   329                 gear^.nImpactSounds:= 1;
       
   330                 gear^.AdvBounce:= 1;
       
   331                 gear^.Radius:= 5;
       
   332                 gear^.Elasticity:= _0_8;
       
   333                 gear^.Friction:= _0_8;
       
   334                 gear^.Density:= _1_5;
       
   335                 gear^.RenderTimer:= true;
       
   336                 if gear^.Timer = 0 then
       
   337                     gear^.Timer:= 3000
       
   338                 end;
       
   339   gtWatermelon: begin
       
   340                 gear^.ImpactSound:= sndMelonImpact;
       
   341                 gear^.nImpactSounds:= 1;
       
   342                 gear^.AdvBounce:= 1;
       
   343                 gear^.Radius:= 6;
       
   344                 gear^.Elasticity:= _0_8;
       
   345                 gear^.Friction:= _0_995;
       
   346                 gear^.Density:= _2;
       
   347                 gear^.RenderTimer:= true;
       
   348                 if gear^.Timer = 0 then
       
   349                     gear^.Timer:= 3000
       
   350                 end;
       
   351   gtMelonPiece: begin
       
   352                 gear^.AdvBounce:= 1;
       
   353                 gear^.Density:= _2;
       
   354                 gear^.Elasticity:= _0_8;
       
   355                 gear^.Friction:= _0_995;
       
   356                 gear^.Radius:= 4
       
   357                 end;
       
   358     gtHedgehog: begin
       
   359                 gear^.AdvBounce:= 1;
       
   360                 gear^.Radius:= cHHRadius;
       
   361                 gear^.Elasticity:= _0_35;
       
   362                 gear^.Friction:= _0_999;
       
   363                 gear^.Angle:= cMaxAngle div 2;
       
   364                 gear^.Density:= _3;
       
   365                 gear^.Z:= cHHZ;
       
   366                 if (GameFlags and gfAISurvival) <> 0 then
       
   367                     if gear^.Hedgehog^.BotLevel > 0 then
       
   368                         gear^.Hedgehog^.Effects[heResurrectable] := 1;
       
   369                 if (GameFlags and gfArtillery) <> 0 then
       
   370                     gear^.Hedgehog^.Effects[heArtillery] := 1;
       
   371                 // this would presumably be set in the frontend
       
   372                 // if we weren't going to do that yet, would need to reinit GetRandom
       
   373                 // oh, and, randomising slightly R and B might be nice too.
       
   374                 //gear^.Tint:= $fa00efff or ((random(80)+128) shl 16)
       
   375                 //gear^.Tint:= $faa4efff
       
   376                 //gear^.Tint:= (($e0+random(32)) shl 24) or
       
   377                 //             ((random(80)+128) shl 16) or
       
   378                 //             (($d5+random(32)) shl 8) or $ff
       
   379                 {c:= GetRandom(32);
       
   380                 gear^.Tint:= (($e0+c) shl 24) or
       
   381                              ((GetRandom(90)+128) shl 16) or
       
   382                              (($d5+c) shl 8) or $ff}
       
   383                 end;
       
   384    gtParachute: begin
       
   385                 gear^.Tag:= 1; // hog face dir. 1 = right, -1 = left
       
   386                 gear^.Z:= cCurrHHZ;
       
   387                 end;
       
   388        gtShell: begin
       
   389                 gear^.Elasticity:= _0_8;
       
   390                 gear^.Friction:= _0_8;
       
   391                 gear^.Radius:= 4;
       
   392                 gear^.Density:= _1;
       
   393                 gear^.AdvBounce:= 1;
       
   394                 end;
       
   395        gtSnowball: begin
       
   396                 gear^.ImpactSound:= sndMudballImpact;
       
   397                 gear^.nImpactSounds:= 1;
       
   398                 gear^.Radius:= 4;
       
   399                 gear^.Density:= _0_5;
       
   400                 gear^.AdvBounce:= 1;
       
   401                 gear^.Elasticity:= _0_8;
       
   402                 gear^.Friction:= _0_8;
       
   403                 end;
       
   404 
       
   405      gtFlake: begin
       
   406                 with Gear^ do
       
   407                     begin
       
   408                     Pos:= 0;
       
   409                     Radius:= 1;
       
   410                     DirAngle:= random(360);
       
   411                     Sticky:= true;
       
   412                     if State and gstTmpFlag = 0 then
       
   413                         begin
       
   414                         dx.isNegative:= GetRandom(2) = 0;
       
   415                         dx.QWordValue:= QWord($40DA) * GetRandom(10000) * 8;
       
   416                         dy.isNegative:= false;
       
   417                         dy.QWordValue:= QWord($3AD3) * GetRandom(7000) * 8;
       
   418                         if GetRandom(2) = 0 then
       
   419                             dx := -dx;
       
   420                         Tint:= $FFFFFFFF
       
   421                         end
       
   422                     else
       
   423                         Tint:= (ExplosionBorderColor shr RShift and $FF shl 24) or
       
   424                                (ExplosionBorderColor shr GShift and $FF shl 16) or
       
   425                                (ExplosionBorderColor shr BShift and $FF shl 8) or $FF;
       
   426                     State:= State or gstInvisible;
       
   427                     // use health field to store current frameticks
       
   428                     if vobFrameTicks > 0 then
       
   429                         Health:= random(vobFrameTicks)
       
   430                     else
       
   431                         Health:= 0;
       
   432                     // use timer to store currently displayed frame index
       
   433                     if gear^.Timer = 0 then Timer:= random(vobFramesCount);
       
   434                     Damage:= (random(2) * 2 - 1) * (vobVelocity + random(vobVelocity)) * 8
       
   435                     end
       
   436                 end;
       
   437        gtGrave: begin
       
   438                 gear^.ImpactSound:= sndGraveImpact;
       
   439                 gear^.nImpactSounds:= 1;
       
   440                 gear^.Radius:= 10;
       
   441                 gear^.Elasticity:= _0_6;
       
   442                 gear^.Z:= 1;
       
   443                 end;
       
   444          gtBee: begin
       
   445                 gear^.Radius:= 5;
       
   446                 if gear^.Timer = 0 then gear^.Timer:= 500;
       
   447                 gear^.RenderTimer:= true;
       
   448                 gear^.Elasticity:= _0_9;
       
   449                 gear^.Tag:= 0;
       
   450                 gear^.State:= Gear^.State or gstSubmersible
       
   451                 end;
       
   452    gtSeduction: begin
       
   453                 gear^.Radius:= cSeductionDist;
       
   454                 end;
       
   455  gtShotgunShot: begin
       
   456                 if gear^.Timer = 0 then gear^.Timer:= 900;
       
   457                 gear^.Radius:= 2
       
   458                 end;
       
   459   gtPickHammer: begin
       
   460                 gear^.Radius:= 10;
       
   461                 if gear^.Timer = 0 then gear^.Timer:= 4000
       
   462                 end;
       
   463    gtHammerHit: begin
       
   464                 gear^.Radius:= 8;
       
   465                 if gear^.Timer = 0 then gear^.Timer:= 125
       
   466                 end;
       
   467         gtRope: begin
       
   468                 gear^.Radius:= 3;
       
   469                 gear^.Friction:= _450 * _0_01 * cRopePercent;
       
   470                 RopePoints.Count:= 0;
       
   471                 gear^.Tint:= $D8D8D8FF;
       
   472                 gear^.Tag:= 0; // normal rope render
       
   473                 gear^.CollisionMask:= lfNotCurHogCrate //lfNotObjMask or lfNotHHObjMask;
       
   474                 end;
       
   475         gtMine: begin
       
   476                 gear^.ImpactSound:= sndMineImpact;
       
   477                 gear^.nImpactSounds:= 1;
       
   478                 gear^.Health:= 10;
       
   479                 gear^.State:= gear^.State or gstMoving;
       
   480                 gear^.Radius:= 2;
       
   481                 gear^.Elasticity:= _0_55;
       
   482                 gear^.Friction:= _0_995;
       
   483                 gear^.Density:= _1;
       
   484                 if gear^.Timer = 0 then
       
   485                     begin
       
   486                     if cMinesTime < 0 then
       
   487                         begin
       
   488                         gear^.Timer:= getrandom(51)*100;
       
   489                         gear^.Karma:= 1;
       
   490                         end
       
   491                     else
       
   492                         gear^.Timer:= cMinesTime;
       
   493                     end;
       
   494                 gear^.RenderTimer:= true;
       
   495                 end;
       
   496      gtAirMine: begin
       
   497                 gear^.AdvBounce:= 1;
       
   498                 gear^.ImpactSound:= sndAirMineImpact;
       
   499                 gear^.nImpactSounds:= 1;
       
   500                 gear^.Health:= 30;
       
   501                 gear^.State:= gear^.State or gstMoving or gstNoGravity or gstSubmersible;
       
   502                 gear^.Radius:= 8;
       
   503                 gear^.Elasticity:= _0_55;
       
   504                 gear^.Friction:= _0_995;
       
   505                 gear^.Density:= _1;
       
   506                 gear^.Angle:= 175; // Radius at which air bombs will start "seeking". $FFFFFFFF = unlimited. check is skipped.
       
   507                 gear^.Power:= cMaxWindSpeed.QWordValue div 2; // hwFloat converted. 1/2 g default. defines the "seek" speed when a gear is in range.
       
   508                 gear^.Pos:= cMaxWindSpeed.QWordValue * 3 div 2; // air friction. slows it down when not hitting stuff
       
   509                 gear^.Tag:= 0;
       
   510                 if gear^.Timer = 0 then
       
   511                     begin
       
   512                     if cMinesTime < 0 then
       
   513                         begin
       
   514                         gear^.Timer:= getrandom(13)*100;
       
   515                         gear^.Karma:= 1;
       
   516                         end
       
   517                     else
       
   518                         gear^.Timer:= cMinesTime div 4;
       
   519                     end;
       
   520                 gear^.RenderTimer:= true;
       
   521                 gear^.WDTimer:= gear^.Timer
       
   522                 end;
       
   523        gtSMine: begin
       
   524                 gear^.Health:= 10;
       
   525                 gear^.State:= gear^.State or gstMoving;
       
   526                 gear^.Radius:= 2;
       
   527                 gear^.Elasticity:= _0_55;
       
   528                 gear^.Friction:= _0_995;
       
   529                 gear^.Density:= _1_6;
       
   530                 gear^.AdvBounce:= 1;
       
   531                 gear^.Sticky:= true;
       
   532                 if gear^.Timer = 0 then gear^.Timer:= 500;
       
   533                 gear^.RenderTimer:= true;
       
   534                 end;
       
   535        gtKnife: begin
       
   536                 gear^.ImpactSound:= sndKnifeImpact;
       
   537                 gear^.AdvBounce:= 1;
       
   538                 gear^.Elasticity:= _0_8;
       
   539                 gear^.Friction:= _0_8;
       
   540                 gear^.Density:= _4;
       
   541                 gear^.Radius:= 7;
       
   542                 gear^.Sticky:= true;
       
   543                 end;
       
   544         gtCase: begin
       
   545                 gear^.ImpactSound:= sndCaseImpact;
       
   546                 gear^.nImpactSounds:= 1;
       
   547                 gear^.Radius:= 16;
       
   548                 gear^.Elasticity:= _0_3;
       
   549                 if gear^.Timer = 0 then gear^.Timer:= 500
       
   550                 end;
       
   551   gtExplosives: begin
       
   552                 gear^.AdvBounce:= 1;
       
   553                 if GameType in [gmtDemo, gmtRecord] then
       
   554                     gear^.RenderHealth:= true;
       
   555                 gear^.ImpactSound:= sndGrenadeImpact;
       
   556                 gear^.nImpactSounds:= 1;
       
   557                 gear^.Radius:= 16;
       
   558                 gear^.Elasticity:= _0_4;
       
   559                 gear^.Friction:= _0_995;
       
   560                 gear^.Density:= _6;
       
   561                 gear^.Health:= cBarrelHealth;
       
   562                 gear^.Z:= cHHZ-1
       
   563                 end;
       
   564   gtDEagleShot: begin
       
   565                 gear^.Radius:= 1;
       
   566                 gear^.Health:= 50;
       
   567                 gear^.Data:= nil;
       
   568                 end;
       
   569   gtSniperRifleShot: begin
       
   570                 gear^.Radius:= 1;
       
   571                 gear^.Health:= 50
       
   572                 end;
       
   573     gtDynamite: begin
       
   574                 gear^.ImpactSound:= sndDynamiteImpact;
       
   575                 gear^.nImpactSounds:= 1;
       
   576                 gear^.Radius:= 3;
       
   577                 gear^.Elasticity:= _0_55;
       
   578                 gear^.Friction:= _0_03;
       
   579                 gear^.Density:= _2;
       
   580                 if gear^.Timer = 0 then gear^.Timer:= 5000;
       
   581                 end;
       
   582      gtCluster: begin
       
   583                 gear^.AdvBounce:= 1;
       
   584                 gear^.Elasticity:= _0_8;
       
   585                 gear^.Friction:= _0_8;
       
   586                 gear^.Radius:= 2;
       
   587                 gear^.Density:= _1_5;
       
   588                 gear^.RenderTimer:= true
       
   589                 end;
       
   590       gtShover: begin
       
   591                 gear^.Radius:= 20;
       
   592                 gear^.Tag:= 0;
       
   593                 gear^.Timer:= 50;
       
   594                 end;
       
   595        gtFlame: begin
       
   596                 gear^.Tag:= GetRandom(32);
       
   597                 gear^.Radius:= 1;
       
   598                 gear^.Health:= 5;
       
   599                 gear^.Density:= _1;
       
   600                 gear^.FlightTime:= 9999999; // determines whether in-air flames do damage. disabled by default
       
   601                 if (gear^.dY.QWordValue = 0) and (gear^.dX.QWordValue = 0) then
       
   602                     begin
       
   603                     gear^.dY:= (getrandomf - _0_8) * _0_03;
       
   604                     gear^.dX:= (getrandomf - _0_5) * _0_4
       
   605                     end
       
   606                 end;
       
   607    gtFirePunch: begin
       
   608                 if gear^.Timer = 0 then gear^.Timer:= 3000;
       
   609                 gear^.Radius:= 15;
       
   610                 gear^.Tag:= Y
       
   611                 end;
       
   612    gtAirAttack: begin
       
   613                 gear^.Health:= 6;
       
   614                 gear^.Damage:= 30;
       
   615                 gear^.Z:= cHHZ+2;
       
   616                 gear^.Karma:= 0; // for sound effect: 0 = normal, 1 = underwater
       
   617                 gear^.Radius:= 150;
       
   618                 gear^.FlightTime:= 0; // for timeout in weWrap
       
   619                 gear^.Power:= 0; // count number of wraps in weWrap
       
   620                 gear^.WDTimer:= 0; // number of required wraps
       
   621                 gear^.Density:= _19;
       
   622                 gear^.Tint:= gear^.Hedgehog^.Team^.Clan^.Color shl 8 or $FF
       
   623                 end;
       
   624      gtAirBomb: begin
       
   625                 gear^.AdvBounce:= 1;
       
   626                 gear^.Radius:= 5;
       
   627                 gear^.Density:= _2;
       
   628                 gear^.Elasticity:= _0_55;
       
   629                 gear^.Friction:= _0_995
       
   630                 end;
       
   631    gtBlowTorch: begin
       
   632                 gear^.Radius:= cHHRadius + cBlowTorchC - 1;
       
   633                 if gear^.Timer = 0 then gear^.Timer:= 7500
       
   634                 end;
       
   635     gtSwitcher: begin
       
   636                 gear^.Z:= cCurrHHZ
       
   637                 end;
       
   638       gtTarget: begin
       
   639                 gear^.ImpactSound:= sndGrenadeImpact;
       
   640                 gear^.nImpactSounds:= 1;
       
   641                 gear^.Radius:= 10;
       
   642                 gear^.Elasticity:= _0_3;
       
   643                 end;
       
   644       gtTardis: begin
       
   645                 gear^.Pos:= 1; // tardis phase
       
   646                 gear^.Tag:= 0; // 1 = hedgehog died, disappeared, took damage or moved
       
   647                 gear^.Z:= cCurrHHZ+1;
       
   648                 end;
       
   649       gtMortar: begin
       
   650                 gear^.AdvBounce:= 1;
       
   651                 gear^.Radius:= 4;
       
   652                 gear^.Elasticity:= _0_2;
       
   653                 gear^.Friction:= _0_08;
       
   654                 gear^.Density:= _1;
       
   655                 end;
       
   656         gtWhip: gear^.Radius:= 20;
       
   657       gtHammer: gear^.Radius:= 20;
       
   658     gtKamikaze: begin
       
   659                 gear^.Health:= 2048;
       
   660                 gear^.Radius:= 20
       
   661                 end;
       
   662         gtCake: begin
       
   663                 gear^.Health:= 2048;
       
   664                 gear^.Radius:= 7;
       
   665                 gear^.Z:= cOnHHZ;
       
   666                 gear^.RenderTimer:= false;
       
   667                 gear^.DirAngle:= -90 * hwSign(Gear^.dX);
       
   668                 gear^.FlightTime:= 100; // (roughly) ticks spent dropping, used to skip getting up anim when stuck.
       
   669                                         // Initially set to a high value so cake has at least one getting up anim.
       
   670                 if not dX.isNegative then
       
   671                     gear^.Angle:= 1
       
   672                 else
       
   673                     gear^.Angle:= 3;
       
   674                 New(cakeData);
       
   675                 gear^.Data:= Pointer(cakeData);
       
   676                 end;
       
   677  gtHellishBomb: begin
       
   678                 gear^.ImpactSound:= sndHellishImpact1;
       
   679                 gear^.nImpactSounds:= 4;
       
   680                 gear^.AdvBounce:= 1;
       
   681                 gear^.Radius:= 4;
       
   682                 gear^.Elasticity:= _0_5;
       
   683                 gear^.Friction:= _0_96;
       
   684                 gear^.Density:= _1_5;
       
   685                 gear^.RenderTimer:= true;
       
   686                 if gear^.Timer = 0 then gear^.Timer:= 5000
       
   687                 end;
       
   688        gtDrill: begin
       
   689                 gear^.AdvBounce:= 1;
       
   690                 gear^.Elasticity:= _0_8;
       
   691                 gear^.Friction:= _0_8;
       
   692                 if gear^.Timer = 0 then
       
   693                     gear^.Timer:= 5000;
       
   694                 // Tag for drill strike. if 1 then first impact occured already
       
   695                 gear^.Tag := 0;
       
   696                 // Pos for state. If 1, drill is drilling
       
   697                 gear^.Pos := 0;
       
   698                 gear^.Radius:= 4;
       
   699                 gear^.Density:= _1;
       
   700                 end;
       
   701         gtBall: begin
       
   702                 gear^.ImpactSound:= sndGrenadeImpact;
       
   703                 gear^.nImpactSounds:= 1;
       
   704                 gear^.AdvBounce:= 1;
       
   705                 gear^.Radius:= 5;
       
   706                 gear^.Tag:= random(8);
       
   707                 if gear^.Timer = 0 then gear^.Timer:= 5000;
       
   708                 gear^.Elasticity:= _0_7;
       
   709                 gear^.Friction:= _0_995;
       
   710                 gear^.Density:= _1_5;
       
   711                 end;
       
   712      gtBallgun: begin
       
   713                 if gear^.Timer = 0 then gear^.Timer:= 5001;
       
   714                 end;
       
   715      gtRCPlane: begin
       
   716                 if gear^.Timer = 0 then gear^.Timer:= 15000;
       
   717                 gear^.Health:= 3;
       
   718                 gear^.Radius:= 8;
       
   719                 gear^.Tint:= gear^.Hedgehog^.Team^.Clan^.Color shl 8 or $FF
       
   720                 end;
       
   721      gtJetpack: begin
       
   722                 gear^.Health:= 2000;
       
   723                 gear^.Damage:= 100;
       
   724                 gear^.State:= Gear^.State or gstSubmersible
       
   725                 end;
       
   726      gtMolotov: begin
       
   727                 gear^.AdvBounce:= 1;
       
   728                 gear^.Radius:= 6;
       
   729                 gear^.Elasticity:= _0_8;
       
   730                 gear^.Friction:= _0_8;
       
   731                 gear^.Density:= _2
       
   732                 end;
       
   733        gtBirdy: begin
       
   734                 gear^.Radius:= 16; // todo: check
       
   735                 gear^.Health := 2000;
       
   736                 gear^.FlightTime := 2;
       
   737                 gear^.Z:= cCurrHHZ;
       
   738                 end;
       
   739          gtEgg: begin
       
   740                 gear^.AdvBounce:= 1;
       
   741                 gear^.Radius:= 4;
       
   742                 gear^.Elasticity:= _0_6;
       
   743                 gear^.Friction:= _0_96;
       
   744                 gear^.Density:= _1;
       
   745                 if gear^.Timer = 0 then
       
   746                     gear^.Timer:= 3000
       
   747                 end;
       
   748       gtPortal: begin
       
   749                 gear^.ImpactSound:= sndMelonImpact;
       
   750                 gear^.nImpactSounds:= 1;
       
   751                 gear^.Radius:= 17;
       
   752                 // set color
       
   753                 gear^.Tag:= 2 * gear^.Timer;
       
   754                 gear^.Timer:= 15000;
       
   755                 gear^.RenderTimer:= false;
       
   756                 gear^.Health:= 100;
       
   757                 gear^.Sticky:= true;
       
   758                 end;
       
   759        gtPiano: begin
       
   760                 gear^.Radius:= 32;
       
   761                 gear^.Density:= _50;
       
   762                 end;
       
   763  gtSineGunShot: begin
       
   764                 gear^.Radius:= 5;
       
   765                 gear^.Health:= 6000;
       
   766                 end;
       
   767 gtFlamethrower: begin
       
   768                 gear^.Tag:= 10;
       
   769                 if gear^.Timer = 0 then gear^.Timer:= 10;
       
   770                 gear^.Health:= 500;
       
   771                 gear^.Damage:= 100;
       
   772                 end;
       
   773      gtLandGun: begin
       
   774                 gear^.Tag:= 10;
       
   775                 if gear^.Timer = 0 then gear^.Timer:= 10;
       
   776                 gear^.Health:= 1000;
       
   777                 gear^.Damage:= 100;
       
   778                 end;
       
   779  gtPoisonCloud: begin
       
   780                 if gear^.Timer = 0 then gear^.Timer:= 5000;
       
   781                 gear^.WDTimer:= gear^.Timer; // initial timer
       
   782                 gear^.dY:= int2hwfloat(-4 + longint(getRandom(8))) / 1000;
       
   783                 gear^.Tint:= $C0C000C0
       
   784                 end;
       
   785  gtResurrector: begin
       
   786                 gear^.Radius := cResurrectorDist;
       
   787                 gear^.Tag := 0;
       
   788                 gear^.Tint:= $F5DB35FF
       
   789                 end;
       
   790      gtWaterUp: begin
       
   791                 gear^.Tag := 47;
       
   792                 end;
       
   793   gtNapalmBomb: begin
       
   794                 gear^.Elasticity:= _0_8;
       
   795                 gear^.Friction:= _0_8;
       
   796                 if gear^.Timer = 0 then gear^.Timer:= 1000;
       
   797                 gear^.Radius:= 5;
       
   798                 gear^.Density:= _1_5;
       
   799                 end;
       
   800       gtIceGun: begin
       
   801                 gear^.Health:= 1000;
       
   802                 gear^.Radius:= 8;
       
   803                 gear^.Density:= _0;
       
   804                 gear^.Tag:= 0; // sound state: 0 = no sound, 1 = ice beam sound, 2 = idle sound
       
   805                 end;
       
   806      gtCreeper: begin
       
   807                 // TODO: Finish creeper initialization implementation
       
   808                 gear^.Radius:= cHHRadius;
       
   809                 gear^.Elasticity:= _0_35;
       
   810                 gear^.Friction:= _0_93;
       
   811                 gear^.Density:= _5;
       
   812 
       
   813                 gear^.AdvBounce:= 1;
       
   814                 gear^.ImpactSound:= sndAirMineImpact;
       
   815                 gear^.nImpactSounds:= 1;
       
   816                 gear^.Health:= 30;
       
   817                 gear^.Radius:= 8;
       
   818                 gear^.Angle:= 175; // Radius at which it will start "seeking". $FFFFFFFF = unlimited. check is skipped.
       
   819                 gear^.Power:= cMaxWindSpeed.QWordValue div 2; // hwFloat converted. 1/2 g default. defines the "seek" speed when a gear is in range.
       
   820                 gear^.Pos:= cMaxWindSpeed.QWordValue * 3 div 2; // air friction. slows it down when not hitting stuff
       
   821                 if gear^.Timer = 0 then
       
   822                     gear^.Timer:= 5000;
       
   823                 gear^.WDTimer:= gear^.Timer
       
   824                 end;
       
   825      gtMinigun: begin
       
   826                 // Timer. First, it's the timer before shooting. Then it will become the shooting timer and is set to Karma
       
   827                 if gear^.Timer = 0 then
       
   828                     gear^.Timer:= 601;
       
   829                 // minigun shooting time. 1 bullet is fired every 50ms
       
   830                 gear^.Karma:= 3451;
       
   831                 end;
       
   832  gtMinigunBullet: begin
       
   833                 gear^.Radius:= 1;
       
   834                 gear^.Health:= 2;
       
   835                 gear^.Karma:= 5; //impact radius
       
   836                 gear^.Pos:= 0; //uses non-global hit order
       
   837                 gear^.Data:= nil;
       
   838                 end;
       
   839         gtSentry: begin
       
   840                 gear^.Radius:= cHHRadius;
       
   841                 gear^.Health:= cSentryHealth;
       
   842                 gear^.Friction:= _0_999;
       
   843                 gear^.Elasticity:= _0_35;
       
   844                 gear^.Density:= _3;
       
   845                 gear^.Tag:= 0;
       
   846                 gear^.Timer:= 1000;
       
   847                 gear^.WDTimer:= 0;
       
   848                 end;
       
   849 gtGenericFaller:begin
       
   850                 gear^.AdvBounce:= 1;
       
   851                 gear^.Radius:= 1;
       
   852                 gear^.Elasticity:= _0_9;
       
   853                 gear^.Friction:= _0_995;
       
   854                 gear^.Density:= _1;
       
   855                 end;
       
   856     end;
       
   857 
   862 
   858 InsertGearToList(gear);
   863 InsertGearToList(gear);
   859 AddGear:= gear;
   864 AddGear:= gear;
   860 
   865 
   861 ScriptCall('onGearAdd', gear^.uid);
   866 ScriptCall('onGearAdd', gear^.uid);