hedgewars/uGearsHandlersMess.pas
branchui-scaling
changeset 15288 c4fd2813b127
parent 15283 16f389fcd462
child 15301 b5171e6c94a4
equal deleted inserted replaced
13395:0135e64c6c66 15288:c4fd2813b127
    30 unit uGearsHandlersMess;
    30 unit uGearsHandlersMess;
    31 interface
    31 interface
    32 uses uTypes, uFloat;
    32 uses uTypes, uFloat;
    33 
    33 
    34 procedure doStepPerPixel(Gear: PGear; step: TGearStepProcedure; onlyCheckIfChanged: boolean);
    34 procedure doStepPerPixel(Gear: PGear; step: TGearStepProcedure; onlyCheckIfChanged: boolean);
    35 procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
    35 procedure makeHogsWorry(x, y: hwFloat; r: LongInt; gearType: TGearType);
    36 procedure HideHog(HH: PHedgehog);
    36 procedure HideHog(HH: PHedgehog);
    37 procedure doStepDrowningGear(Gear: PGear);
    37 procedure doStepDrowningGear(Gear: PGear);
    38 procedure doStepFallingGear(Gear: PGear);
    38 procedure doStepFallingGear(Gear: PGear);
    39 procedure doStepBomb(Gear: PGear);
    39 procedure doStepBomb(Gear: PGear);
    40 procedure doStepMolotov(Gear: PGear);
    40 procedure doStepMolotov(Gear: PGear);
   113 procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
   113 procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
   114 procedure doStepMovingPortal_real(Gear: PGear);
   114 procedure doStepMovingPortal_real(Gear: PGear);
   115 procedure doStepMovingPortal(Gear: PGear);
   115 procedure doStepMovingPortal(Gear: PGear);
   116 procedure doStepPortalShot(newPortal: PGear);
   116 procedure doStepPortalShot(newPortal: PGear);
   117 procedure doStepPiano(Gear: PGear);
   117 procedure doStepPiano(Gear: PGear);
       
   118 procedure doStepPianoWork(Gear: PGear);
   118 procedure doStepSineGunShotWork(Gear: PGear);
   119 procedure doStepSineGunShotWork(Gear: PGear);
   119 procedure doStepSineGunShot(Gear: PGear);
   120 procedure doStepSineGunShot(Gear: PGear);
   120 procedure doStepFlamethrowerWork(Gear: PGear);
   121 procedure doStepFlamethrowerWork(Gear: PGear);
   121 procedure doStepFlamethrower(Gear: PGear);
   122 procedure doStepFlamethrower(Gear: PGear);
   122 procedure doStepLandGunWork(Gear: PGear);
   123 procedure doStepLandGunWork(Gear: PGear);
   126 procedure doStepHammerHitWork(Gear: PGear);
   127 procedure doStepHammerHitWork(Gear: PGear);
   127 procedure doStepHammerHit(Gear: PGear);
   128 procedure doStepHammerHit(Gear: PGear);
   128 procedure doStepResurrectorWork(Gear: PGear);
   129 procedure doStepResurrectorWork(Gear: PGear);
   129 procedure doStepResurrector(Gear: PGear);
   130 procedure doStepResurrector(Gear: PGear);
   130 procedure doStepNapalmBomb(Gear: PGear);
   131 procedure doStepNapalmBomb(Gear: PGear);
   131 //procedure doStepStructure(Gear: PGear);
       
   132 procedure doStepTardisWarp(Gear: PGear);
   132 procedure doStepTardisWarp(Gear: PGear);
   133 procedure doStepTardis(Gear: PGear);
   133 procedure doStepTardis(Gear: PGear);
   134 procedure updateFuel(Gear: PGear);
   134 procedure updateFuel(Gear: PGear);
   135 procedure updateTarget(Gear:PGear; newX, newY:HWFloat);
   135 procedure updateTarget(Gear:PGear; newX, newY:HWFloat);
   136 procedure doStepIceGun(Gear: PGear);
   136 procedure doStepIceGun(Gear: PGear);
   137 procedure doStepAddAmmo(Gear: PGear);
   137 procedure doStepAddAmmo(Gear: PGear);
   138 procedure doStepGenericFaller(Gear: PGear);
   138 procedure doStepGenericFaller(Gear: PGear);
   139 //procedure doStepCreeper(Gear: PGear);
   139 procedure doStepCreeper(Gear: PGear);
   140 procedure doStepKnife(Gear: PGear);
   140 procedure doStepKnife(Gear: PGear);
   141 procedure doStepDuck(Gear: PGear);
       
   142 procedure doStepMinigunWork(Gear: PGear);
   141 procedure doStepMinigunWork(Gear: PGear);
   143 procedure doStepMinigun(Gear: PGear);
   142 procedure doStepMinigun(Gear: PGear);
   144 procedure doStepMinigunBullet(Gear: PGear);
   143 procedure doStepMinigunBullet(Gear: PGear);
   145 
   144 
   146 var
   145 var
   200         or ((Gear^.State and gstMoving) = 0) then
   199         or ((Gear^.State and gstMoving) = 0) then
   201             break;
   200             break;
   202         end;
   201         end;
   203 end;
   202 end;
   204 
   203 
   205 procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
   204 procedure makeHogsWorry(x, y: hwFloat; r: LongInt; gearType: TGearType);
   206 var
   205 var
   207     gi: PGear;
   206     gi: PGear;
   208     d: LongInt;
   207     d: LongInt;
       
   208     grenadeTaunt: boolean;
   209 begin
   209 begin
   210     gi := GearsList;
   210     gi := GearsList;
   211     while gi <> nil do
   211     while gi <> nil do
   212         begin
   212         begin
   213         if (gi^.Kind = gtHedgehog) then
   213         if (gi^.Kind = gtHedgehog) then
   214             begin
   214             begin
   215             d := r - hwRound(Distance(gi^.X - x, gi^.Y - y));
   215             d := r - hwRound(Distance(gi^.X - x, gi^.Y - y));
   216             if (d > 1) and (gi^.Hedgehog^.Effects[heInvulnerable] = 0) and (GetRandom(2) = 0) then
   216             if (d > 1) and (gi^.Hedgehog^.Effects[heInvulnerable] = 0) and (GetRandom(2) = 0) then
   217                 begin
   217                 begin
   218                 if (CurrentHedgehog^.Gear = gi) then
   218                 if (CurrentHedgehog^.Gear = gi) then
   219                     PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack)
   219                     if (CurrentHedgehog^.Gear^.FlightTime = 0) then
       
   220                         case random(4) of
       
   221                         0: PlaySoundV(sndWhatThe, gi^.Hedgehog^.Team^.voicepack);
       
   222                         1: PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack);
       
   223                         2: PlaySoundV(sndRunAway, gi^.Hedgehog^.Team^.voicepack);
       
   224                         3: PlaySoundV(sndRunAway, gi^.Hedgehog^.Team^.voicepack);
       
   225                         end
       
   226                     else
       
   227                         if random(4) = 0 then
       
   228                            PlaySoundV(sndWhatThe, gi^.Hedgehog^.Team^.voicepack)
       
   229                         else
       
   230                            PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack)
   220 
   231 
   221                 else
   232                 else
   222                     begin
   233                     begin
   223                     if ((gi^.State and gstMoving) = 0) and (gi^.Hedgehog^.Effects[heFrozen] = 0) then
   234                     if ((gi^.State and gstMoving) = 0) and (gi^.Hedgehog^.Effects[heFrozen] = 0) then
   224                         begin
   235                         begin
   225                         gi^.dX.isNegative:= X<gi^.X;
   236                         gi^.dX.isNegative:= X<gi^.X;
   226                         gi^.State := gi^.State or gstLoser;
   237                         gi^.State := gi^.State or gstLoser;
   227                         end;
   238                         end;
   228 
   239 
   229                     if d > r div 2 then
   240                     grenadeTaunt:= false;
   230                         PlaySoundV(sndNooo, gi^.Hedgehog^.Team^.voicepack)
   241                     if (gearType = gtGrenade) then
       
   242                         grenadeTaunt:= random(2) = 0;
       
   243 
       
   244                     if grenadeTaunt then
       
   245                         PlaySoundV(sndGrenade, gi^.Hedgehog^.Team^.voicepack)
   231                     else
   246                     else
   232                         PlaySoundV(sndUhOh, gi^.Hedgehog^.Team^.voicepack);
   247                         if d > r div 2 then
       
   248                             if random(3) = 0 then
       
   249                                 PlaySoundV(sndWhatThe, gi^.Hedgehog^.Team^.voicepack)
       
   250                             else
       
   251                                 PlaySoundV(sndNooo, gi^.Hedgehog^.Team^.voicepack)
       
   252                         else
       
   253                             PlaySoundV(sndUhOh, gi^.Hedgehog^.Team^.voicepack);
       
   254 
   233                     end;
   255                     end;
   234                 end;
   256                 end;
   235             end;
   257             end;
   236 
   258 
   237         gi := gi^.NextGear
   259         gi := gi^.NextGear
   285 
   307 
   286 Gear^.Y := Gear^.Y + cDrownSpeed;
   308 Gear^.Y := Gear^.Y + cDrownSpeed;
   287 
   309 
   288 if cWaterLine > hwRound(Gear^.Y) + Gear^.Radius then
   310 if cWaterLine > hwRound(Gear^.Y) + Gear^.Radius then
   289     begin
   311     begin
   290     if LongInt(leftX) + Gear^.Radius > hwRound(Gear^.X) then
   312     if leftX + Gear^.Radius > hwRound(Gear^.X) then
   291         Gear^.X := Gear^.X - cDrownSpeed
   313         Gear^.X := Gear^.X - cDrownSpeed
   292     else
   314     else
   293         Gear^.X := Gear^.X + cDrownSpeed;
   315         Gear^.X := Gear^.X + cDrownSpeed;
   294     end
   316     end
   295 else
   317 else
   305 or (SuddenDeathDmg and (SDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then
   327 or (SuddenDeathDmg and (SDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then
   306     if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
   328     if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
   307         AddVisualGear(bubbleX, bubbleY, vgtBubble)
   329         AddVisualGear(bubbleX, bubbleY, vgtBubble)
   308 else if Random(12) = 0 then
   330 else if Random(12) = 0 then
   309         AddVisualGear(bubbleX, bubbleY, vgtBubble);
   331         AddVisualGear(bubbleX, bubbleY, vgtBubble);
       
   332 // Insta-delete gear and skip drowning animation if water is 100% opaque
   310 if (not SuddenDeathDmg and (WaterOpacity > $FE))
   333 if (not SuddenDeathDmg and (WaterOpacity > $FE))
   311 or (SuddenDeathDmg and (SDWaterOpacity > $FE))
   334 or (SuddenDeathDmg and (SDWaterOpacity > $FE)) then
   312 or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then
   335     begin
       
   336     // Teleport gear to a suitable position for the damage tag in the water
       
   337     if (WorldEdge = weSea) and (hwRound(Gear^.X) - Gear^.Radius < leftX) then
       
   338         begin
       
   339         if (hwRound(Gear^.X) - Gear^.Radius > leftX - 90) then
       
   340             Gear^.X := Gear^.X - _90
       
   341         end
       
   342     else if (WorldEdge = weSea) and (hwRound(Gear^.X) + Gear^.Radius > rightX) then
       
   343         begin
       
   344         if (hwRound(Gear^.X) - Gear^.Radius < rightX + 90) then
       
   345             Gear^.X := Gear^.X + _90
       
   346         end
       
   347     else
       
   348         Gear^.Y := int2hwFloat(Gear^.Radius + cWaterLine + cVisibleWater);
       
   349     DeleteGear(Gear);
       
   350     exit;
       
   351     end;
       
   352 // Delete gear normally if it is outside of visible range.
       
   353 // But first determine size tolerance for big gears to make sure the gear is REALLY out of range.
       
   354 if Gear^.Kind = gtPiano then
       
   355     d:= SpritesData[sprPiano].height
       
   356 else if Gear^.Kind = gtRCPlane then
       
   357     d:= SpritesData[sprPlane].width
       
   358 else if Gear^.Kind = gtKnife then
       
   359     d:= SpritesData[sprKnife].height
       
   360 else if Gear^.Kind = gtDynamite then
       
   361     d:= SpritesData[sprDynamite].height
       
   362 else if Gear^.Kind = gtSnowball then
       
   363     d:= SpritesData[sprSnowball].height
       
   364 else
       
   365     d:= Gear^.Radius * 2;
       
   366 if (hwRound(Gear^.Y) > d + cWaterLine + cVisibleWater) then
   313     DeleteGear(Gear);
   367     DeleteGear(Gear);
   314 end;
   368 end;
   315 
   369 
   316 ////////////////////////////////////////////////////////////////////////////////
   370 ////////////////////////////////////////////////////////////////////////////////
   317 procedure doStepFallingGear(Gear: PGear);
   371 procedure doStepFallingGear(Gear: PGear);
   318 var
   372 var
   319     isFalling: boolean;
   373     isFalling: boolean;
   320     //tmp: QWord;
       
   321     tX, tdX, tdY: hwFloat;
   374     tX, tdX, tdY: hwFloat;
   322     collV, collH, gX, gY: LongInt;
   375     collV, collH, gX, gY: LongInt;
   323     land, xland: word;
   376     land, xland: word;
   324 begin
   377 begin
   325     tX:= Gear^.X;
   378     tX:= Gear^.X;
   326     gX:= hwRound(Gear^.X);
   379     gX:= hwRound(Gear^.X);
   327     gY:= hwRound(Gear^.Y);
   380     gY:= hwRound(Gear^.Y);
   328     if (Gear^.Kind <> gtGenericFaller) and WorldWrap(Gear) and (WorldEdge = weWrap) and (Gear^.AdvBounce <> 0) and
   381     Gear^.State := Gear^.State and (not gstCollision);
       
   382 
       
   383     // World wrap
       
   384     if (Gear^.Kind <> gtGenericFaller) and WorldWrap(Gear) and (WorldEdge = weWrap) and
   329       ((TestCollisionXwithGear(Gear, 1) <> 0) or (TestCollisionXwithGear(Gear, -1) <> 0))  then
   385       ((TestCollisionXwithGear(Gear, 1) <> 0) or (TestCollisionXwithGear(Gear, -1) <> 0))  then
   330         begin
   386         begin
   331         Gear^.X:= tX;
   387         // Collision with land that *just* behind the other side of the world wrap edge
   332         Gear^.dX.isNegative:= (gX > LongInt(leftX) + Gear^.Radius*2)
   388         if (not Gear^.Sticky) then
       
   389             begin
       
   390             Gear^.X:= tX;
       
   391             Gear^.dX.isNegative:= (gX > leftX + Gear^.Radius*2);
       
   392             Gear^.dX := Gear^.dX * Gear^.Friction;
       
   393             end;
       
   394         Gear^.State := Gear^.State or gstCollision;
   333         end;
   395         end;
   334 
   396 
   335     // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems.
   397     // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems.
   336     if Gear^.dX.Round > 1 then
   398     if Gear^.dX.Round > 1 then
   337         Gear^.dX.QWordValue:= 8589934592;
   399         Gear^.dX.QWordValue:= 8589934592;
   342         begin
   404         begin
   343         Gear^.dX:= Gear^.dX * _0_999;
   405         Gear^.dX:= Gear^.dX * _0_999;
   344         Gear^.dY:= Gear^.dY * _0_999
   406         Gear^.dY:= Gear^.dY * _0_999
   345         end;
   407         end;
   346 
   408 
   347     Gear^.State := Gear^.State and (not gstCollision);
       
   348     collV := 0;
   409     collV := 0;
   349     collH := 0;
   410     collH := 0;
   350     tdX := Gear^.dX;
   411     tdX := Gear^.dX;
   351     tdY := Gear^.dY;
   412     tdY := Gear^.dY;
   352 
   413 
   428     else if Gear^.AdvBounce = 1 then
   489     else if Gear^.AdvBounce = 1 then
   429         begin
   490         begin
   430         xland:= TestCollisionXwithGear(Gear, -hwSign(Gear^.dX));
   491         xland:= TestCollisionXwithGear(Gear, -hwSign(Gear^.dX));
   431         if xland <> 0 then collH := -hwSign(Gear^.dX)
   492         if xland <> 0 then collH := -hwSign(Gear^.dX)
   432         end;
   493         end;
   433     //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
       
   434     if (collV <> 0) and (collH <> 0) and
   494     if (collV <> 0) and (collH <> 0) and
   435        (((Gear^.AdvBounce=1) and ((collV=-1) or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)))) then
   495        (((Gear^.AdvBounce=1) and ((collV=-1) or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)))) then
   436  //or ((xland or land) and lfBouncy <> 0)) then
       
   437         begin
   496         begin
   438         if (xland or land) and lfBouncy = 0 then
   497         if (xland or land) and lfBouncy = 0 then
   439             begin
   498             begin
   440             Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
   499             Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
   441             Gear^.dY := tdX*Gear^.Elasticity;
   500             Gear^.dY := tdX*Gear^.Elasticity;
   484         end;
   543         end;
   485 
   544 
   486     Gear^.X := Gear^.X + Gear^.dX;
   545     Gear^.X := Gear^.X + Gear^.dX;
   487     Gear^.Y := Gear^.Y + Gear^.dY;
   546     Gear^.Y := Gear^.Y + Gear^.dY;
   488     CheckGearDrowning(Gear);
   547     CheckGearDrowning(Gear);
   489     //if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) < _0_0002) and
       
   490     if (not isFalling) and ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_02.QWordValue) then
   548     if (not isFalling) and ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_02.QWordValue) then
   491         Gear^.State := Gear^.State and (not gstMoving)
   549         Gear^.State := Gear^.State and (not gstMoving)
   492     else
   550     else
   493         Gear^.State := Gear^.State or gstMoving;
   551         Gear^.State := Gear^.State or gstMoving;
   494 
   552 
   495     if ((xland or land) and lfBouncy <> 0) and (Gear^.dX.QWordValue < _0_15.QWordValue) and (Gear^.dY.QWordValue < _0_15.QWordValue) then
   553     if ((xland or land) and lfBouncy <> 0) and (Gear^.dX.QWordValue < _0_15.QWordValue) and (Gear^.dY.QWordValue < _0_15.QWordValue) then
   496         Gear^.State := Gear^.State or gstCollision;
   554         Gear^.State := Gear^.State or gstCollision;
   497 
   555 
   498     if ((xland or land) and lfBouncy <> 0) and (Gear^.Radius >= 3) and
   556     if ((xland or land) and lfBouncy <> 0) and
   499        ((Gear^.dX.QWordValue > _0_15.QWordValue) or (Gear^.dY.QWordValue > _0_15.QWordValue)) then
   557        ((Gear^.dX.QWordValue > _0_15.QWordValue) or (Gear^.dY.QWordValue > _0_15.QWordValue)) then
   500         begin
   558         begin
   501         AddBounceEffectForGear(Gear);
   559         AddBounceEffectForGear(Gear);
   502         end
   560         end
   503     else if (Gear^.nImpactSounds > 0) and
   561     else if (Gear^.nImpactSounds > 0) and
   524     if Gear^.Timer = 1000 then // might need adjustments
   582     if Gear^.Timer = 1000 then // might need adjustments
   525         case Gear^.Kind of
   583         case Gear^.Kind of
   526             gtGrenade,
   584             gtGrenade,
   527             gtClusterBomb,
   585             gtClusterBomb,
   528             gtWatermelon,
   586             gtWatermelon,
   529             gtHellishBomb: makeHogsWorry(Gear^.X, Gear^.Y, Gear^.Boom);
   587             gtHellishBomb: makeHogsWorry(Gear^.X, Gear^.Y, Gear^.Boom, Gear^.Kind);
   530             gtGasBomb: makeHogsWorry(Gear^.X, Gear^.Y, 50);
   588             gtGasBomb: makeHogsWorry(Gear^.X, Gear^.Y, 50, Gear^.Kind);
   531         end;
   589         end;
   532 
   590 
   533     if (Gear^.Kind = gtBall) and ((Gear^.State and gstTmpFlag) <> 0) then
   591     if (Gear^.Kind = gtBall) and ((Gear^.State and gstTmpFlag) <> 0) then
   534         begin
   592         begin
   535         CheckCollision(Gear);
   593         CheckCollision(Gear);
   662         PlaySound(sndMolotov);
   720         PlaySound(sndMolotov);
   663         gX := hwRound(Gear^.X);
   721         gX := hwRound(Gear^.X);
   664         gY := hwRound(Gear^.Y);
   722         gY := hwRound(Gear^.Y);
   665         for i:= 0 to 4 do
   723         for i:= 0 to 4 do
   666             begin
   724             begin
   667             (*glass:= AddVisualGear(gx+random(7)-3, gy+random(5)-2, vgtEgg);
   725             glass:= AddVisualGear(gx+random(7)-3, gy+random(7)-3, vgtEgg);
   668             if glass <> nil then
       
   669                 begin
       
   670                 glass^.Frame:= 2;
       
   671                 glass^.Tint:= $41B83ED0 - i * $10081000;
       
   672                 glass^.dX:= 1/(10*(random(11)-5));
       
   673                 glass^.dY:= -1/(random(4)+5);
       
   674                 end;*)
       
   675             glass:= AddVisualGear(gx+random(7)-3, gy+random(7)-3, vgtStraightShot);
       
   676             if glass <> nil then
   726             if glass <> nil then
   677                 with glass^ do
   727                 with glass^ do
   678                     begin
   728                     begin
   679                     Frame:= 2;
   729                     Frame:= 2;
   680                     Tint:= $41B83ED0 - i * $10081000;
   730                     Tint:= $41B83ED0 - i * $10081000;
       
   731                     dX:= dX + hwFloat2Float(Gear^.dX) / 2;
   681                     Angle:= random(360);
   732                     Angle:= random(360);
   682                     dx:= 0.0000001;
       
   683                     dy:= 0;
       
   684                     if random(2) = 0 then
       
   685                         dx := -dx;
       
   686                     FrameTicks:= 750;
   733                     FrameTicks:= 750;
   687                     State:= ord(sprEgg)
   734                     State:= ord(sprEgg)
   688                     end;
   735                     end;
   689             end;
   736             end;
   690         for i:= 0 to 24 do
   737         for i:= 0 to 24 do
   792     CheckCollision(Gear);
   839     CheckCollision(Gear);
   793     if ((Gear^.State and gstCollision) <> 0) or ((Gear^.State and gstMoving) = 0) then
   840     if ((Gear^.State and gstCollision) <> 0) or ((Gear^.State and gstMoving) = 0) then
   794         draw:= true;
   841         draw:= true;
   795     xx:= hwRound(Gear^.X);
   842     xx:= hwRound(Gear^.X);
   796     yy:= hwRound(Gear^.Y);
   843     yy:= hwRound(Gear^.Y);
   797     if draw and (WorldEdge = weWrap) and ((xx < LongInt(leftX) + 3) or (xx > LongInt(rightX) - 3)) then
   844     if draw and (WorldEdge = weWrap) and ((xx < leftX + 3) or (xx > rightX - 3)) then
   798         begin
   845         begin
   799         if xx < LongInt(leftX) + 3 then
   846         if xx < leftX + 3 then
   800              xx:= rightX-3
   847              xx:= rightX-3
   801         else xx:= leftX+3;
   848         else xx:= leftX+3;
   802         Gear^.X:= int2hwFloat(xx)
   849         Gear^.X:= int2hwFloat(xx)
   803         end
   850         end
   804     end
   851     end
   817             if DirAngle < 0 then
   864             if DirAngle < 0 then
   818                 DirAngle := DirAngle + 360
   865                 DirAngle := DirAngle + 360
   819             else if 360 < DirAngle then
   866             else if 360 < DirAngle then
   820                 DirAngle := DirAngle - 360;
   867                 DirAngle := DirAngle - 360;
   821             end;
   868             end;
   822 (*
       
   823 We aren't using frametick right now, so just a waste of cycles.
       
   824         inc(Health, 8);
       
   825         if longword(Health) > vobFrameTicks then
       
   826             begin
       
   827             dec(Health, vobFrameTicks);
       
   828             inc(Timer);
       
   829             if Timer = vobFramesCount then
       
   830                 Timer:= 0
       
   831             end;
       
   832 *)
       
   833     // move back to cloud layer
   869     // move back to cloud layer
   834         if CheckCoordInWater(xx, yy) then
   870         if CheckCoordInWater(xx, yy) then
   835             move:= true
   871             move:= true
   836         else if (xx > snowRight) or (xx < snowLeft) then
   872         else if (xx > snowRight) or (xx < snowLeft) then
   837             move:=true
   873             move:=true
   996 ////////////////////////////////////////////////////////////////////////////////
  1032 ////////////////////////////////////////////////////////////////////////////////
   997 procedure doStepBeeWork(Gear: PGear);
  1033 procedure doStepBeeWork(Gear: PGear);
   998 var
  1034 var
   999     t: hwFloat;
  1035     t: hwFloat;
  1000     gX,gY,i: LongInt;
  1036     gX,gY,i: LongInt;
  1001     uw, nuw: boolean;
  1037     uw, nuw, wrapped: boolean;
  1002     flower: PVisualGear;
  1038     flower: PVisualGear;
  1003 
  1039 
  1004 begin
  1040 begin
  1005     WorldWrap(Gear);
  1041     wrapped:= WorldWrap(Gear);
       
  1042     if wrapped then
       
  1043         HomingWrap(Gear);
       
  1044 
  1006     AllInactive := false;
  1045     AllInactive := false;
  1007     gX := hwRound(Gear^.X);
  1046     gX := hwRound(Gear^.X);
  1008     gY := hwRound(Gear^.Y);
  1047     gY := hwRound(Gear^.Y);
  1009     uw := (Gear^.Tag <> 0); // was bee underwater last tick?
  1048     uw := (Gear^.Tag <> 0); // was bee underwater last tick?
  1010     nuw := CheckCoordInWater(gx, gy + Gear^.Radius); // is bee underwater now?
  1049     nuw := CheckCoordInWater(gx, gy + Gear^.Radius); // is bee underwater now?
  1028         end;
  1067         end;
  1029 
  1068 
  1030 
  1069 
  1031     if Gear^.Timer = 0 then
  1070     if Gear^.Timer = 0 then
  1032         begin
  1071         begin
  1033         // no "fuel"? just fall
  1072         // no energy? just fall
  1034         doStepFallingGear(Gear);
  1073         doStepFallingGear(Gear);
  1035         // if drowning, stop bee sound
  1074         // if drowning, stop bee sound
  1036         if (Gear^.State and gstDrowning) <> 0 then
  1075         if (Gear^.State and gstDrowning) <> 0 then
  1037             StopSoundChan(Gear^.SoundChannel);
  1076             StopSoundChan(Gear^.SoundChannel);
  1038         end
  1077         end
  1095             end;
  1134             end;
  1096         end;
  1135         end;
  1097 end;
  1136 end;
  1098 
  1137 
  1099 procedure doStepBee(Gear: PGear);
  1138 procedure doStepBee(Gear: PGear);
       
  1139 var wrapped: boolean;
  1100 begin
  1140 begin
  1101     AllInactive := false;
  1141     AllInactive := false;
  1102     Gear^.X := Gear^.X + Gear^.dX;
  1142     Gear^.X := Gear^.X + Gear^.dX;
  1103     Gear^.Y := Gear^.Y + Gear^.dY;
  1143     Gear^.Y := Gear^.Y + Gear^.dY;
  1104     WorldWrap(Gear);
  1144     wrapped:= WorldWrap(Gear);
       
  1145     if wrapped then
       
  1146         HomingWrap(Gear);
  1105     Gear^.dY := Gear^.dY + cGravity;
  1147     Gear^.dY := Gear^.dY + cGravity;
  1106     CheckGearDrowning(Gear);
  1148     CheckGearDrowning(Gear);
  1107     CheckCollision(Gear);
  1149     CheckCollision(Gear);
  1108     if (Gear^.State and gstCollision) <> 0 then
  1150     if (Gear^.State and gstCollision) <> 0 then
  1109         begin
  1151         begin
  1138             DeleteGear(Gear);
  1180             DeleteGear(Gear);
  1139             AfterAttack
  1181             AfterAttack
  1140             end
  1182             end
  1141         end
  1183         end
  1142     else
  1184     else
  1143         begin
       
  1144         DeleteGear(Gear);
  1185         DeleteGear(Gear);
  1145         end
       
  1146 end;
  1186 end;
  1147 
  1187 
  1148 procedure CreateShellForGear(Gear: PGear; startFrame: Longword);
  1188 procedure CreateShellForGear(Gear: PGear; startFrame: Longword);
  1149 var
  1189 var
  1150     shell: PVisualGear;
  1190     shell: PVisualGear;
  1158         shell^.dY := gear^.dY.QWordValue / -17179869184;
  1198         shell^.dY := gear^.dY.QWordValue / -17179869184;
  1159         shell^.Frame := startFrame;
  1199         shell^.Frame := startFrame;
  1160     end;
  1200     end;
  1161 end;
  1201 end;
  1162 
  1202 
       
  1203 function ShotgunLineHitHelp(Gear: PGear; oX, oY, tX, tY: hwFloat): Boolean;
       
  1204 var i: LongInt;
       
  1205     Collisions: PGearArray;
       
  1206 begin
       
  1207     ShotgunLineHitHelp := false;
       
  1208     Collisions := CheckAllGearsLineCollision(Gear, oX, oY, tX, tY);
       
  1209     i := Collisions^.Count;
       
  1210     while i > 0 do
       
  1211         begin
       
  1212         dec(i);
       
  1213         if Collisions^.ar[i]^.Kind in
       
  1214             [gtMine, gtSMine, gtAirMine, gtKnife, gtCase, gtTarget, gtExplosives] then
       
  1215             begin
       
  1216             Gear^.X := Collisions^.ar[i]^.X;
       
  1217             Gear^.Y := Collisions^.ar[i]^.Y;
       
  1218             ShotgunShot(Gear);
       
  1219             Gear^.doStep := @doStepShotIdle;
       
  1220             ShotgunLineHitHelp := true;
       
  1221             exit;
       
  1222             end;
       
  1223         end;
       
  1224 end;
       
  1225 
  1163 procedure doStepShotgunShot(Gear: PGear);
  1226 procedure doStepShotgunShot(Gear: PGear);
  1164 var
  1227 var
  1165     i: LongWord;
  1228     i: LongWord;
       
  1229     oX, oY, tmpX, tmpY: hwFloat;
  1166 begin
  1230 begin
  1167     AllInactive := false;
  1231     AllInactive := false;
  1168 
  1232 
  1169     if ((Gear^.State and gstAnimation) = 0) then
  1233     if ((Gear^.State and gstAnimation) = 0) then
  1170         begin
  1234         begin
  1184             exit
  1248             exit
  1185             end
  1249             end
  1186     else
  1250     else
  1187         inc(Gear^.Timer);
  1251         inc(Gear^.Timer);
  1188 
  1252 
  1189         i := 200;
  1253     i := 100;
       
  1254     oX := Gear^.X;
       
  1255     oY := Gear^.Y;
  1190     repeat
  1256     repeat
  1191         Gear^.X := Gear^.X + Gear^.dX;
  1257         if Gear^.Tag = 0 then
  1192         Gear^.Y := Gear^.Y + Gear^.dY;
  1258             begin
  1193         WorldWrap(Gear);
  1259             Gear^.X := Gear^.X + Gear^.dX;
       
  1260             Gear^.Y := Gear^.Y + Gear^.dY;
       
  1261             end;
       
  1262 
       
  1263         tmpX := Gear^.X;
       
  1264         tmpY := Gear^.Y;
       
  1265         if (Gear^.PortalCounter < 30) and WorldWrap(Gear) then
       
  1266             begin
       
  1267             inc(Gear^.PortalCounter);
       
  1268             if ShotgunLineHitHelp(Gear, oX, oY, tmpX, tmpY) then
       
  1269                 exit;
       
  1270             oX := Gear^.X;
       
  1271             oY := Gear^.Y;
       
  1272             end;
  1194         CheckCollision(Gear);
  1273         CheckCollision(Gear);
  1195         if (Gear^.State and gstCollision) <> 0 then
  1274 
  1196             begin
  1275         if ((Gear^.State and gstCollision) <> 0) then
  1197             Gear^.X := Gear^.X + Gear^.dX * 8;
  1276             begin
  1198             Gear^.Y := Gear^.Y + Gear^.dY * 8;
  1277             if Gear^.Tag = 0 then
  1199             ShotgunShot(Gear);
  1278                 begin
  1200             Gear^.doStep := @doStepShotIdle;
  1279                     //Try to align the shot with the land to give portals a chance to catch it
  1201             exit
  1280                     Gear^.X := Gear^.X + Gear^.dX * 2;
  1202             end;
  1281                     Gear^.Y := Gear^.Y + Gear^.dY * 2;
       
  1282                     Gear^.Tag := 1
       
  1283                 end
       
  1284                 else
       
  1285                 begin
       
  1286                     Gear^.X := Gear^.X + Gear^.dX * 6;
       
  1287                     Gear^.Y := Gear^.Y + Gear^.dY * 6;
       
  1288                     ShotgunShot(Gear);
       
  1289                     Gear^.doStep := @doStepShotIdle;
       
  1290                 end;
       
  1291                 exit
       
  1292             end
       
  1293         else
       
  1294             Gear^.Tag := 0;
  1203 
  1295 
  1204         CheckGearDrowning(Gear);
  1296         CheckGearDrowning(Gear);
  1205         if (Gear^.State and gstDrowning) <> 0 then
  1297         if (Gear^.State and gstDrowning) <> 0 then
  1206             begin
  1298             begin
  1207             Gear^.doStep := @doStepShotIdle;
  1299             Gear^.doStep := @doStepShotIdle;
  1208             exit
  1300             break;
  1209             end;
  1301             end;
  1210         dec(i)
  1302         dec(i)
  1211     until i = 0;
  1303     until i = 0;
       
  1304 
       
  1305     ShotgunLineHitHelp(Gear, oX, oY, Gear^.X, Gear^.Y);
       
  1306 
  1212     if (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
  1307     if (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
  1213         Gear^.doStep := @doStepShotIdle
  1308         Gear^.doStep := @doStepShotIdle
  1214 end;
  1309 end;
  1215 
  1310 
  1216 ////////////////////////////////////////////////////////////////////////////////
  1311 ////////////////////////////////////////////////////////////////////////////////
  1299 end;
  1394 end;
  1300 
  1395 
  1301 procedure LineShoveHelp(Gear: PGear; oX, oY, tX, tY, dX, dY: hwFloat; count: LongWord);
  1396 procedure LineShoveHelp(Gear: PGear; oX, oY, tX, tY, dX, dY: hwFloat; count: LongWord);
  1302 var dmg,power: LongInt;
  1397 var dmg,power: LongInt;
  1303 begin
  1398 begin
  1304     if ((Gear^.Kind = gtMinigunBullet) or (Gear^.Damage > 0))
  1399     if hwSqr(tX - oX) + hwSqr(tY - oY) > _0_25 then
  1305     and (hwSqr(tX - oX) + hwSqr(tY - oY) > _0_25) then
       
  1306     begin
  1400     begin
  1307         if (Gear^.AmmoType = amDEagle) or (Gear^.AmmoType = amMinigun) then
  1401         if (Gear^.AmmoType = amDEagle) or (Gear^.AmmoType = amMinigun) then
  1308             dmg:= Gear^.Boom
  1402             dmg:= Gear^.Boom
  1309         else
  1403         else
  1310             dmg:= Gear^.Timer * Gear^.Boom div 100000;
  1404             dmg:= Gear^.Timer * Gear^.Boom div 100000;
  1320         dec(Gear^.Health, Gear^.Damage);
  1414         dec(Gear^.Health, Gear^.Damage);
  1321         Gear^.Damage := 0
  1415         Gear^.Damage := 0
  1322     end;
  1416     end;
  1323 end;
  1417 end;
  1324 
  1418 
       
  1419 procedure CheckBulletDrowningHelp(Bullet: PGear);
       
  1420 var dX, dY: hwFloat;
       
  1421 begin
       
  1422     dX := Bullet^.dX;
       
  1423     dY := Bullet^.dY;
       
  1424     CheckGearDrowning(Bullet);
       
  1425     if (dX <> Bullet^.dX) or (dY <> Bullet^.dY) then
       
  1426     begin
       
  1427         SpawnBulletTrail(Bullet, Bullet^.X, Bullet^.Y, Bullet^.FlightTime = 0);
       
  1428         Bullet^.Elasticity := Bullet^.X;
       
  1429         Bullet^.Friction := Bullet^.Y;
       
  1430         Inc(Bullet^.PortalCounter);
       
  1431         Bullet^.FlightTime:= 1;
       
  1432     end;
       
  1433 end;
       
  1434 
       
  1435 procedure CreateBubblesForBullet(Gear: PGear);
       
  1436 var i, iInit: LongWord;
       
  1437 begin
       
  1438 iInit:= 0;
       
  1439 if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Health > 0) then
       
  1440     begin
       
  1441     // draw bubbles
       
  1442     if (not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF)) then
       
  1443         begin
       
  1444         case Gear^.Kind of
       
  1445             gtMinigunBullet: iInit:= Gear^.Health * 100;
       
  1446             gtDEagleShot, gtSniperRifleShot: iInit:= Gear^.Health * 4
       
  1447             end;
       
  1448         for i:=iInit downto 0 do
       
  1449             begin
       
  1450             if Random(6) = 0 then
       
  1451                 AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
       
  1452             Gear^.X := Gear^.X + Gear^.dX;
       
  1453             Gear^.Y := Gear^.Y + Gear^.dY;
       
  1454             end;
       
  1455         end;
       
  1456     // bullet dies underwater
       
  1457     Gear^.Health:= 0;
       
  1458     end;
       
  1459 end;
       
  1460 
  1325 procedure doStepBulletWork(Gear: PGear);
  1461 procedure doStepBulletWork(Gear: PGear);
  1326 var
  1462 var
  1327     i, x, y, iInit: LongWord;
  1463     i, x, y, iInit: LongWord;
  1328     oX, oY, tX, tY, tDx, tDy: hwFloat;
  1464     oX, oY, tX, tY, tDx, tDy: hwFloat;
  1329     VGear: PVisualGear;
  1465     VGear: PVisualGear;
  1376             begin
  1512             begin
  1377             Gear^.Tag := 1;
  1513             Gear^.Tag := 1;
  1378             dec(Gear^.Damage);
  1514             dec(Gear^.Damage);
  1379             Gear^.X := Gear^.X - Gear^.dX;
  1515             Gear^.X := Gear^.X - Gear^.dX;
  1380             Gear^.Y := Gear^.Y - Gear^.dY;
  1516             Gear^.Y := Gear^.Y - Gear^.dY;
  1381             CheckGearDrowning(Gear);
  1517             CheckBulletDrowningHelp(Gear);
  1382             break;
  1518             break;
  1383             end
  1519             end
  1384         else if (not isDigging) then
  1520         else if (not isDigging) then
  1385             Gear^.Tag := 0;
  1521             Gear^.Tag := 0;
  1386 
  1522 
  1393             iInit:= i;
  1529             iInit:= i;
  1394             oX:= Gear^.X;
  1530             oX:= Gear^.X;
  1395             oY:= Gear^.Y;
  1531             oY:= Gear^.Y;
  1396             end;
  1532             end;
  1397 
  1533 
  1398         CheckGearDrowning(Gear);
  1534         CheckBulletDrowningHelp(Gear);
  1399         case Gear^.Kind of
  1535         case Gear^.Kind of
  1400             gtMinigunBullet: isDead:= isDigging;
  1536             gtMinigunBullet: isDead:= isDigging or ((Gear^.State and gstDrowning) <> 0);
  1401             gtDEagleShot, gtSniperRifleShot: isDead:= Gear^.Damage >= Gear^.Health;
  1537             gtDEagleShot, gtSniperRifleShot: isDead:= (Gear^.Damage >= Gear^.Health) or ((Gear^.State and gstDrowning) <> 0)
  1402         end;
  1538         end;
  1403         dec(i)
  1539         dec(i)
  1404     until (i = 0) or (isDead) or ((Gear^.State and gstDrowning) <> 0);
  1540     until (i = 0) or (isDead);
  1405 
  1541 
  1406     LineShoveHelp(Gear, oX, oY, Gear^.X, Gear^.Y,
  1542     LineShoveHelp(Gear, oX, oY, Gear^.X, Gear^.Y,
  1407                   Gear^.dX, Gear^.dY, iInit + 2 - i);
  1543                   Gear^.dX, Gear^.dY, iInit + 2 - i);
  1408 
  1544 
  1409     if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Health > 0) then
  1545     CreateBubblesForBullet(Gear);
  1410         begin
  1546 
  1411         // draw bubbles
  1547     x := hwRound(Gear^.X);
  1412         if (not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF)) then
  1548     y := hwRound(Gear^.Y);
  1413             begin
  1549     if (isDead) or (x and LAND_WIDTH_MASK <> 0) or (y and LAND_HEIGHT_MASK <> 0) then
  1414             for i:=(Gear^.Health * 4) downto 0 do
  1550         begin
  1415                 begin
  1551         if (Gear^.Kind = gtSniperRifleShot) then
  1416                 if Random(6) = 0 then
  1552             cLaserSightingSniper := false;
  1417                     AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
  1553         if (Ammoz[Gear^.AmmoType].Ammo.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and (CurrentHedgehog^.Effects[heArtillery] = 2) then
  1418                 Gear^.X := Gear^.X + Gear^.dX;
  1554             CurrentHedgehog^.Effects[heArtillery]:= 0;
  1419                 Gear^.Y := Gear^.Y + Gear^.dY;
  1555 
       
  1556         // Bullet Hit
       
  1557         if ((Gear^.State and gstDrowning) = 0) and (x and LAND_WIDTH_MASK = 0) and (y and LAND_HEIGHT_MASK = 0) then
       
  1558             begin
       
  1559             if Gear^.Kind = gtMinigunBullet then
       
  1560                 begin
       
  1561                 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 5,
       
  1562                                 Gear^.Hedgehog, (EXPLNoDamage or EXPLDoNotTouchHH){ or EXPLDontDraw or EXPLNoGfx});
       
  1563                 VGear := AddVisualGear(hwRound(Gear^.X + Gear^.dX * 5), hwRound(Gear^.Y + Gear^.dY * 5), vgtBulletHit);
       
  1564                 end
       
  1565             else
       
  1566                 VGear := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBulletHit);
       
  1567 
       
  1568             if VGear <> nil then
       
  1569                 begin
       
  1570                 VGear^.Angle := DxDy2Angle(-Gear^.dX, Gear^.dY);
  1420                 end;
  1571                 end;
  1421             end;
  1572             end;
  1422         // bullet dies underwater
  1573 
  1423         Gear^.Health:= 0;
  1574         spawnBulletTrail(Gear, Gear^.X, Gear^.Y, Gear^.FlightTime = 0);
  1424         end;
  1575         Gear^.FlightTime:= 1;
  1425 
  1576         if Gear^.Kind = gtMinigunBullet then
  1426     if (isDead)
  1577             ClearHitOrderLeq(Gear^.Tag);
  1427         or (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0)
  1578 
  1428         or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
  1579         if (worldEdge = weSea) and (Gear^.Kind = gtMinigunBullet)
  1429             begin
  1580             and Gear^.Y.isNegative and Gear^.dY.isNegative
  1430             if (Gear^.Kind = gtSniperRifleShot) then
  1581             and (Gear^.Health > 0) and (not isZero(Gear^.dX)) then
  1431                 cLaserSightingSniper := false;
  1582         begin
  1432             if (Ammoz[Gear^.AmmoType].Ammo.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and (CurrentHedgehog^.Effects[heArtillery] = 2) then
  1583             if Gear^.dX.isNegative then
  1433                 CurrentHedgehog^.Effects[heArtillery]:= 0;
  1584                 begin
  1434 
  1585 
  1435         // Bullet Hit
  1586                 Gear^.X:= int2hwFloat(-1);
  1436             if ((Gear^.State and gstDrowning) = 0) and (hwRound(Gear^.X) and LAND_WIDTH_MASK = 0) and (hwRound(Gear^.Y) and LAND_HEIGHT_MASK = 0) then
  1587                 iInit:= x - leftX;
  1437                 begin
  1588                 end
  1438                 if Gear^.Kind = gtMinigunBullet then
  1589             else
  1439                     begin
  1590                 begin
  1440                     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 5,
  1591                 Gear^.X:= int2hwFloat(LAND_WIDTH);
  1441                                     Gear^.Hedgehog, EXPLNoDamage{ or EXPLDontDraw or EXPLNoGfx});
  1592                 iInit:= rightX - x - 1;
  1442                     VGear := AddVisualGear(hwRound(Gear^.X + Gear^.dX * 5), hwRound(Gear^.Y + Gear^.dY * 5), vgtBulletHit);
       
  1443                     end
       
  1444                 else
       
  1445                     VGear := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBulletHit);
       
  1446 
       
  1447                 if VGear <> nil then
       
  1448                     begin
       
  1449                     VGear^.Angle := DxDy2Angle(-Gear^.dX, Gear^.dY);
       
  1450                     end;
       
  1451                 end;
  1593                 end;
  1452 
  1594             Gear^.Y:= Gear^.Y + Gear^.dY * hwAbs(int2hwFloat(iInit) / Gear^.dX);
  1453             spawnBulletTrail(Gear, Gear^.X, Gear^.Y, Gear^.FlightTime = 0);
  1595             CheckGearDrowning(Gear);
  1454             Gear^.FlightTime:= 1;
  1596             CreateBubblesForBullet(Gear);
  1455             if Gear^.Kind = gtMinigunBullet then
  1597         end;
  1456                 ClearHitOrderLeq(Gear^.Tag);
  1598         Gear^.doStep := @doStepShotIdle
  1457             Gear^.doStep := @doStepShotIdle
  1599         end;
  1458             end;
       
  1459 end;
  1600 end;
  1460 
  1601 
  1461 procedure doStepDEagleShot(Gear: PGear);
  1602 procedure doStepDEagleShot(Gear: PGear);
  1462 begin
  1603 begin
  1463     Gear^.Data:= nil;
  1604     Gear^.Data:= nil;
  1464     // remember who fired this
  1605     // remember who fired this
  1465     if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) then
  1606     if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) then
  1466         Gear^.Data:= Pointer(Gear^.Hedgehog^.Gear);
  1607         Gear^.Data:= Pointer(Gear^.Hedgehog^.Gear);
  1467 
  1608 
  1468     PlaySound(sndGun);
  1609     PlaySound(sndGun);
       
  1610     ClearHitOrder();
  1469     // add 2 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just plain old weird angles
  1611     // add 2 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just plain old weird angles
  1470     Gear^.X := Gear^.X + Gear^.dX * 2;
  1612     Gear^.X := Gear^.X + Gear^.dX * 2;
  1471     Gear^.Y := Gear^.Y + Gear^.dY * 2;
  1613     Gear^.Y := Gear^.Y + Gear^.dY * 2;
  1472     Gear^.FlightTime := 0;
  1614     Gear^.FlightTime := 0;
  1473     Gear^.doStep := @doStepBulletWork
  1615     Gear^.doStep := @doStepBulletWork
  1506         CreateShellForGear(Gear, 1);
  1648         CreateShellForGear(Gear, 1);
  1507         Gear^.State := Gear^.State or gstAnimation;
  1649         Gear^.State := Gear^.State or gstAnimation;
  1508         Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
  1650         Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
  1509         Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5;
  1651         Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5;
  1510         PlaySound(sndGun);
  1652         PlaySound(sndGun);
       
  1653         ClearHitOrder();
  1511         // add 2 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just weird angles
  1654         // add 2 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just weird angles
  1512         Gear^.X := Gear^.X + Gear^.dX * 2;
  1655         Gear^.X := Gear^.X + Gear^.dX * 2;
  1513         Gear^.Y := Gear^.Y + Gear^.dY * 2;
  1656         Gear^.Y := Gear^.Y + Gear^.dY * 2;
  1514         Gear^.FlightTime := 0;
  1657         Gear^.FlightTime := 0;
  1515         Gear^.doStep := @doStepBulletWork;
  1658         Gear^.doStep := @doStepBulletWork;
  1541     gtATStartGame:
  1684     gtATStartGame:
  1542         begin
  1685         begin
  1543         AllInactive := false;
  1686         AllInactive := false;
  1544         if Gear^.Timer = 0 then
  1687         if Gear^.Timer = 0 then
  1545             begin
  1688             begin
  1546             AddCaption(GetEventString(eidRoundStart), cWhiteColor, capgrpGameState);
  1689             AddCaption(GetEventString(eidRoundStart), capcolDefault, capgrpGameState);
  1547             end
  1690             end
  1548         end;
  1691         end;
  1549     gtATFinishGame:
  1692     gtATFinishGame:
  1550         begin
  1693         begin
  1551         AllInactive := false;
  1694         AllInactive := false;
  1556             ScreenFadeSpeed := 1;
  1699             ScreenFadeSpeed := 1;
  1557             end;
  1700             end;
  1558         if Gear^.Timer = 0 then
  1701         if Gear^.Timer = 0 then
  1559             begin
  1702             begin
  1560             SendIPC(_S'N');
  1703             SendIPC(_S'N');
       
  1704             if (luaCmdUsed) then
       
  1705                 SendIPC(_S'm');
  1561             SendIPC(_S'q');
  1706             SendIPC(_S'q');
  1562             GameState := gsExit
  1707             GameState := gsExit
  1563             end
  1708             end
  1564         end;
  1709         end;
  1565     end;
  1710     end;
  1606 
  1751 
  1607         i := x - Gear^.Radius - LongInt(GetRandom(2));
  1752         i := x - Gear^.Radius - LongInt(GetRandom(2));
  1608         ei := x + Gear^.Radius + LongInt(GetRandom(2));
  1753         ei := x + Gear^.Radius + LongInt(GetRandom(2));
  1609         while i <= ei do
  1754         while i <= ei do
  1610             begin
  1755             begin
  1611             DrawExplosion(i, y + 3, 3);
  1756             doMakeExplosion(i, y + 3, 3, Gear^.Hedgehog, EXPLNoDamage or EXPLDoNotTouchAny or EXPLNoGfx or EXPLForceDraw);
  1612             inc(i, 1)
  1757             inc(i, 1)
  1613             end;
  1758             end;
  1614 
  1759 
  1615         if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9), lfIndestructible) then
  1760         if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9), lfIndestructible) then
  1616             begin
  1761             begin
  1819 var vg: PVisualGear;
  1964 var vg: PVisualGear;
  1820     dxdy: hwFloat;
  1965     dxdy: hwFloat;
  1821     dmg: LongWord;
  1966     dmg: LongWord;
  1822 begin
  1967 begin
  1823     if Gear^.Health = 0 then dxdy:= hwAbs(Gear^.dX)+hwAbs(Gear^.dY);
  1968     if Gear^.Health = 0 then dxdy:= hwAbs(Gear^.dX)+hwAbs(Gear^.dY);
       
  1969     Gear^.RenderTimer:= ((Gear^.State and gstFrozen) = 0) and ((Gear^.State and gstAttacking) = 0) and (Gear^.Health <> 0);
  1824     if (Gear^.State and gstMoving) <> 0 then
  1970     if (Gear^.State and gstMoving) <> 0 then
  1825         begin
  1971         begin
  1826         DeleteCI(Gear);
  1972         DeleteCI(Gear);
  1827         doStepFallingGear(Gear);
  1973         doStepFallingGear(Gear);
  1828         if (Gear^.State and gstMoving) = 0 then
  1974         if (Gear^.State and gstMoving) = 0 then
  1885                 if ((Gear^.State and gstWait) <> 0)
  2031                 if ((Gear^.State and gstWait) <> 0)
  1886                 or (cMineDudPercent = 0)
  2032                 or (cMineDudPercent = 0)
  1887                 or (getRandom(100) > cMineDudPercent) then
  2033                 or (getRandom(100) > cMineDudPercent) then
  1888                     begin
  2034                     begin
  1889                     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  2035                     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  1890                     DeleteGear(Gear)
  2036                     DeleteGear(Gear);
       
  2037                     exit   // redundant but we've had too many delete gear bugs
  1891                     end
  2038                     end
  1892                 else
  2039                 else
  1893                     begin
  2040                     begin
  1894                     vg:= AddVisualGear(hwRound(Gear^.X) - 4  + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
  2041                     vg:= AddVisualGear(hwRound(Gear^.X) - 4  + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
  1895                     if vg <> nil then
  2042                     if vg <> nil then
  1913 procedure doStepAirMine(Gear: PGear);
  2060 procedure doStepAirMine(Gear: PGear);
  1914 var i,t,targDist,tmpDist: LongWord;
  2061 var i,t,targDist,tmpDist: LongWord;
  1915     targ, tmpG: PGear;
  2062     targ, tmpG: PGear;
  1916     trackSpeed, airFriction, tX, tY: hwFloat;
  2063     trackSpeed, airFriction, tX, tY: hwFloat;
  1917     isUnderwater: Boolean;
  2064     isUnderwater: Boolean;
  1918 begin
  2065     sparkle: PVisualGear;
       
  2066 begin
       
  2067     targ:= nil;
       
  2068     Gear^.RenderTimer:= ((Gear^.State and gstFrozen) = 0) and ((Gear^.State and gstAttacking) = 0);
       
  2069     if (Gear^.State and gstFrozen) <> 0 then
       
  2070         begin
       
  2071         if Gear^.Damage > 0 then
       
  2072             begin
       
  2073             // Normal, damaging explosion
       
  2074             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
       
  2075             if ((Gear^.State and gstNoGravity) <> 0) then
       
  2076                 // Remove land created by frozen air mine sprite pixel-perfectly
       
  2077                 EraseLand(
       
  2078                     hwRound(Gear^.X) - SpritesData[sprFrozenAirMine].Width div 2,
       
  2079                     hwRound(Gear^.Y) - SpritesData[sprFrozenAirMine].Height div 2,
       
  2080                     sprFrozenAirMine, 0, 0, false, false, false, false);
       
  2081             DeleteGear(Gear);
       
  2082             exit
       
  2083             end;
       
  2084         if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) > _0_02.QWordValue) or ((GameTicks and $3F) = 15) then
       
  2085             doStepFallingGear(Gear);
       
  2086         exit
       
  2087         end;
  1919     isUnderwater:= CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + Gear^.Radius);
  2088     isUnderwater:= CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + Gear^.Radius);
  1920     if Gear^.Pos > 0 then
  2089     if Gear^.Pos > 0 then
  1921         begin
  2090         begin
  1922         airFriction:= _1;
  2091         airFriction:= _1;
  1923         if isUnderwater then
  2092         if isUnderwater then
  1925         else
  2094         else
  1926             dec(airFriction.QWordValue,Gear^.Pos);
  2095             dec(airFriction.QWordValue,Gear^.Pos);
  1927         Gear^.dX:= Gear^.dX*airFriction;
  2096         Gear^.dX:= Gear^.dX*airFriction;
  1928         Gear^.dY:= Gear^.dY*airFriction
  2097         Gear^.dY:= Gear^.dY*airFriction
  1929         end;
  2098         end;
  1930     doStepFallingGear(Gear);
  2099     if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) > _0_02.QWordValue) or ((GameTicks and $3F) = 15) then
       
  2100         doStepFallingGear(Gear);
  1931     if (TurnTimeLeft = 0) and ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) > _0_02.QWordValue) then
  2101     if (TurnTimeLeft = 0) and ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) > _0_02.QWordValue) then
  1932         AllInactive := false;
  2102         AllInactive := false;
       
  2103 
       
  2104     // Disable targeting if airmine is not active yet
       
  2105     if ((Gear^.State and gsttmpFlag) = 0) then
       
  2106         begin
       
  2107         if (TurnTimeLeft = 0)
       
  2108         or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime))
       
  2109         or (CurrentHedgehog^.Gear = nil) then
       
  2110         begin
       
  2111         Gear^.FlightTime:= GameTicks;
       
  2112         Gear^.State := Gear^.State or gsttmpFlag;
       
  2113         Gear^.Hedgehog := nil;
       
  2114         end;
       
  2115         exit;
       
  2116         end;
       
  2117 
       
  2118     //Disable targeting while the airmine is stunned
       
  2119     if Gear^.Tag <> 0 then
       
  2120         begin
       
  2121         if ((Gear^.FlightTime and $FF) = 0) then
       
  2122             // spawn lots of particles when stunned (sparkles or bubbles)
       
  2123             if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) = false then
       
  2124                 begin
       
  2125                 sparkle:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtDust, 1);
       
  2126                 if sparkle <> nil then
       
  2127                     begin
       
  2128                         sparkle^.dX:= 0.004 * (random(100) - 50);
       
  2129                         sparkle^.dY:= -0.05 + 0.004 * (random(100) - 50);
       
  2130                         sparkle^.Tint:= $D5CD8CFF;
       
  2131                         sparkle^.Angle:= random(360);
       
  2132                     end;
       
  2133                 end
       
  2134             else
       
  2135                 AddVisualGear(hwRound(Gear^.X) - 8 + random(16), hwRound(Gear^.Y) + 16 + random(8), vgtBubble);
       
  2136 
       
  2137         dec(Gear^.FlightTime);
       
  2138         if Gear^.FlightTime = 0 then
       
  2139             begin
       
  2140             Gear^.Tag:= 0;
       
  2141             Gear^.Hedgehog:= nil;
       
  2142             Gear^.State:= Gear^.State and (not gstAttacking);
       
  2143             Gear^.Timer:= Gear^.WDTimer
       
  2144             end;
       
  2145         exit
       
  2146         end;
  1933 
  2147 
  1934     if (TurnTimeLeft = 0) or (Gear^.Angle = 0) or (Gear^.Hedgehog = nil) or (Gear^.Hedgehog^.Gear = nil) then
  2148     if (TurnTimeLeft = 0) or (Gear^.Angle = 0) or (Gear^.Hedgehog = nil) or (Gear^.Hedgehog^.Gear = nil) then
  1935         begin
  2149         begin
  1936         Gear^.Hedgehog:= nil;
  2150         Gear^.Hedgehog:= nil;
  1937         targ:= nil;
  2151         targ:= nil;
  1941     if targ <> nil then
  2155     if targ <> nil then
  1942         begin
  2156         begin
  1943         tX:=Gear^.X-targ^.X;
  2157         tX:=Gear^.X-targ^.X;
  1944         tY:=Gear^.Y-targ^.Y;
  2158         tY:=Gear^.Y-targ^.Y;
  1945         // allow escaping - should maybe flag this too
  2159         // allow escaping - should maybe flag this too
  1946         if (GameTicks > Gear^.FlightTime+10000) or 
  2160         if (GameTicks > Gear^.FlightTime + 10000) or
  1947             ((tX.Round+tY.Round > Gear^.Angle*6) and
  2161             (not ((tX.Round + tY.Round < Gear^.Angle * 9) and
  1948             (hwRound(hwSqr(tX) + hwSqr(tY)) > sqr(Gear^.Angle*6))) then
  2162                   (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Angle * 6))))
       
  2163              then
  1949             targ:= nil
  2164             targ:= nil
  1950         end;
  2165         end;
  1951 
  2166 
  1952     // If in ready timer, or after turn, or in first 5 seconds of turn (really a window due to extra time utility)
  2167     // If in ready timer, or after turn, or in first 5 seconds of turn (really a window due to extra time utility)
  1953     // or mine is inactive due to lack of gsttmpflag or hunting is disabled due to seek radius of 0
  2168     // or hunting is disabled due to seek radius of 0 then we aren't hunting
  1954     // then we aren't hunting
       
  1955     if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or 
  2169     if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or 
  1956         ((TurnTimeLeft < cHedgehogTurnTime) and (cHedgehogTurnTime-TurnTimeLeft < 5000)) or
  2170         ((TurnTimeLeft < cHedgehogTurnTime) and (cHedgehogTurnTime-TurnTimeLeft < 5000)) or
  1957         (Gear^.State and gsttmpFlag = 0) or
       
  1958         (Gear^.Angle = 0) then
  2171         (Gear^.Angle = 0) then
  1959         gear^.State:= gear^.State and (not gstChooseTarget)
  2172         gear^.State:= gear^.State and (not gstChooseTarget)
  1960     else if
  2173     else if
  1961     // todo, allow not finding new target, set timeout on target retention
  2174     // todo, allow not finding new target, set timeout on target retention
  1962         (Gear^.State and gstAttacking = 0) and
  2175         (Gear^.State and gstAttacking = 0) and
  1968              targDist:= Distance(Gear^.X-targ^.X,Gear^.Y-targ^.Y).Round
  2181              targDist:= Distance(Gear^.X-targ^.X,Gear^.Y-targ^.Y).Round
  1969         else targDist:= 0;
  2182         else targDist:= 0;
  1970         for t:= 0 to Pred(TeamsCount) do
  2183         for t:= 0 to Pred(TeamsCount) do
  1971             with TeamsArray[t]^ do
  2184             with TeamsArray[t]^ do
  1972                 for i:= 0 to cMaxHHIndex do
  2185                 for i:= 0 to cMaxHHIndex do
  1973                     if Hedgehogs[i].Gear <> nil then
  2186                     if (Hedgehogs[i].Gear <> nil) and (Hedgehogs[i].Effects[heFrozen] = 0) then
  1974                         begin
  2187                         begin
  1975                         tmpG:= Hedgehogs[i].Gear;
  2188                         tmpG:= Hedgehogs[i].Gear;
  1976                         tX:=Gear^.X-tmpG^.X;
  2189                         tX:=Gear^.X-tmpG^.X;
  1977                         tY:=Gear^.Y-tmpG^.Y;
  2190                         tY:=Gear^.Y-tmpG^.Y;
  1978                         if (Gear^.Angle = $FFFFFFFF) or
  2191                         if (Gear^.Angle = $FFFFFFFF) or
  2013         else if (Gear^.Y > targ^.Y) and (Gear^.dY > -_0_1) then
  2226         else if (Gear^.Y > targ^.Y) and (Gear^.dY > -_0_1) then
  2014             Gear^.dY:= Gear^.dY-trackSpeed
  2227             Gear^.dY:= Gear^.dY-trackSpeed
  2015         end
  2228         end
  2016     else Gear^.Hedgehog:= nil;
  2229     else Gear^.Hedgehog:= nil;
  2017 
  2230 
  2018     if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
  2231     if ((Gear^.State and gstAttacking) = 0) then
  2019         begin
  2232         begin
  2020         if ((Gear^.State and gstAttacking) = 0) then
  2233         if (((GameTicks+Gear^.Uid) and $1F) = 0) then
  2021             begin
  2234             begin
  2022             if ((GameTicks and $1F) = 0) then
  2235             if targ <> nil then
  2023                 begin
  2236                 begin
  2024                 if targ <> nil then
  2237                 tX:=Gear^.X-targ^.X;
  2025                     begin
  2238                 tY:=Gear^.Y-targ^.Y;
  2026                     tX:=Gear^.X-targ^.X;
  2239                 if (tX.Round+tY.Round < Gear^.Boom) and
  2027                     tY:=Gear^.Y-targ^.Y;
  2240                    (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Boom)) then
  2028                     if (tX.Round+tY.Round < Gear^.Karma) and
  2241                 Gear^.State := Gear^.State or gstAttacking
  2029                        (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Karma)) then
       
  2030                     Gear^.State := Gear^.State or gstAttacking
       
  2031                     end
       
  2032                 else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Karma, Gear^.Karma) <> nil) then
       
  2033                     Gear^.State := Gear^.State or gstAttacking
       
  2034                 end
  2242                 end
       
  2243             else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Boom, Gear^.Boom) <> nil) then
       
  2244                 Gear^.State := Gear^.State or gstAttacking
  2035             end
  2245             end
  2036         else // gstAttacking <> 0
  2246         end
  2037             begin
  2247     else // gstAttacking <> 0
  2038             AllInactive := false;
  2248         begin
  2039             if (Gear^.Timer and $FF) = 0 then
  2249         AllInactive := false;
  2040                 PlaySound(sndMineTick);
  2250         if (Gear^.Timer and $FF) = 0 then
  2041             if Gear^.Timer = 0 then
  2251             PlaySound(sndMineTick);
  2042                 begin
  2252         if Gear^.Timer = 0 then
  2043                 // recheck
  2253             begin
  2044                 if targ <> nil then
  2254             // recheck
  2045                     begin
  2255             if targ <> nil then
  2046                     tX:=Gear^.X-targ^.X;
  2256                 begin
  2047                     tY:=Gear^.Y-targ^.Y;
  2257                 tX:=Gear^.X-targ^.X;
  2048                     if (tX.Round+tY.Round < Gear^.Karma) and
  2258                 tY:=Gear^.Y-targ^.Y;
  2049                        (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Karma)) then
  2259                 if (tX.Round+tY.Round < Gear^.Boom) and
  2050                         begin
  2260                    (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Boom)) then
  2051                         Gear^.Hedgehog:= CurrentHedgehog;
       
  2052                         tmpG:= FollowGear;
       
  2053                         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Karma, Gear^.Hedgehog, EXPLAutoSound);
       
  2054                         FollowGear:= tmpG;
       
  2055                         DeleteGear(Gear);
       
  2056                         exit
       
  2057                         end
       
  2058                     end
       
  2059                 else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Karma, Gear^.Karma) <> nil) then
       
  2060                     begin
  2261                     begin
  2061                     Gear^.Hedgehog:= CurrentHedgehog;
  2262                     Gear^.Hedgehog:= CurrentHedgehog;
  2062                     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Karma, Gear^.Hedgehog, EXPLAutoSound);
  2263                     tmpG:= FollowGear;
       
  2264                     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
       
  2265                     FollowGear:= tmpG;
  2063                     DeleteGear(Gear);
  2266                     DeleteGear(Gear);
  2064                     exit
  2267                     exit
  2065                     end;
  2268                     end
  2066                 Gear^.State:= Gear^.State and (not gstAttacking);
  2269                 end
  2067                 Gear^.Timer:= Gear^.WDTimer
  2270             else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Boom, Gear^.Boom) <> nil) then
       
  2271                 begin
       
  2272                 Gear^.Hedgehog:= CurrentHedgehog;
       
  2273                 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
       
  2274                 DeleteGear(Gear);
       
  2275                 exit
  2068                 end;
  2276                 end;
  2069             if Gear^.Timer > 0 then
  2277             Gear^.State:= Gear^.State and (not gstAttacking);
  2070                 dec(Gear^.Timer);
  2278             Gear^.Timer:= Gear^.WDTimer
  2071             end
  2279             end;
  2072         end
  2280         if Gear^.Timer > 0 then
  2073     else // gsttmpFlag = 0
  2281             dec(Gear^.Timer);
  2074         if (TurnTimeLeft = 0)
       
  2075         or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime))
       
  2076         or (CurrentHedgehog^.Gear = nil) then
       
  2077         begin
       
  2078         Gear^.FlightTime:= GameTicks;
       
  2079         Gear^.State := Gear^.State or gsttmpFlag
       
  2080         end
  2282         end
  2081 end;
  2283 end;
  2082 
  2284 
  2083 ////////////////////////////////////////////////////////////////////////////////
  2285 ////////////////////////////////////////////////////////////////////////////////
  2084 procedure doStepSMine(Gear: PGear);
  2286 procedure doStepSMine(Gear: PGear);
  2107         doStepFallingGear(Gear);
  2309         doStepFallingGear(Gear);
  2108         AllInactive := false;
  2310         AllInactive := false;
  2109         CalcRotationDirAngle(Gear);
  2311         CalcRotationDirAngle(Gear);
  2110         end;
  2312         end;
  2111 
  2313 
       
  2314     Gear^.RenderTimer:= (Gear^.State and (gstFrozen or gstAttacking or gstDrowning) = 0);
  2112     if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
  2315     if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
  2113         begin
  2316         begin
  2114         if ((Gear^.State and gstAttacking) = 0) and ((Gear^.State and gstFrozen) = 0) then
  2317         if ((Gear^.State and gstAttacking) = 0) and ((Gear^.State and gstFrozen) = 0) then
  2115             begin
  2318             begin
  2116             if ((GameTicks and $1F) = 0) then
  2319             if ((GameTicks and $1F) = 0) then
  2146     AllInactive := false;
  2349     AllInactive := false;
  2147 
  2350 
  2148     if Gear^.Timer mod 166 = 0 then
  2351     if Gear^.Timer mod 166 = 0 then
  2149         inc(Gear^.Tag);
  2352         inc(Gear^.Tag);
  2150     if Gear^.Timer = 1000 then // might need better timing
  2353     if Gear^.Timer = 1000 then // might need better timing
  2151         makeHogsWorry(Gear^.X, Gear^.Y, 75);
  2354         makeHogsWorry(Gear^.X, Gear^.Y, 75, Gear^.Kind);
  2152     if Gear^.Timer = 0 then
  2355     if Gear^.Timer = 0 then
  2153         begin
  2356         begin
  2154         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  2357         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  2155         DeleteGear(Gear);
  2358         DeleteGear(Gear);
  2156         exit
  2359         exit
  2193             dmg:= hwRound(dxdy * _50);
  2396             dmg:= hwRound(dxdy * _50);
  2194             inc(Gear^.Damage, dmg);
  2397             inc(Gear^.Damage, dmg);
  2195             ScriptCall('onGearDamage', Gear^.UID, dmg)
  2398             ScriptCall('onGearDamage', Gear^.UID, dmg)
  2196             end;
  2399             end;
  2197         CalcRotationDirAngle(Gear);
  2400         CalcRotationDirAngle(Gear);
  2198         //CheckGearDrowning(Gear)
       
  2199         end
  2401         end
  2200     else
  2402     else
  2201         begin
  2403         begin
  2202         Gear^.State := Gear^.State or gsttmpFlag;
  2404         Gear^.State := Gear^.State or gsttmpFlag;
  2203         AddCI(Gear)
  2405         AddCI(Gear)
  2204         end;
  2406         end;
  2205 
       
  2206 (*
       
  2207 Attempt to make a barrel knock itself over an edge.  Would need more checks to avoid issues like burn damage
       
  2208     begin
       
  2209     x:= hwRound(Gear^.X);
       
  2210     y:= hwRound(Gear^.Y);
       
  2211     if (((y+1) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
       
  2212         if (Land[y+1, x] = 0) then
       
  2213             begin
       
  2214             if (((y+1) and LAND_HEIGHT_MASK) = 0) and (((x+Gear^.Radius-2) and LAND_WIDTH_MASK) = 0) and (Land[y+1, x+Gear^.Radius-2] = 0) then
       
  2215                 Gear^.dX:= -_0_08
       
  2216             else if (((y+1 and LAND_HEIGHT_MASK)) = 0) and (((x-(Gear^.Radius-2)) and LAND_WIDTH_MASK) = 0) and (Land[y+1, x-(Gear^.Radius-2)] = 0) then
       
  2217                 Gear^.dX:= _0_08;
       
  2218             end;
       
  2219     if Gear^.dX.QWordValue = 0 then AddCI(Gear)
       
  2220     end; *)
       
  2221 
  2407 
  2222     if not Gear^.dY.isNegative and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then
  2408     if not Gear^.dY.isNegative and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then
  2223         Gear^.dY := _0;
  2409         Gear^.dY := _0;
  2224     if hwAbs(Gear^.dX) < _0_001 then
  2410     if hwAbs(Gear^.dX) < _0_001 then
  2225         Gear^.dX := _0;
  2411         Gear^.dX := _0;
  2227     if (Gear^.Health > 0) and ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
  2413     if (Gear^.Health > 0) and ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
  2228         if (cBarrelHealth div Gear^.Health) > 2 then
  2414         if (cBarrelHealth div Gear^.Health) > 2 then
  2229             AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
  2415             AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
  2230     else
  2416     else
  2231         AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
  2417         AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
       
  2418 
  2232     dec(Gear^.Health, Gear^.Damage);
  2419     dec(Gear^.Health, Gear^.Damage);
  2233     Gear^.Damage := 0;
  2420     Gear^.Damage := 0;
  2234     if Gear^.Health <= 0 then
  2421     if Gear^.Health <= 0 then
  2235         doStepCase(Gear);
  2422         doStepCase(Gear)
       
  2423     else
       
  2424         // health texture (FlightTime = health when the last texture was generated)
       
  2425         if (Gear^.Health <> Gear^.FlightTime) or (Gear^.Tex = nil) then
       
  2426             begin
       
  2427             Gear^.FlightTime:= Gear^.Health;
       
  2428             FreeAndNilTexture(Gear^.Tex);
       
  2429             Gear^.Tex := RenderStringTex(ansistring(inttostr(Gear^.Health)), $ff808080, fnt16);
       
  2430             end;
  2236 end;
  2431 end;
  2237 
  2432 
  2238 procedure doStepCase(Gear: PGear);
  2433 procedure doStepCase(Gear: PGear);
  2239 var
  2434 var
  2240     i, x, y: LongInt;
  2435     i, x, y: LongInt;
  2262         begin
  2457         begin
  2263         x := hwRound(Gear^.X);
  2458         x := hwRound(Gear^.X);
  2264         y := hwRound(Gear^.Y);
  2459         y := hwRound(Gear^.Y);
  2265         hog:= Gear^.Hedgehog;
  2460         hog:= Gear^.Hedgehog;
  2266 
  2461 
  2267         DeleteGear(Gear);
       
  2268         // <-- delete gear!
       
  2269 
       
  2270         if k = gtCase then
  2462         if k = gtCase then
  2271             begin
  2463             begin
  2272             doMakeExplosion(x, y, Gear^.Boom, hog, EXPLAutoSound);
  2464             doMakeExplosion(x, y, Gear^.Boom, hog, EXPLAutoSound);
  2273             for i:= 0 to 63 do
  2465             for i:= 0 to 63 do
  2274                 AddGear(x, y, gtFlame, 0, _0, _0, 0);
  2466                 AddGear(x, y, gtFlame, 0, _0, _0, 0);
  2275             end
  2467             end
  2276         else if k = gtTarget then
  2468         else if k = gtTarget then
  2277             uStats.TargetHit()
  2469             uStats.TargetHit()
  2278         else if k = gtExplosives then
  2470         else if k = gtExplosives then
  2279                 begin
  2471             begin
  2280                 doMakeExplosion(x, y, Gear^.Boom, hog, EXPLAutoSound);
  2472             doMakeExplosion(x, y, Gear^.Boom, hog, EXPLAutoSound);
  2281                 for i:= 0 to 31 do
  2473             for i:= 0 to 31 do
  2282                     begin
  2474                 begin
  2283                     dX := AngleCos(i * 64) * _0_5 * (getrandomf + _1);
  2475                 dX := AngleCos(i * 64) * _0_5 * (getrandomf + _1);
  2284                     dY := AngleSin(i * 64) * _0_5 * (getrandomf + _1);
  2476                 dY := AngleSin(i * 64) * _0_5 * (getrandomf + _1);
  2285                     AddGear(x, y, gtFlame, 0, dX, dY, 0);
  2477                 AddGear(x, y, gtFlame, 0, dX, dY, 0);
  2286                     AddGear(x, y, gtFlame, gstTmpFlag, -dX, -dY, 0);
  2478                 AddGear(x, y, gtFlame, gstTmpFlag, -dX, -dY, 0);
  2287                     end
  2479                 end
  2288                 end;
  2480             end;
  2289             exit
  2481         DeleteGear(Gear);
       
  2482         exit
  2290         end;
  2483         end;
  2291 
  2484 
  2292     if k = gtExplosives then
  2485     if k = gtExplosives then
  2293         begin
  2486         begin
  2294         //if V > _0_03 then Gear^.State:= Gear^.State or gstAnimation;
       
  2295         if (hwAbs(Gear^.dX) > _0_15) or ((hwAbs(Gear^.dY) > _0_15) and (hwAbs(Gear^.dX) > _0_02)) then
  2487         if (hwAbs(Gear^.dX) > _0_15) or ((hwAbs(Gear^.dY) > _0_15) and (hwAbs(Gear^.dX) > _0_02)) then
  2296             begin
  2488             begin
  2297             Gear^.doStep := @doStepRollingBarrel;
  2489             Gear^.doStep := @doStepRollingBarrel;
  2298             exit;
  2490             exit;
  2299             end
  2491             end
  2302         if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
  2494         if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
  2303             if (cBarrelHealth div Gear^.Health) > 2 then
  2495             if (cBarrelHealth div Gear^.Health) > 2 then
  2304                 AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
  2496                 AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
  2305             else
  2497             else
  2306                 AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
  2498                 AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
       
  2499 
  2307         dec(Gear^.Health, Gear^.Damage);
  2500         dec(Gear^.Health, Gear^.Damage);
  2308         Gear^.Damage := 0;
  2501         Gear^.Damage := 0;
       
  2502         // health texture (FlightTime = health when the last texture was generated)
       
  2503         if (Gear^.Health <> Gear^.FlightTime) or (Gear^.Tex = nil) then
       
  2504             begin
       
  2505             Gear^.FlightTime:= Gear^.Health;
       
  2506             FreeAndNilTexture(Gear^.Tex);
       
  2507             Gear^.Tex := RenderStringTex(ansistring(inttostr(Gear^.Health)), $ff808080, fnt16);
       
  2508             end;
  2309         end
  2509         end
  2310     else
  2510     else
  2311         begin
  2511         begin
       
  2512         // health texture for health crate
       
  2513         if (k = gtCase) and ((Gear^.Pos and posCaseHealth) <> 0) then
       
  2514             begin
       
  2515             if ((Gear^.State and gstFrozen) = 0) then
       
  2516                 begin
       
  2517                 // Karma=2: Always hide health
       
  2518                 if (Gear^.Karma = 2) then
       
  2519                     i:= 0
       
  2520                 // Karma=1: Hide health in game, but show in demo
       
  2521                 else if (Gear^.Karma = 1) then
       
  2522                     if (GameType in [gmtDemo, gmtRecord]) then
       
  2523                         i:= 1
       
  2524                     else
       
  2525                         i:= 0
       
  2526                 // Always show health (default)
       
  2527                 else
       
  2528                     i:= 1;
       
  2529                 if i = 1 then
       
  2530                     begin
       
  2531                     if (Gear^.Health <> Gear^.FlightTime) or (Gear^.Tex = nil) then
       
  2532                         begin
       
  2533                         Gear^.FlightTime:= Gear^.Health;
       
  2534                         FreeAndNilTexture(Gear^.Tex);
       
  2535                         Gear^.Tex := RenderStringTex(ansistring(inttostr(Gear^.Health)), $ff80ff80, fnt16)
       
  2536                         end
       
  2537                     end
       
  2538                 else
       
  2539                     begin
       
  2540                     if (Gear^.FlightTime <> $ffffffff) or (Gear^.Tex = nil) then
       
  2541                         begin
       
  2542                         Gear^.FlightTime:= $ffffffff;
       
  2543                         FreeAndNilTexture(Gear^.Tex);
       
  2544                         Gear^.Tex := RenderStringTex(trmsg[sidUnknownGearValue], $ff80ff80, fnt16)
       
  2545                         end
       
  2546                     end
       
  2547                 end;
       
  2548             end;
  2312         if Gear^.Timer = 500 then
  2549         if Gear^.Timer = 500 then
  2313             begin
  2550             begin
  2314 (* Can't make sparkles team coloured without working out what the next team is going to be. This should be solved, really, since it also screws up
  2551 (* Can't make sparkles team coloured without working out what the next team is going to be. This should be solved, really, since it also screws up
  2315    voices. Reinforcements voices is heard for active team, not team-to-be.  Either that or change crate spawn from end of turn to start, although that
  2552    voices. Reinforcements voices is heard for active team, not team-to-be.  Either that or change crate spawn from end of turn to start, although that
  2316    has its own complexities. *)
  2553    has its own complexities. *)
  2369             if Gear^.dY > - _0_001 then
  2606             if Gear^.dY > - _0_001 then
  2370                 Gear^.dY := _0
  2607                 Gear^.dY := _0
  2371             else if Gear^.dY < - _0_03 then
  2608             else if Gear^.dY < - _0_03 then
  2372                 PlaySound(Gear^.ImpactSound);
  2609                 PlaySound(Gear^.ImpactSound);
  2373             end;
  2610             end;
  2374         //if Gear^.dY > - _0_001 then Gear^.dY:= _0
       
  2375         CheckGearDrowning(Gear);
  2611         CheckGearDrowning(Gear);
       
  2612         if ((Gear^.State and gstDrowning) <> 0) then
       
  2613             Gear^.RenderHealth:= false;
  2376         end;
  2614         end;
  2377 
  2615 
  2378     if (Gear^.dY.QWordValue = 0) then
  2616     if (Gear^.dY.QWordValue = 0) then
  2379         AddCI(Gear)
  2617         AddCI(Gear)
  2380     else if (Gear^.dY.QWordValue <> 0) then
  2618     else if (Gear^.dY.QWordValue <> 0) then
  2427 begin
  2665 begin
  2428     dec(Gear^.Timer);
  2666     dec(Gear^.Timer);
  2429     if Gear^.Timer = 0 then
  2667     if Gear^.Timer = 0 then
  2430         begin
  2668         begin
  2431         inc(Gear^.Tag);
  2669         inc(Gear^.Tag);
  2432         Gear^.Timer := 50
  2670         Gear^.Timer := 50;
       
  2671         if Gear^.Tag = 3 then
       
  2672             begin
       
  2673             ClearHitOrder();
       
  2674             RefillProximityCache(Gear, 100);
       
  2675             end;
  2433         end;
  2676         end;
  2434 
  2677 
  2435     if Gear^.Tag = 3 then
  2678     if Gear^.Tag = 3 then
  2436         begin
  2679         begin
  2437         HHGear := Gear^.Hedgehog^.Gear;
  2680         HHGear := Gear^.Hedgehog^.Gear;
  2438         HHGear^.State := HHGear^.State or gstNoDamage;
  2681         HHGear^.State := HHGear^.State or gstNoDamage;
  2439         DeleteCI(HHGear);
  2682         DeleteCI(HHGear);
  2440 
  2683 
  2441         AmmoShove(Gear, Gear^.Boom, 115);
  2684         AmmoShoveCache(Gear, Gear^.Boom, 115);
  2442 
  2685 
  2443         HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
  2686         HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
  2444         end
  2687         end
  2445     else if Gear^.Tag = 4 then
  2688     else if Gear^.Tag = 4 then
  2446         begin
  2689         begin
       
  2690         ClearHitOrder();
       
  2691         ClearProximityCache();
  2447         Gear^.Timer := 250;
  2692         Gear^.Timer := 250;
  2448         Gear^.doStep := @doStepIdle
  2693         Gear^.doStep := @doStepIdle
  2449         end
  2694         end
  2450 end;
  2695 end;
  2451 
  2696 
  2457 begin
  2702 begin
  2458     HHGear := Gear^.Hedgehog^.Gear;
  2703     HHGear := Gear^.Hedgehog^.Gear;
  2459     HHGear^.State := HHGear^.State or gstNoDamage;
  2704     HHGear^.State := HHGear^.State or gstNoDamage;
  2460     DeleteCI(HHGear);
  2705     DeleteCI(HHGear);
  2461 
  2706 
       
  2707     ClearHitOrder();
       
  2708     RefillProximityCache(Gear, 100);
  2462     for i:= 0 to 3 do
  2709     for i:= 0 to 3 do
  2463         begin
  2710         begin
  2464         AddVisualGear(hwRound(Gear^.X) + hwSign(Gear^.dX) * (10 + 6 * i), hwRound(Gear^.Y) + 12 + Random(6), vgtDust);
  2711         AddVisualGear(hwRound(Gear^.X) + hwSign(Gear^.dX) * (10 + 6 * i), hwRound(Gear^.Y) + 12 + Random(6), vgtDust);
  2465         AmmoShove(Gear, Gear^.Boom, 25);
  2712         AmmoShoveCache(Gear, Gear^.Boom, 25);
  2466         Gear^.X := Gear^.X + Gear^.dX * 5
  2713         Gear^.X := Gear^.X + Gear^.dX * 5
  2467         end;
  2714         end;
  2468 
  2715 
       
  2716     ClearHitOrder();
       
  2717     ClearProximityCache();
  2469     HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
  2718     HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
  2470 
  2719 
  2471     Gear^.Timer := 250;
  2720     Gear^.Timer := 250;
  2472     Gear^.doStep := @doStepIdle
  2721     Gear^.doStep := @doStepIdle
  2473 end;
  2722 end;
  2481     tdX,tdY, f: HWFloat;
  2730     tdX,tdY, f: HWFloat;
  2482     landPixel: Word;
  2731     landPixel: Word;
  2483 begin
  2732 begin
  2484     WorldWrap(Gear);
  2733     WorldWrap(Gear);
  2485     if Gear^.FlightTime > 0 then dec(Gear^.FlightTime);
  2734     if Gear^.FlightTime > 0 then dec(Gear^.FlightTime);
       
  2735     // There are 2 flame types: normal and sticky
  2486     sticky:= (Gear^.State and gsttmpFlag) <> 0;
  2736     sticky:= (Gear^.State and gsttmpFlag) <> 0;
  2487     if not sticky then AllInactive := false;
  2737     if not sticky then AllInactive := false;
  2488 
  2738 
  2489     landPixel:= TestCollisionYwithGear(Gear, 1);
  2739     landPixel:= TestCollisionYwithGear(Gear, 1);
       
  2740     // Flame is in mid-air
  2490     if landPixel = 0 then
  2741     if landPixel = 0 then
  2491         begin
  2742         begin
  2492         AllInactive := false;
  2743         AllInactive := false;
  2493 
  2744 
       
  2745         // Deals damage in mid-air if FlightTime = 0.
       
  2746         // Otherwise, flame is harmless in mid-air.
       
  2747         // Intended for use with scripts.
  2494         if (GameTicks and $F = 0) and (Gear^.FlightTime = 0) then
  2748         if (GameTicks and $F = 0) and (Gear^.FlightTime = 0) then
  2495             begin
  2749             begin
  2496             Gear^.Radius := 7;
  2750             Gear^.Radius := 7;
  2497             tdX:= Gear^.dX;
  2751             tdX:= Gear^.dX;
  2498             tdY:= Gear^.dY;
  2752             tdY:= Gear^.dY;
  2502             Gear^.dY.isNegative:= true;
  2756             Gear^.dY.isNegative:= true;
  2503             AmmoShove(Gear, Gear^.Boom, 125);
  2757             AmmoShove(Gear, Gear^.Boom, 125);
  2504             Gear^.dX:= tdX;
  2758             Gear^.dX:= tdX;
  2505             Gear^.dY:= tdY;
  2759             Gear^.dY:= tdY;
  2506             Gear^.Radius := 1
  2760             Gear^.Radius := 1
  2507 	    end;
  2761         end;
  2508 
  2762 
  2509         if ((GameTicks mod 100) = 0) then
  2763         if ((GameTicks mod 100) = 0) then
  2510             begin
  2764             begin
  2511             vgt:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFire, gstTmpFlag);
  2765             vgt:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFire, gstTmpFlag);
  2512             if vgt <> nil then
  2766             if vgt <> nil then
  2525             f:= _1_9 / Distance(Gear^.dX, Gear^.dY);
  2779             f:= _1_9 / Distance(Gear^.dX, Gear^.dY);
  2526             Gear^.dX:= Gear^.dX * f;
  2780             Gear^.dX:= Gear^.dX * f;
  2527             Gear^.dY:= Gear^.dY * f;
  2781             Gear^.dY:= Gear^.dY * f;
  2528         end
  2782         end
  2529         else begin
  2783         else begin
       
  2784             // Gravity and wind
  2530             if Gear^.dX.QWordValue > _0_01.QWordValue then
  2785             if Gear^.dX.QWordValue > _0_01.QWordValue then
  2531                     Gear^.dX := Gear^.dX * _0_995;
  2786                     Gear^.dX := Gear^.dX * _0_995;
  2532 
  2787 
  2533             Gear^.dY := Gear^.dY + cGravity;
  2788             Gear^.dY := Gear^.dY + cGravity;
  2534             // if sticky then Gear^.dY := Gear^.dY + cGravity;
       
  2535 
  2789 
  2536             if Gear^.dY.QWordValue > _0_2.QWordValue then
  2790             if Gear^.dY.QWordValue > _0_2.QWordValue then
  2537                 Gear^.dY := Gear^.dY * _0_995;
  2791                 Gear^.dY := Gear^.dY * _0_995;
  2538 
  2792 
  2539             //if sticky then Gear^.X := Gear^.X + Gear^.dX else
  2793             // Apply speed changes
  2540             Gear^.X := Gear^.X + Gear^.dX + cWindSpeed * 640;
  2794 
       
  2795             tdX:= Gear^.dX + cWindSpeed * 640;
       
  2796             // Don't apply wind speed if moving against bounce world edge
       
  2797             if (WorldEdge = weBounce) and
       
  2798                 (((hwRound(Gear^.X + tdX) - Gear^.Radius < leftX) and (hwSign(tdX) = -1)) or
       
  2799                 ((hwRound(Gear^.X + tdX) + Gear^.Radius > rightX) and (hwSign(tdX) = 1))) then
       
  2800                     Gear^.X := Gear^.X + Gear^.dX
       
  2801             else
       
  2802                 // Apply dX and wind speed
       
  2803                 Gear^.X := Gear^.X + tdX;
       
  2804 
  2541             Gear^.Y := Gear^.Y + Gear^.dY;
  2805             Gear^.Y := Gear^.Y + Gear^.dY;
  2542         end;
  2806         end;
  2543 
  2807 
  2544         gX := hwRound(Gear^.X);
  2808         gX := hwRound(Gear^.X);
  2545         gY := hwRound(Gear^.Y);
  2809         gY := hwRound(Gear^.Y);
  2546 
  2810 
       
  2811         // Extinguish in water
  2547         if CheckCoordInWater(gX, gY) then
  2812         if CheckCoordInWater(gX, gY) then
  2548             begin
  2813             begin
  2549             for i:= 0 to 3 do
  2814             for i:= 0 to 3 do
  2550                 AddVisualGear(gX - 8 + Random(16), gY - 8 + Random(16), vgtSteam);
  2815                 AddVisualGear(gX - 8 + Random(16), gY - 8 + Random(16), vgtSteam);
  2551             PlaySound(sndVaporize);
  2816             PlaySound(sndVaporize);
  2552             DeleteGear(Gear);
  2817             DeleteGear(Gear);
  2553             exit
  2818             exit
  2554             end
  2819             end
  2555         end
  2820         end
       
  2821     // Flame is on terrain
  2556     else
  2822     else
  2557         begin
  2823         begin
  2558         if (Gear^.Timer = 1) and (GameTicks and $3 = 0) then
  2824         if (Gear^.Timer = 1) and (GameTicks and $3 = 0) then
  2559             begin
  2825             begin
  2560             Gear^.Y:= Gear^.Y+_6;
  2826             Gear^.Y:= Gear^.Y+_6;
       
  2827             // Extinguish on ice
  2561             if (landPixel and lfIce <> 0) or (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
  2828             if (landPixel and lfIce <> 0) or (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
  2562                 begin
  2829                 begin
  2563                 gX := hwRound(Gear^.X);
  2830                 gX := hwRound(Gear^.X);
  2564                 gY := hwRound(Gear^.Y) - 6;
  2831                 gY := hwRound(Gear^.Y) - 6;
  2565                 DrawExplosion(gX, gY, 4);
  2832                 doMakeExplosion(gX, gY, 4, Gear^.Hedgehog, EXPLNoDamage or EXPLDoNotTouchAny or EXPLNoGfx);
  2566                 PlaySound(sndVaporize);
  2833                 PlaySound(sndVaporize);
  2567                 AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSteam);
  2834                 AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSteam);
  2568                 DeleteGear(Gear);
  2835                 DeleteGear(Gear);
  2569                 exit
  2836                 exit
  2570                 end;
  2837                 end;
  2571             Gear^.Y:= Gear^.Y-_6
  2838             Gear^.Y:= Gear^.Y-_6
  2572             end;
  2839             end;
       
  2840         // Sticky flame damage
  2573         if sticky and (GameTicks and $F = 0) then
  2841         if sticky and (GameTicks and $F = 0) then
  2574             begin
  2842             begin
  2575             Gear^.Radius := 7;
  2843             Gear^.Radius := 7;
  2576             tdX:= Gear^.dX;
  2844             tdX:= Gear^.dX;
  2577             tdY:= Gear^.dY;
  2845             tdY:= Gear^.dY;
  2588             begin
  2856             begin
  2589             dec(Gear^.Timer);
  2857             dec(Gear^.Timer);
  2590             inc(Gear^.Damage)
  2858             inc(Gear^.Damage)
  2591             end
  2859             end
  2592         else
  2860         else
       
  2861             // Flame burn-down handling
  2593             begin
  2862             begin
  2594             gX := hwRound(Gear^.X);
  2863             gX := hwRound(Gear^.X);
  2595             gY := hwRound(Gear^.Y);
  2864             gY := hwRound(Gear^.Y);
  2596             // Standard fire
  2865             // Normal flame: Burns down quickly and must be destroyed before the turn ends
  2597             if not sticky then
  2866             if not sticky then
  2598                 begin
  2867                 begin
       
  2868                 // Deal damage
  2599                 if ((GameTicks and $1) = 0) then
  2869                 if ((GameTicks and $1) = 0) then
  2600                     begin
  2870                     begin
  2601                     Gear^.Radius := 7;
  2871                     Gear^.Radius := 7;
  2602                     tdX:= Gear^.dX;
  2872                     tdX:= Gear^.dX;
  2603                     tdY:= Gear^.dY;
  2873                     tdY:= Gear^.dY;
  2609                     Gear^.dX:= tdX;
  2879                     Gear^.dX:= tdX;
  2610                     Gear^.dY:= tdY;
  2880                     Gear^.dY:= tdY;
  2611                     Gear^.Radius := 1;
  2881                     Gear^.Radius := 1;
  2612                     end
  2882                     end
  2613                 else if ((GameTicks and $3) = 3) then
  2883                 else if ((GameTicks and $3) = 3) then
  2614                     doMakeExplosion(gX, gY, Gear^.Boom * 4, Gear^.Hedgehog, 0);//, EXPLNoDamage);
  2884                     doMakeExplosion(gX, gY, Gear^.Boom * 4, Gear^.Hedgehog, 0);
  2615                 //DrawExplosion(gX, gY, 4);
       
  2616 
  2885 
  2617                 if ((GameTicks and $7) = 0) and (Random(2) = 0) then
  2886                 if ((GameTicks and $7) = 0) and (Random(2) = 0) then
  2618                     for i:= Random(2) downto 0 do
  2887                     for i:= Random(2) downto 0 do
  2619                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2888                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2620 
  2889 
       
  2890                 // Flame burn-out due to time
  2621                 if Gear^.Health > 0 then
  2891                 if Gear^.Health > 0 then
  2622                     dec(Gear^.Health);
  2892                     dec(Gear^.Health);
       
  2893 
       
  2894                 // Calculate time for next flame update with a bit of random jitter
  2623                 Gear^.Timer := 450 - Gear^.Tag * 8 + LongInt(GetRandom(2))
  2895                 Gear^.Timer := 450 - Gear^.Tag * 8 + LongInt(GetRandom(2))
  2624                 end
  2896                 end
       
  2897             // Sticky flame: Burns down slowly and persists between turns
  2625             else
  2898             else
  2626                 begin
  2899                 begin
  2627                 // Modified fire
  2900                 // Destroy land very slowly (low chance this gets called)
  2628                 if ((GameTicks and $7FF) = 0) and ((GameFlags and gfSolidLand) = 0) then
  2901                 if ((GameTicks and $7FF) = 0) and ((GameFlags and gfSolidLand) = 0) then
  2629                     begin
  2902                     begin
  2630                     DrawExplosion(gX, gY, 4);
  2903                     doMakeExplosion(gX, gY, 4, Gear^.Hedgehog, EXPLNoDamage or EXPLDoNotTouchAny or EXPLNoGfx);
  2631 
  2904 
  2632                     for i:= Random(3) downto 0 do
  2905                     for i:= Random(3) downto 0 do
  2633                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2906                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2634                     end;
  2907                     end;
  2635 
  2908 
  2636 // This one is interesting.  I think I understand the purpose, but I wonder if a bit more fuzzy of kicking could be done with getrandom.
  2909                 // Calculate time for next flame update with a bit of random jitter
  2637                 Gear^.Timer := 100 - Gear^.Tag * 3 + LongInt(GetRandom(2));
  2910                 Gear^.Timer := 100 - Gear^.Tag * 3 + LongInt(GetRandom(2));
       
  2911 
       
  2912                 // Flame burn-out due to time
  2638                 if (Gear^.Damage > 3000+Gear^.Tag*1500) then
  2913                 if (Gear^.Damage > 3000+Gear^.Tag*1500) then
  2639                     Gear^.Health := 0
  2914                     Gear^.Health := 0
  2640                 end
  2915                 end
  2641             end
  2916             end
  2642         end;
  2917         end;
       
  2918     // This kills the flame
  2643     if Gear^.Health = 0 then
  2919     if Gear^.Health = 0 then
  2644         begin
  2920         begin
  2645         gX := hwRound(Gear^.X);
  2921         gX := hwRound(Gear^.X);
  2646         gY := hwRound(Gear^.Y);
  2922         gY := hwRound(Gear^.Y);
  2647         if not sticky then
  2923         if not sticky then
  2653         else
  2929         else
  2654             for i:= Random(3) downto 0 do
  2930             for i:= Random(3) downto 0 do
  2655                 AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2931                 AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2656 
  2932 
  2657         DeleteGear(Gear)
  2933         DeleteGear(Gear)
  2658         end;
  2934         end
  2659 end;
  2935 end;
  2660 
  2936 
  2661 ////////////////////////////////////////////////////////////////////////////////
  2937 ////////////////////////////////////////////////////////////////////////////////
  2662 procedure doStepFirePunchWork(Gear: PGear);
  2938 procedure doStepFirePunchWork(Gear: PGear);
  2663 var
  2939 var
  2676         begin
  2952         begin
  2677         Gear^.Tag := hwRound(HHGear^.Y);
  2953         Gear^.Tag := hwRound(HHGear^.Y);
  2678         DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y - _1, _0_5, _0, cHHRadius * 4+2, 2);
  2954         DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y - _1, _0_5, _0, cHHRadius * 4+2, 2);
  2679         HHGear^.State := HHGear^.State or gstNoDamage;
  2955         HHGear^.State := HHGear^.State or gstNoDamage;
  2680         Gear^.Y := HHGear^.Y;
  2956         Gear^.Y := HHGear^.Y;
  2681         AmmoShove(Gear, Gear^.Boom, 40);
  2957         AmmoShoveCache(Gear, Gear^.Boom, 40);
  2682         HHGear^.State := HHGear^.State and (not gstNoDamage)
  2958         HHGear^.State := HHGear^.State and (not gstNoDamage)
  2683         end;
  2959         end;
  2684 
  2960 
  2685     HHGear^.dY := HHGear^.dY + cGravity;
  2961     HHGear^.dY := HHGear^.dY + cGravity;
  2686     if Gear^.Timer > 0 then dec(Gear^.Timer);
  2962     if Gear^.Timer > 0 then dec(Gear^.Timer);
  2687     if not (HHGear^.dY.isNegative) or (Gear^.Timer = 0) then
  2963     if not (HHGear^.dY.isNegative) or (Gear^.Timer = 0) then
  2688         begin
  2964         begin
  2689         HHGear^.State := HHGear^.State or gstMoving;
  2965         HHGear^.State := HHGear^.State or gstMoving;
       
  2966         ClearHitOrder();
       
  2967         ClearProximityCache();
  2690         DeleteGear(Gear);
  2968         DeleteGear(Gear);
  2691         AfterAttack;
  2969         AfterAttack;
  2692         exit
  2970         exit
  2693         end;
  2971         end;
  2694 
  2972 
  2695     if CheckLandValue(hwRound(HHGear^.X), hwRound(HHGear^.Y + HHGear^.dY + SignAs(_6,Gear^.dY)),
  2973     if CheckLandValue(hwRound(HHGear^.X), hwRound(HHGear^.Y + HHGear^.dY + SignAs(_6,Gear^.dY)),
  2696         lfIndestructible) then
  2974         lfIndestructible) then
  2697             HHGear^.Y := HHGear^.Y + HHGear^.dY
  2975             HHGear^.Y := HHGear^.Y + HHGear^.dY;
       
  2976 
       
  2977     if (Gear^.Timer mod 200) = 0 then
       
  2978         RefillProximityCache(Gear, 300);
  2698 end;
  2979 end;
  2699 
  2980 
  2700 procedure doStepFirePunch(Gear: PGear);
  2981 procedure doStepFirePunch(Gear: PGear);
  2701 var
  2982 var
  2702     HHGear: PGear;
  2983     HHGear: PGear;
  2703 begin
  2984 begin
  2704     AllInactive := false;
  2985     AllInactive := false;
  2705     HHGear := Gear^.Hedgehog^.Gear;
  2986     HHGear := Gear^.Hedgehog^.Gear;
  2706     DeleteCI(HHGear);
  2987     DeleteCI(HHGear);
  2707     //HHGear^.X := int2hwFloat(hwRound(HHGear^.X)) - _0_5; WTF?
       
  2708     HHGear^.dX := SignAs(cLittle, Gear^.dX);
  2988     HHGear^.dX := SignAs(cLittle, Gear^.dX);
  2709 
  2989 
  2710     HHGear^.dY := - _0_3;
  2990     HHGear^.dY := - _0_3;
       
  2991 
       
  2992     ClearHitOrder();
       
  2993     RefillProximityCache(Gear, 300);
  2711 
  2994 
  2712     Gear^.X := HHGear^.X;
  2995     Gear^.X := HHGear^.X;
  2713     Gear^.dX := SignAs(_0_45, Gear^.dX);
  2996     Gear^.dX := SignAs(_0_45, Gear^.dX);
  2714     Gear^.dY := - _0_9;
  2997     Gear^.dY := - _0_9;
  2715     Gear^.doStep := @doStepFirePunchWork;
  2998     Gear^.doStep := @doStepFirePunchWork;
  2721 ////////////////////////////////////////////////////////////////////////////////
  3004 ////////////////////////////////////////////////////////////////////////////////
  2722 
  3005 
  2723 procedure doStepParachuteWork(Gear: PGear);
  3006 procedure doStepParachuteWork(Gear: PGear);
  2724 var
  3007 var
  2725     HHGear: PGear;
  3008     HHGear: PGear;
       
  3009     deltaX, deltaY: hwFloat;
  2726 begin
  3010 begin
  2727     HHGear := Gear^.Hedgehog^.Gear;
  3011     HHGear := Gear^.Hedgehog^.Gear;
  2728 
  3012 
  2729     inc(Gear^.Timer);
  3013     inc(Gear^.Timer);
  2730 
  3014 
  2734     or ((Gear^.Message and gmAttack) <> 0) then
  3018     or ((Gear^.Message and gmAttack) <> 0) then
  2735         begin
  3019         begin
  2736         with HHGear^ do
  3020         with HHGear^ do
  2737             begin
  3021             begin
  2738             Message := 0;
  3022             Message := 0;
       
  3023             if Gear^.Tag = 1 then
       
  3024                 dX := _1
       
  3025             else
       
  3026                 dX := - _1;
  2739             SetLittle(dX);
  3027             SetLittle(dX);
  2740             dY := _0;
  3028             dY := _0;
  2741             State := State or gstMoving;
  3029             State := State or gstMoving;
  2742             end;
  3030             end;
  2743         DeleteGear(Gear);
  3031         if (GetAmmoEntry(HHGear^.Hedgehog^, amParachute)^.Count >= 1) and ((Ammoz[HHGear^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) and (HHGear^.Hedgehog^.MultiShootAttacks = 0) then
  2744         if (GetAmmoEntry(HHGear^.Hedgehog^, amParachute)^.Count >= 1) and ((Ammoz[HHGear^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
       
  2745             HHGear^.Hedgehog^.CurAmmoType:= amParachute;
  3032             HHGear^.Hedgehog^.CurAmmoType:= amParachute;
  2746         isCursorVisible := false;
  3033         isCursorVisible := false;
  2747         ApplyAmmoChanges(HHGear^.Hedgehog^);
  3034         ApplyAmmoChanges(HHGear^.Hedgehog^);
       
  3035         DeleteGear(Gear);
  2748         exit
  3036         exit
  2749         end;
  3037         end;
  2750 
  3038 
  2751     HHGear^.X := HHGear^.X + cWindSpeed * 200;
  3039     deltaX:= _0;
       
  3040     deltaX:= deltaX + cWindSpeed * 200;
       
  3041     deltaY:= _0;
  2752 
  3042 
  2753     if (Gear^.Message and gmLeft) <> 0 then
  3043     if (Gear^.Message and gmLeft) <> 0 then
  2754         HHGear^.X := HHGear^.X - cMaxWindSpeed * 80
  3044         deltaX := deltaX - cMaxWindSpeed * 80
  2755 
  3045 
  2756     else if (Gear^.Message and gmRight) <> 0 then
  3046     else if (Gear^.Message and gmRight) <> 0 then
  2757         HHGear^.X := HHGear^.X + cMaxWindSpeed * 80;
  3047         deltaX := deltaX + cMaxWindSpeed * 80;
  2758 
  3048 
  2759     if (Gear^.Message and gmUp) <> 0 then
  3049     if (Gear^.Message and gmUp) <> 0 then
  2760         HHGear^.Y := HHGear^.Y - cGravity * 40
  3050         deltaY := deltaY - cGravity * 40
  2761 
  3051 
  2762     else if (Gear^.Message and gmDown) <> 0 then
  3052     else if (Gear^.Message and gmDown) <> 0 then
  2763         HHGear^.Y := HHGear^.Y + cGravity * 40;
  3053         deltaY := deltaY + cGravity * 40;
  2764 
  3054 
       
  3055     HHGear^.X := HHGear^.X + deltaX;
  2765     // don't drift into obstacles
  3056     // don't drift into obstacles
  2766     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) <> 0 then
  3057     if TestCollisionXwithGear(HHGear, hwSign(deltaX)) <> 0 then
  2767         HHGear^.X := HHGear^.X - int2hwFloat(hwSign(HHGear^.dX));
  3058         begin
  2768     HHGear^.Y := HHGear^.Y + cGravity * 100;
  3059         HHGear^.X := HHGear^.X - int2hwFloat(hwSign(deltaX));
       
  3060         deltaX:= _0;
       
  3061         end;
       
  3062     deltaY := deltaY + cGravity * 100;
       
  3063     HHGear^.Y := HHGear^.Y + deltaY;
       
  3064 
       
  3065     HHGear^.dX := deltaX;
       
  3066     HHGear^.dY := deltaY;
       
  3067 
  2769     Gear^.X := HHGear^.X;
  3068     Gear^.X := HHGear^.X;
  2770     Gear^.Y := HHGear^.Y
  3069     Gear^.Y := HHGear^.Y
  2771 end;
  3070 end;
  2772 
  3071 
  2773 procedure doStepParachute(Gear: PGear);
  3072 procedure doStepParachute(Gear: PGear);
  2793     doStepParachuteWork(Gear)
  3092     doStepParachuteWork(Gear)
  2794 end;
  3093 end;
  2795 
  3094 
  2796 ////////////////////////////////////////////////////////////////////////////////
  3095 ////////////////////////////////////////////////////////////////////////////////
  2797 procedure doStepAirAttackWork(Gear: PGear);
  3096 procedure doStepAirAttackWork(Gear: PGear);
       
  3097 var uw, nuw: boolean;
       
  3098     tmpFloat: hwFloat;
       
  3099     i: LongInt;
  2798 begin
  3100 begin
  2799     AllInactive := false;
  3101     AllInactive := false;
       
  3102     if (WorldEdge = weWrap) then
       
  3103         if (WorldWrap(Gear)) then
       
  3104             inc(Gear^.Power);
  2800     Gear^.X := Gear^.X + cAirPlaneSpeed * Gear^.Tag;
  3105     Gear^.X := Gear^.X + cAirPlaneSpeed * Gear^.Tag;
  2801 
  3106     if (Gear^.Health > 0) and (Gear^.Power >= Gear^.WDTimer) and (((Gear^.Tag = 1) and (not (Gear^.X < Gear^.dX))) or ((Gear^.Tag = -1) and (not (Gear^.X > Gear^.dX)))) then
  2802     if (Gear^.Health > 0) and (not (Gear^.X < Gear^.dX)) and (Gear^.X < Gear^.dX + cAirPlaneSpeed) then
       
  2803         begin
  3107         begin
  2804         dec(Gear^.Health);
  3108         dec(Gear^.Health);
  2805             case Gear^.State of
  3109         Gear^.FlightTime:= 0;
  2806                 0: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
  3110         // Spawn missile
  2807                 1: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine,    0, cBombsSpeed * Gear^.Tag, _0, 0);
  3111         case Gear^.State of
  2808                 2: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtNapalmBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
  3112             0: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
  2809                 3: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtDrill, gsttmpFlag, cBombsSpeed * Gear^.Tag, _0, Gear^.Timer + 1);
  3113             1: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine,    0, cBombsSpeed * Gear^.Tag, _0, 0);
  2810             //4: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtWaterMelon, 0, cBombsSpeed *
  3114             2: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtNapalmBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
  2811             //                 Gear^.Tag, _0, 5000);
  3115             3: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtDrill, gsttmpFlag, cBombsSpeed * Gear^.Tag, _0, Gear^.Timer + 1);
  2812             end;
  3116         end;
  2813         Gear^.dX := Gear^.dX + int2hwFloat(Gear^.Damage * Gear^.Tag);
  3117         Gear^.dX := Gear^.X + int2hwFloat(Gear^.Damage * Gear^.Tag);
       
  3118         if (WorldEdge = weWrap) then
       
  3119             begin
       
  3120             Gear^.dX := int2hwFloat(CalcWorldWrap(hwRound(Gear^.dX), 0));
       
  3121             if (((Gear^.Tag = 1) and (not (Gear^.X < Gear^.dX))) or ((Gear^.Tag = -1) and (not (Gear^.X > Gear^.dX)))) then
       
  3122                 inc(Gear^.WDTimer);
       
  3123             end;
       
  3124 
  2814         if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then
  3125         if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then
  2815             FollowGear^.State:= FollowGear^.State or gstSubmersible;
  3126             FollowGear^.State:= FollowGear^.State or gstSubmersible;
       
  3127         end;
       
  3128 
       
  3129     if (Gear^.Health = 0) then
       
  3130         inc(Gear^.FlightTime);
       
  3131 
       
  3132     if (Gear^.SoundChannel <> -1) and (WorldEdge <> weSea) and (Gear^.FlightTime > 20) then
       
  3133         begin
  2816         StopSoundChan(Gear^.SoundChannel, 4000);
  3134         StopSoundChan(Gear^.SoundChannel, 4000);
  2817         end;
  3135         Gear^.SoundChannel := -1;
  2818 
  3136         end;
       
  3137 
       
  3138     // Particles
  2819     if (GameTicks and $3F) = 0 then
  3139     if (GameTicks and $3F) = 0 then
  2820         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  3140         if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then
  2821 
  3141             begin
  2822     if (hwRound(Gear^.X) > (max(LAND_WIDTH,4096)+2048)) or (hwRound(Gear^.X) < -2048) then
  3142             // air plane bubbles
  2823         begin
  3143             for i:=1 to 3 do
  2824         // avoid to play forever (is this necessary?)
  3144                 AddVisualGear(hwRound(Gear^.X) - 8 + Random(16), hwRound(Gear^.Y) - 8 + Random(16), vgtBubble);
       
  3145             // pilot's snorkel bubbles
       
  3146             if random(2) = 0 then
       
  3147                 AddVisualGear(hwRound(Gear^.X) + 10, hwRound(Gear^.Y) - 50, vgtBubble);
       
  3148             end
       
  3149         else
       
  3150             // smoke
       
  3151             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
       
  3152 
       
  3153     // Get rid of gear and cleanup
       
  3154     if ((WorldEdge = weWrap) and (Gear^.FlightTime >= 4000)) or
       
  3155         ((WorldEdge <> weWrap) and (((hwRound(Gear^.X) - Gear^.Radius > (max(LAND_WIDTH,4096)+2048)) or (hwRound(Gear^.X) + Gear^.Radius < -2048) or ((Gear^.Message and gmDestroy) > 0)))) then
       
  3156         begin
       
  3157         // fail-safe: instanly stop sound if it wasn't disabled before
       
  3158         if (Gear^.SoundChannel <> -1) then
       
  3159             begin
       
  3160             StopSoundChan(Gear^.SoundChannel);
       
  3161             Gear^.SoundChannel := -1;
       
  3162             end;
       
  3163         if (WorldEdge = weWrap) then
       
  3164             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBigExplosion);
       
  3165         DeleteGear(Gear);
       
  3166         exit;
       
  3167         end;
       
  3168 
       
  3169     uw := (Gear^.Karma <> 0); // Was plane underwater last tick?
       
  3170     nuw := CheckCoordInWater(hwRound(Gear^.X) + Gear^.Radius * Gear^.Tag, hwRound(Gear^.Y)); // Is plane underwater now?
       
  3171 
       
  3172     // if water entered or left
       
  3173     if nuw <> uw then
       
  3174         begin
       
  3175         tmpFloat:= Gear^.dX;
       
  3176         Gear^.dX := cAirPlaneSpeed * Gear^.Tag;
       
  3177         AddSplashForGear(Gear, false);
       
  3178         Gear^.dX := tmpFloat;
  2825         StopSoundChan(Gear^.SoundChannel);
  3179         StopSoundChan(Gear^.SoundChannel);
  2826         DeleteGear(Gear)
  3180         if nuw then
  2827         end;
  3181             begin
       
  3182             Gear^.SoundChannel := LoopSound(sndPlaneWater);
       
  3183             StopSoundChan(Gear^.SoundChannel, 4000);
       
  3184             Gear^.SoundChannel := -1;
       
  3185             Gear^.Karma := 1;
       
  3186             end
       
  3187         else
       
  3188             begin
       
  3189             Gear^.SoundChannel := LoopSound(sndPlane);
       
  3190             Gear^.Karma := 0;
       
  3191             end;
       
  3192         end;
       
  3193 
  2828 end;
  3194 end;
  2829 
  3195 
  2830 procedure doStepAirAttack(Gear: PGear);
  3196 procedure doStepAirAttack(Gear: PGear);
       
  3197 var HHGear: PGear;
  2831 begin
  3198 begin
  2832     AllInactive := false;
  3199     AllInactive := false;
  2833 
  3200 
       
  3201     if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) then
       
  3202         HHGear:= Gear^.Hedgehog^.Gear;
       
  3203 
       
  3204     if (HHGear <> nil) then
       
  3205         PlaySoundV(sndIncoming, Gear^.Hedgehog^.Team^.voicepack);
       
  3206     AfterAttack;
       
  3207     CurAmmoGear := nil;
       
  3208 
  2834     if Gear^.X.QWordValue = 0 then
  3209     if Gear^.X.QWordValue = 0 then
  2835         begin
  3210         begin
  2836         Gear^.Tag :=  1;
  3211         Gear^.Tag :=  1;
  2837         Gear^.X := -_2048;
  3212         if (WorldEdge = weWrap) then
       
  3213             Gear^.X := int2hwFloat(CalcWorldWrap(Gear^.Target.X + max(384, LAND_WIDTH shr 2), 0))
       
  3214         else
       
  3215             Gear^.X := -_2048;
  2838         end
  3216         end
  2839     else
  3217     else
  2840         begin
  3218         begin
  2841         Gear^.Tag := -1;
  3219         Gear^.Tag := -1;
  2842         Gear^.X := int2hwFloat(max(LAND_WIDTH,4096) + 2048);
  3220         if (WorldEdge = weWrap) then
  2843         end;
  3221             Gear^.X := int2hwFloat(CalcWorldWrap(Gear^.Target.X - max(384, LAND_WIDTH shr 2), 0))
  2844 
  3222         else
  2845     Gear^.Y := int2hwFloat(topY-300);
  3223             Gear^.X := int2hwFloat(max(LAND_WIDTH,4096) + 2048);
       
  3224         end;
       
  3225 
       
  3226     Gear^.Y := int2hwFloat(topY - 300);
       
  3227 
       
  3228     // Appear out of nowhere in wrap
       
  3229     if (WorldEdge = weWrap) then
       
  3230         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBigExplosion);
       
  3231 
  2846     Gear^.dX := int2hwFloat(Gear^.Target.X) - int2hwFloat(Gear^.Tag * (Gear^.Health-1) * Gear^.Damage) / 2;
  3232     Gear^.dX := int2hwFloat(Gear^.Target.X) - int2hwFloat(Gear^.Tag * (Gear^.Health-1) * Gear^.Damage) / 2;
  2847 
  3233 
  2848     // calcs for Napalm Strike, so that it will hit the target (without wind at least :P)
  3234     // calcs for Napalm Strike, so that it will hit the target (without wind at least :P)
  2849     if (Gear^.State = 2) then
  3235     if (Gear^.State = 2) then
  2850         Gear^.dX := Gear^.dX - cBombsSpeed * Gear^.Tag * 900
  3236         Gear^.dX := Gear^.dX - cBombsSpeed * Gear^.Tag * 900
  2851     // calcs for regular falling gears
  3237     // calcs for regular falling gears
  2852     else if (int2hwFloat(Gear^.Target.Y) - Gear^.Y > _0) then
  3238     else if (int2hwFloat(Gear^.Target.Y) - Gear^.Y > _0) then
  2853             Gear^.dX := Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(Gear^.Target.Y) - Gear^.Y) * 2 /
  3239             Gear^.dX := Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(Gear^.Target.Y) - Gear^.Y) * 2 /
  2854                 cGravity) * Gear^.Tag;
  3240                 cGravity) * Gear^.Tag;
  2855 
  3241 
       
  3242     if (WorldEdge = weWrap) then
       
  3243         begin
       
  3244         Gear^.dX := int2hwFloat(CalcWorldWrap(hwRound(Gear^.dX), 0));
       
  3245         if (((Gear^.Tag = 1) and (not (Gear^.X < Gear^.dX))) or ((Gear^.Tag = -1) and (not (Gear^.X > Gear^.dX)))) then
       
  3246             Gear^.WDTimer:= 1;
       
  3247         end;
       
  3248 
  2856     Gear^.doStep := @doStepAirAttackWork;
  3249     Gear^.doStep := @doStepAirAttackWork;
  2857     Gear^.SoundChannel := LoopSound(sndPlane, 4000);
  3250 
       
  3251     if (WorldEdge = weSea) then
       
  3252         begin
       
  3253         Gear^.SoundChannel := LoopSound(sndPlaneWater, 4000);
       
  3254         Gear^.Karma := 1;
       
  3255         end
       
  3256     else if  (WorldEdge = weWrap) then
       
  3257         begin
       
  3258         Gear^.SoundChannel := LoopSound(sndPlane, 500);
       
  3259         Gear^.Karma := 0;
       
  3260         end
       
  3261     else
       
  3262         begin
       
  3263         Gear^.SoundChannel := LoopSound(sndPlane, 4000);
       
  3264         Gear^.Karma := 0;
       
  3265         end;
  2858 
  3266 
  2859 end;
  3267 end;
  2860 
  3268 
  2861 ////////////////////////////////////////////////////////////////////////////////
  3269 ////////////////////////////////////////////////////////////////////////////////
  2862 
  3270 
  2865     AllInactive := false;
  3273     AllInactive := false;
  2866     doStepFallingGear(Gear);
  3274     doStepFallingGear(Gear);
  2867     if (Gear^.State and gstCollision) <> 0 then
  3275     if (Gear^.State and gstCollision) <> 0 then
  2868         begin
  3276         begin
  2869         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  3277         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  2870         DeleteGear(Gear);
       
  2871         {$IFNDEF PAS2C}
  3278         {$IFNDEF PAS2C}
  2872         with mobileRecord do
  3279         with mobileRecord do
  2873             if (performRumble <> nil) and (not fastUntilLag) then
  3280             if (performRumble <> nil) and (not fastUntilLag) then
  2874                 performRumble(kSystemSoundID_Vibrate);
  3281                 performRumble(kSystemSoundID_Vibrate);
  2875         {$ENDIF}
  3282         {$ENDIF}
       
  3283         DeleteGear(Gear);
  2876         exit
  3284         exit
  2877         end;
  3285         end;
  2878     if (GameTicks and $3F) = 0 then
  3286     if (GameTicks and $3F) = 0 then
  2879         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
  3287         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
  2880 end;
  3288 end;
  2926         end
  3334         end
  2927     else
  3335     else
  2928         begin
  3336         begin
  2929         PlaySound(sndPlaced);
  3337         PlaySound(sndPlaced);
  2930         DeleteGear(Gear);
  3338         DeleteGear(Gear);
  2931         AfterAttack;
  3339         AfterAttack
  2932         end;
  3340         end;
  2933 
  3341 
  2934     HHGear^.State := HHGear^.State and (not (gstAttacking or gstAttacked));
  3342     HHGear^.State := HHGear^.State and (not (gstAttacking or gstAttacked));
  2935     HHGear^.Message := HHGear^.Message and (not gmAttack);
  3343     HHGear^.Message := HHGear^.Message and (not gmAttack);
  2936 end;
  3344 end;
  2945     // if not infattack mode wait for hedgehog finish falling to collect cases
  3353     // if not infattack mode wait for hedgehog finish falling to collect cases
  2946     if ((GameFlags and gfInfAttack) <> 0)
  3354     if ((GameFlags and gfInfAttack) <> 0)
  2947     or (HHGear = nil)
  3355     or (HHGear = nil)
  2948     or ((HHGear^.State and gstMoving) = 0)
  3356     or ((HHGear^.State and gstMoving) = 0)
  2949     or (HHGear^.Damage > 0)
  3357     or (HHGear^.Damage > 0)
  2950     or ((HHGear^.State and gstDrowning) = 1) then
  3358     or ((HHGear^.State and gstDrowning) <> 0) then
  2951         begin
  3359         begin
  2952         DeleteGear(Gear);
  3360         DeleteGear(Gear);
  2953         AfterAttack
  3361         AfterAttack
  2954         end
  3362         end
  2955 end;
  3363 end;
  2958 begin
  3366 begin
  2959     if (Gear^.Hedgehog^.Gear = nil) or (Gear^.Hedgehog^.Gear^.Damage > 0) then
  3367     if (Gear^.Hedgehog^.Gear = nil) or (Gear^.Hedgehog^.Gear^.Damage > 0) then
  2960         begin
  3368         begin
  2961         DeleteGear(Gear);
  3369         DeleteGear(Gear);
  2962         AfterAttack;
  3370         AfterAttack;
       
  3371         exit
  2963         end;
  3372         end;
  2964     inc(Gear^.Timer);
  3373     inc(Gear^.Timer);
  2965     if Gear^.Timer = 65 then
  3374     if Gear^.Timer = 65 then
  2966         begin
  3375         begin
  2967         Gear^.Timer := 0;
  3376         Gear^.Timer := 0;
  3054 var
  3463 var
  3055     HHGear: PGear;
  3464     HHGear: PGear;
  3056     hedgehog: PHedgehog;
  3465     hedgehog: PHedgehog;
  3057     State: Longword;
  3466     State: Longword;
  3058     switchDir: Longword;
  3467     switchDir: Longword;
       
  3468     oldUid: Longword;
  3059 begin
  3469 begin
  3060     AllInactive := false;
  3470     AllInactive := false;
  3061 
  3471 
  3062     if ((Gear^.Message and (not (gmSwitch or gmPrecise))) <> 0) or (TurnTimeLeft = 0) then
  3472     if ((Gear^.Message and (not (gmSwitch or gmPrecise))) <> 0) or (TurnTimeLeft = 0) then
  3063         begin
  3473         begin
  3064         hedgehog := Gear^.Hedgehog;
  3474         hedgehog := Gear^.Hedgehog;
  3065         //Msg := Gear^.Message and (not gmSwitch);
       
  3066         DeleteGear(Gear);
       
  3067         ApplyAmmoChanges(hedgehog^);
  3475         ApplyAmmoChanges(hedgehog^);
  3068 
  3476 
  3069         HHGear := CurrentHedgehog^.Gear;
  3477         HHGear := CurrentHedgehog^.Gear;
  3070         ApplyAmmoChanges(HHGear^.Hedgehog^);
  3478         ApplyAmmoChanges(HHGear^.Hedgehog^);
  3071         //HHGear^.Message := Msg;
  3479         DeleteGear(Gear);
  3072         exit
  3480         exit
  3073         end;
  3481         end;
  3074 
  3482 
       
  3483     HHGear := CurrentHedgehog^.Gear;
  3075     if (Gear^.Message and gmSwitch) <> 0 then
  3484     if (Gear^.Message and gmSwitch) <> 0 then
  3076         begin
  3485         begin
  3077         HHGear := CurrentHedgehog^.Gear;
  3486         oldUid:= HHGear^.uid;
  3078         HHGear^.Message := HHGear^.Message and (not gmSwitch);
  3487         HHGear^.Message := HHGear^.Message and (not gmSwitch);
  3079         Gear^.Message := Gear^.Message and (not gmSwitch);
  3488         Gear^.Message := Gear^.Message and (not gmSwitch);
  3080 
  3489 
  3081         // switching in reverse direction
  3490         // switching in reverse direction
  3082         if (Gear^.Message and gmPrecise) <> 0 then
  3491         if (Gear^.Message and gmPrecise) <> 0 then
  3086             end
  3495             end
  3087         else
  3496         else
  3088             switchDir:=  1;
  3497             switchDir:=  1;
  3089 
  3498 
  3090         State := HHGear^.State;
  3499         State := HHGear^.State;
  3091         HHGear^.State := 0;
  3500         if (HHGear^.State and gstMoving) = 0 then
       
  3501             HHGear^.Active := false;
       
  3502         HHGear^.State := HHGear^.State and gstMoving;
  3092         HHGear^.Z := cHHZ;
  3503         HHGear^.Z := cHHZ;
  3093         HHGear^.Active := false;
       
  3094         HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
  3504         HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
  3095 
  3505 
  3096         PlaySound(sndSwitchHog);
  3506         PlaySound(sndSwitchHog);
  3097 
  3507 
  3098         repeat
  3508         repeat
  3105 
  3515 
  3106         SwitchCurrentHedgehog(@CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog]);
  3516         SwitchCurrentHedgehog(@CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog]);
  3107         AmmoMenuInvalidated:= true;
  3517         AmmoMenuInvalidated:= true;
  3108 
  3518 
  3109         HHGear := CurrentHedgehog^.Gear;
  3519         HHGear := CurrentHedgehog^.Gear;
       
  3520         ScriptCall('onHogSwitch', oldUid);
  3110         HHGear^.State := State;
  3521         HHGear^.State := State;
  3111         HHGear^.Active := true;
  3522         HHGear^.Active := true;
  3112         FollowGear := HHGear;
  3523         FollowGear := HHGear;
  3113         HHGear^.Z := cCurrHHZ;
  3524         HHGear^.Z := cCurrHHZ;
  3114         // restore precise key
  3525         // restore precise key
  3115         if (switchDir <> 1) then
  3526         if (switchDir <> 1) then
  3116             HHGear^.Message:= HHGear^.Message or gmPrecise;
  3527             HHGear^.Message:= HHGear^.Message or gmPrecise;
  3117         HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
  3528         HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
  3118         Gear^.X := HHGear^.X;
  3529         end;
  3119         Gear^.Y := HHGear^.Y
  3530     doStepHedgehogMoving(HHGear);
  3120         end;
  3531     Gear^.X := HHGear^.X;
       
  3532     Gear^.Y := HHGear^.Y
  3121 end;
  3533 end;
  3122 
  3534 
  3123 procedure doStepSwitcher(Gear: PGear);
  3535 procedure doStepSwitcher(Gear: PGear);
  3124 var
  3536 var
  3125     HHGear: PGear;
  3537     HHGear: PGear;
  3129     HHGear := Gear^.Hedgehog^.Gear;
  3541     HHGear := Gear^.Hedgehog^.Gear;
  3130     OnUsedAmmo(HHGear^.Hedgehog^);
  3542     OnUsedAmmo(HHGear^.Hedgehog^);
  3131     with HHGear^ do
  3543     with HHGear^ do
  3132         begin
  3544         begin
  3133         State := State and (not gstAttacking);
  3545         State := State and (not gstAttacking);
  3134         Message := Message and (not gmAttack)
  3546         Message := Message and (not (gmAttack or gmSwitch))
  3135         end
  3547         end
  3136 end;
  3548 end;
  3137 
  3549 
  3138 ////////////////////////////////////////////////////////////////////////////////
  3550 ////////////////////////////////////////////////////////////////////////////////
  3139 procedure doStepMortar(Gear: PGear);
  3551 procedure doStepMortar(Gear: PGear);
  3163 
  3575 
  3164         DeleteGear(Gear);
  3576         DeleteGear(Gear);
  3165         exit
  3577         exit
  3166         end;
  3578         end;
  3167 
  3579 
       
  3580     // particles
  3168     if (GameTicks and $3F) = 0 then
  3581     if (GameTicks and $3F) = 0 then
  3169         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  3582         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  3170 end;
  3583 end;
  3171 
  3584 
  3172 ////////////////////////////////////////////////////////////////////////////////
  3585 ////////////////////////////////////////////////////////////////////////////////
  3184         Gear^.AdvBounce:= 1;
  3597         Gear^.AdvBounce:= 1;
  3185 
  3598 
  3186     HHGear := Gear^.Hedgehog^.Gear;
  3599     HHGear := Gear^.Hedgehog^.Gear;
  3187     if HHGear = nil then
  3600     if HHGear = nil then
  3188         begin
  3601         begin
       
  3602         ClearHitOrder();
       
  3603         ClearProximityCache();
  3189         DeleteGear(Gear);
  3604         DeleteGear(Gear);
  3190         exit
  3605         exit
  3191         end;
  3606         end;
  3192 
  3607 
  3193     HHGear^.State := HHGear^.State or gstNoDamage;
  3608     HHGear^.State := HHGear^.State or gstNoDamage;
  3215 
  3630 
  3216         // check for drowning
  3631         // check for drowning
  3217         if CheckGearDrowning(HHGear) then
  3632         if CheckGearDrowning(HHGear) then
  3218             begin
  3633             begin
  3219             AfterAttack;
  3634             AfterAttack;
       
  3635             ClearHitOrder();
       
  3636             ClearProximityCache();
  3220             DeleteGear(Gear);
  3637             DeleteGear(Gear);
  3221             exit;
  3638             exit;
  3222             end;
  3639             end;
  3223 
  3640 
  3224         inc(Gear^.Damage, 2);
  3641         inc(Gear^.Damage, 2);
  3225 
       
  3226         //  if TestCollisionXwithGear(HHGear, hwSign(Gear^.dX))
       
  3227         //      or TestCollisionYwithGear(HHGear, hwSign(Gear^.dY)) then inc(Gear^.Damage, 3);
       
  3228 
  3642 
  3229         dec(i)
  3643         dec(i)
  3230     until (i = 0)
  3644     until (i = 0)
  3231     or (Gear^.Damage > Gear^.Health);
  3645     or (Gear^.Damage > Gear^.Health);
  3232 
  3646 
  3239                 Gear^.Pos := 3
  3653                 Gear^.Pos := 3
  3240             else
  3654             else
  3241                 Gear^.Pos := 2;
  3655                 Gear^.Pos := 2;
  3242             end;
  3656             end;
  3243 
  3657 
  3244         AmmoShove(Gear, Gear^.Boom, 40);
  3658         AmmoShoveCache(Gear, Gear^.Boom, 40);
  3245 
  3659 
  3246         DrawTunnel(HHGear^.X - HHGear^.dX * 10,
  3660         DrawTunnel(HHGear^.X - HHGear^.dX * 10,
  3247                     HHGear^.Y - _2 - HHGear^.dY * 10 + hwAbs(HHGear^.dY) * 2,
  3661                     HHGear^.Y - _2 - HHGear^.dY * 10 + hwAbs(HHGear^.dY) * 2,
  3248         HHGear^.dX,
  3662         HHGear^.dX,
  3249         HHGear^.dY,
  3663         HHGear^.dY,
  3250         20 + cHHRadius * 2,
  3664         20 + cHHRadius * 2,
  3251         cHHRadius * 2 + 7);
  3665         cHHRadius * 2 + 7);
  3252 
  3666 
  3253         upd := 0
  3667         upd := 0
  3254         end;
  3668         end;
       
  3669 
       
  3670     inc(Gear^.Timer);
       
  3671     if (Gear^.Timer mod 100) = 0 then
       
  3672         RefillProximityCache(Gear, 300);
  3255 
  3673 
  3256     if Gear^.Health < Gear^.Damage then
  3674     if Gear^.Health < Gear^.Damage then
  3257         begin
  3675         begin
  3258         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  3676         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  3259         if hasWishes then
  3677         if hasWishes then
  3273                             dy := -dy;
  3691                             dy := -dy;
  3274                         FrameTicks:= random(400) + 250
  3692                         FrameTicks:= random(400) + 250
  3275                         end
  3693                         end
  3276                 end;
  3694                 end;
  3277         s:= ansistring(Gear^.Hedgehog^.Name);
  3695         s:= ansistring(Gear^.Hedgehog^.Name);
  3278         AddCaption(FormatA(GetEventString(eidKamikaze), s), cWhiteColor, capgrpMessage);
  3696         AddCaption(FormatA(GetEventString(eidKamikaze), s), capcolDefault, capgrpMessage);
  3279         uStats.HedgehogSacrificed(Gear^.Hedgehog);
  3697         uStats.HedgehogSacrificed(Gear^.Hedgehog);
  3280         AfterAttack;
  3698         AfterAttack;
  3281         HHGear^.Message:= HHGear^.Message or gmDestroy;
  3699         HHGear^.Message:= HHGear^.Message or gmDestroy;
       
  3700         ClearHitOrder();
       
  3701         ClearProximityCache();
  3282         DeleteGear(Gear);
  3702         DeleteGear(Gear);
  3283         end
  3703         end
  3284     else
  3704     else
  3285         begin
  3705         begin
  3286         dec(Gear^.Health, Gear^.Damage);
  3706         dec(Gear^.Health, Gear^.Damage);
  3287         Gear^.Damage := 0
  3707         Gear^.Damage := 0
  3288         end
  3708         end
  3289 end;
  3709 end;
  3290 
  3710 
  3291 procedure doStepKamikazeIdle(Gear: PGear);
  3711 procedure doStepKamikazeIdle(Gear: PGear);
       
  3712 var HHGear: PGear;
  3292 begin
  3713 begin
  3293     AllInactive := false;
  3714     AllInactive := false;
  3294     dec(Gear^.Timer);
  3715     dec(Gear^.Timer);
       
  3716     HHGear := Gear^.Hedgehog^.Gear;
       
  3717     if (HHGear = nil) or (HHGear^.Damage <> 0) then
       
  3718         begin
       
  3719         if (HHGear <> nil) then
       
  3720             AfterAttack;
       
  3721         ClearHitOrder();
       
  3722         ClearProximityCache();
       
  3723         DeleteGear(Gear);
       
  3724         exit;
       
  3725         end;
  3295     if Gear^.Timer = 0 then
  3726     if Gear^.Timer = 0 then
  3296         begin
  3727         begin
  3297         Gear^.Pos := 1;
  3728         Gear^.Pos := 1;
  3298         PlaySoundV(sndKamikaze, Gear^.Hedgehog^.Team^.voicepack);
  3729         PlaySoundV(sndKamikaze, Gear^.Hedgehog^.Team^.voicepack);
       
  3730         ClearHitOrder();
       
  3731         RefillProximityCache(Gear, 300);
  3299         Gear^.doStep := @doStepKamikazeWork
  3732         Gear^.doStep := @doStepKamikazeWork
  3300         end
  3733         end
  3301 end;
  3734 end;
  3302 
  3735 
  3303 procedure doStepKamikaze(Gear: PGear);
  3736 procedure doStepKamikaze(Gear: PGear);
  3359     Gear^.Tag := 0;
  3792     Gear^.Tag := 0;
  3360 
  3793 
  3361     if Gear^.Pos = 0 then
  3794     if Gear^.Pos = 0 then
  3362         begin
  3795         begin
  3363 ///////////// adapted from doMakeExplosion ///////////////////////////
  3796 ///////////// adapted from doMakeExplosion ///////////////////////////
  3364         //fX:= Gear^.X;
       
  3365         //fY:= Gear^.Y;
       
  3366         //fX.QWordValue:= fX.QWordValue and $FFFFFFFF00000000;
       
  3367         //fY.QWordValue:= fY.QWordValue and $FFFFFFFF00000000;
       
  3368         fX:= int2hwFloat(hwRound(Gear^.X));
  3797         fX:= int2hwFloat(hwRound(Gear^.X));
  3369         fY:= int2hwFloat(hwRound(Gear^.Y));
  3798         fY:= int2hwFloat(hwRound(Gear^.Y));
  3370         dmgBase:= Gear^.Boom shl 1 + cHHRadius div 2;
  3799         dmgBase:= Gear^.Boom shl 1 + cHHRadius div 2;
  3371         partyEpicness:= 0;
  3800         partyEpicness:= 0;
  3372         gi := GearsList;
  3801         gi := GearsList;
  3423 
  3852 
  3424 procedure doStepCakeWalk(Gear: PGear);
  3853 procedure doStepCakeWalk(Gear: PGear);
  3425 var
  3854 var
  3426     tdx, tdy: hwFloat;
  3855     tdx, tdy: hwFloat;
  3427     cakeData: PCakeData;
  3856     cakeData: PCakeData;
       
  3857     i: Longword;
  3428 begin
  3858 begin
  3429     AllInactive := false;
  3859     AllInactive := false;
  3430 
  3860 
  3431     inc(Gear^.Tag);
  3861     inc(Gear^.Tag);
  3432     if Gear^.Tag < 7 then
  3862     if Gear^.Tag < 7 then
  3446         end
  3876         end
  3447     else if Gear^.Timer < 6000 then
  3877     else if Gear^.Timer < 6000 then
  3448         Gear^.RenderTimer:= true;
  3878         Gear^.RenderTimer:= true;
  3449 
  3879 
  3450     if not cakeStep(Gear) then Gear^.doStep:= @doStepCakeFall;
  3880     if not cakeStep(Gear) then Gear^.doStep:= @doStepCakeFall;
       
  3881 
       
  3882     // Cake passed world edge.
       
  3883     if (Gear^.Karma = 1) then
       
  3884         (* This code is not ideal, but at least not horribly broken.
       
  3885         The cake tries to reach the other side and continue to walk,
       
  3886         but there are some exceptions.
       
  3887         This code is called *after* the X coordinate have been wrapped.
       
  3888         Depending on terrain on the other side, the cake does this:
       
  3889         * Cake collides horizontally (even by 1 pixel): Turn around
       
  3890         * Cake does not see walkable ground above or below: Fall
       
  3891         * Otherwise: Walk normally
       
  3892         *)
       
  3893         begin
       
  3894         // Update coordinates
       
  3895         tdx:=Gear^.X;
       
  3896         if (hwRound(Gear^.X) < leftX) then
       
  3897              Gear^.X:= Gear^.X + int2hwfloat(rightX - leftX)
       
  3898         else Gear^.X:= Gear^.X - int2hwfloat(rightX - leftX);
       
  3899 
       
  3900         Gear^.Tag:= 0;
       
  3901         if ((TestCollisionXwithGear(Gear, 1) <> 0) or (TestCollisionXwithGear(Gear, -1) <> 0)) then
       
  3902             // Cake collided horizontally, turn around. Prevents cake from being stuck in infinite loop.
       
  3903             // This can also happen if the terrain is just a slight slope. :-(
       
  3904             begin
       
  3905             Gear^.X := tdx;
       
  3906             Gear^.Karma := 3;
       
  3907             end
       
  3908         else
       
  3909             begin
       
  3910             // Check if cake has something to walk on the other side. If not, make it drop.
       
  3911             // There is nothing for the cake to stand on.
       
  3912             if (TestCollisionYwithGear(Gear, 1) = 0) and (TestCollisionYwithGear(Gear, -1) = 0) then
       
  3913                 Gear^.doStep:= @doStepCakeFall;
       
  3914             Gear^.Karma := 4;
       
  3915             end;
       
  3916         end;
       
  3917     // Cake bounced!
       
  3918     if (Gear^.Karma = 2) or (Gear^.Karma = 3) then
       
  3919         begin
       
  3920         // Turn cake around
       
  3921         Gear^.dX.isNegative := (not Gear^.dX.isNegative);
       
  3922         Gear^.WDTimer := 0;
       
  3923         Gear^.Angle := (LongInt(Gear^.Angle) + 2) and 3;
       
  3924 
       
  3925         // Bounce effect
       
  3926         if (Gear^.Karma = 2) then
       
  3927             AddBounceEffectForGear(Gear, 0.55);
       
  3928 
       
  3929         Gear^.Tag:= 0;
       
  3930         Gear^.Karma := 4;
       
  3931         end;
       
  3932     if (Gear^.Karma = 4) then
       
  3933         begin
       
  3934         // Reset CakePoints to fix cake angle
       
  3935         cakeData:= PCakeData(Gear^.Data);
       
  3936         with cakeData^ do
       
  3937             begin
       
  3938             for i:= 0 to Pred(cakeh) do
       
  3939                 begin
       
  3940                 CakePoints[i].x := Gear^.X;
       
  3941                 CakePoints[i].y := Gear^.Y;
       
  3942                 end;
       
  3943                 CakeI:= 0;
       
  3944             end;
       
  3945         Gear^.Karma := 0;
       
  3946         end;
  3451 
  3947 
  3452     if Gear^.Tag = 0 then
  3948     if Gear^.Tag = 0 then
  3453         begin
  3949         begin
  3454         cakeData:= PCakeData(Gear^.Data);
  3950         cakeData:= PCakeData(Gear^.Data);
  3455         with cakeData^ do
  3951         with cakeData^ do
  3522 
  4018 
  3523 procedure doStepCake(Gear: PGear);
  4019 procedure doStepCake(Gear: PGear);
  3524 begin
  4020 begin
  3525     AllInactive := false;
  4021     AllInactive := false;
  3526 
  4022 
  3527     Gear^.CollisionMask:= lfNotCurrentMask;
  4023     Gear^.CollisionMask:= lfNotCurHogCrate;
  3528 
  4024 
  3529     Gear^.dY:= cMaxWindSpeed * 100;
  4025     Gear^.dY:= cMaxWindSpeed * 100;
  3530 
  4026 
  3531     Gear^.doStep := @doStepCakeFall
  4027     Gear^.doStep := @doStepCakeFall
  3532 end;
  4028 end;
  3533 
  4029 
  3534 ////////////////////////////////////////////////////////////////////////////////
  4030 ////////////////////////////////////////////////////////////////////////////////
  3535 procedure doStepSeductionWork(Gear: PGear);
  4031 procedure doStepSeductionWork(Gear: PGear);
  3536 var i: LongInt;
  4032 var i: LongInt;
  3537     hogs: PGearArrayS;
  4033     hogs: PGearArrayS;
       
  4034     HHGear: PGear;
  3538 begin
  4035 begin
  3539     AllInactive := false;
  4036     AllInactive := false;
       
  4037 
       
  4038     HHGear := Gear^.Hedgehog^.Gear;
       
  4039     if (HHGear <> nil) and ((HHGear^.State and gstHHDriven) = 0) then
       
  4040         begin
       
  4041         StopSound(sndYoohoo);
       
  4042         AfterAttack;
       
  4043         DeleteGear(Gear);
       
  4044         exit;
       
  4045         end;
       
  4046 
  3540     hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius);
  4047     hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius);
  3541     if hogs.size > 0 then
  4048     if hogs.size > 0 then
  3542         begin
  4049         begin
  3543         for i:= 0 to hogs.size - 1 do
  4050         for i:= 0 to hogs.size - 1 do
  3544             with hogs.ar^[i]^ do
  4051             with hogs.ar^[i]^ do
  3554                     Active:= true;
  4061                     Active:= true;
  3555                     end
  4062                     end
  3556                 else if Hedgehog^.Effects[heFrozen] > 255 then
  4063                 else if Hedgehog^.Effects[heFrozen] > 255 then
  3557                     Hedgehog^.Effects[heFrozen]:= 255
  4064                     Hedgehog^.Effects[heFrozen]:= 255
  3558         end ;
  4065         end ;
       
  4066     AfterAttack;
       
  4067     DeleteGear(Gear);
       
  4068 end;
       
  4069 
       
  4070 procedure doStepSeductionWear(Gear: PGear);
       
  4071 var heart: PVisualGear;
       
  4072     HHGear: PGear;
       
  4073 begin
       
  4074     AllInactive := false;
       
  4075 
       
  4076     HHGear := Gear^.Hedgehog^.Gear;
       
  4077     if (HHGear <> nil) and ((HHGear^.State and gstHHDriven) = 0) then
       
  4078         begin
       
  4079         StopSound(sndYoohoo);
  3559         AfterAttack;
  4080         AfterAttack;
  3560         DeleteGear(Gear);
  4081         DeleteGear(Gear);
  3561 (*
  4082         exit;
  3562     Gear^.X := Gear^.X + Gear^.dX;
  4083         end;
  3563     Gear^.Y := Gear^.Y + Gear^.dY;
  4084 
  3564     x := hwRound(Gear^.X);
       
  3565     y := hwRound(Gear^.Y);
       
  3566 
       
  3567     if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
       
  3568         if (Land[y, x] <> 0) then
       
  3569             begin
       
  3570             Gear^.dX.isNegative := not Gear^.dX.isNegative;
       
  3571             Gear^.dY.isNegative := not Gear^.dY.isNegative;
       
  3572             Gear^.dX := Gear^.dX * _1_5;
       
  3573             Gear^.dY := Gear^.dY * _1_5 - _0_3;
       
  3574             AmmoShove(Gear, 0, 40);
       
  3575             AfterAttack;
       
  3576             DeleteGear(Gear)
       
  3577             end
       
  3578         else
       
  3579     else
       
  3580         begin
       
  3581         AfterAttack;
       
  3582         DeleteGear(Gear)
       
  3583         end*)
       
  3584 end;
       
  3585 
       
  3586 procedure doStepSeductionWear(Gear: PGear);
       
  3587 var heart: PVisualGear;
       
  3588 begin
       
  3589     AllInactive := false;
       
  3590     inc(Gear^.Timer);
  4085     inc(Gear^.Timer);
  3591     if Gear^.Timer > 250 then
  4086     if Gear^.Timer > 250 then
  3592         begin
  4087         begin
  3593         Gear^.Timer := 0;
  4088         Gear^.Timer := 0;
  3594         inc(Gear^.Pos);
  4089         inc(Gear^.Pos);
  3595         if Gear^.Pos = 5 then
  4090         if Gear^.Pos = 5 then
  3596             PlaySound(sndYoohoo);
  4091             PlaySound(sndYoohoo);
       
  4092         if Gear^.Pos = 14 then
       
  4093             PlaySound(sndKiss);
  3597         end;
  4094         end;
  3598 
  4095 
  3599 
  4096 
  3600     // note: use GameTicks, not RealTicks, otherwise amount can vary greatly
  4097     // note: use GameTicks, not RealTicks, otherwise amount can vary greatly
  3601     if (Gear^.Pos = 14) and (GameTicks and $1 = 0) then
  4098     if (Gear^.Pos = 14) and (GameTicks and $1 = 0) then
  3602         begin
  4099         begin
  3603         heart:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot);
  4100         heart:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot);
  3604         if heart <> nil then
  4101         if heart <> nil then
  3605             with heart^ do
  4102             with heart^ do
  3606                 begin
  4103                 begin
  3607                 { // old calcs
       
  3608                 dx:= 0.001 * (random(200));
       
  3609                 dy:= 0.001 * (random(200));
       
  3610                 if random(2) = 0 then
       
  3611                     dx := -dx;
       
  3612                 if random(2) = 0 then
       
  3613                     dy := -dy;
       
  3614                 }
       
  3615 
  4104 
  3616                 // randomize speed in both directions
  4105                 // randomize speed in both directions
  3617                 dx:= 0.001 * (random(201));
  4106                 dx:= 0.001 * (random(201));
  3618                 dy:= 0.001 * (random(201));
  4107                 dy:= 0.001 * (random(201));
  3619 
  4108 
  3647 end;
  4136 end;
  3648 
  4137 
  3649 procedure doStepSeduction(Gear: PGear);
  4138 procedure doStepSeduction(Gear: PGear);
  3650 begin
  4139 begin
  3651     AllInactive := false;
  4140     AllInactive := false;
  3652     //DeleteCI(Gear^.Hedgehog^.Gear);
       
  3653     Gear^.doStep := @doStepSeductionWear
  4141     Gear^.doStep := @doStepSeductionWear
  3654 end;
  4142 end;
  3655 
  4143 
  3656 ////////////////////////////////////////////////////////////////////////////////
  4144 ////////////////////////////////////////////////////////////////////////////////
  3657 procedure doStepWaterUp(Gear: PGear);
  4145 procedure doStepWaterUp(Gear: PGear);
  3700 procedure doStepDrillDrilling(Gear: PGear);
  4188 procedure doStepDrillDrilling(Gear: PGear);
  3701 var
  4189 var
  3702     t: PGearArray;
  4190     t: PGearArray;
  3703     tempColl: Word;
  4191     tempColl: Word;
  3704 begin
  4192 begin
       
  4193     WorldWrap(Gear);
  3705     AllInactive := false;
  4194     AllInactive := false;
  3706     if (Gear^.Timer > 0) and (Gear^.Timer mod 10 <> 0) then
  4195     if (Gear^.Timer > 0) and (Gear^.Timer mod 10 <> 0) then
  3707         begin
  4196         begin
  3708         dec(Gear^.Timer);
  4197         dec(Gear^.Timer);
  3709         exit;
  4198         exit;
  3719         StopSoundChan(Gear^.SoundChannel);
  4208         StopSoundChan(Gear^.SoundChannel);
  3720         exit
  4209         exit
  3721     end;
  4210     end;
  3722 
  4211 
  3723     tempColl:= Gear^.CollisionMask;
  4212     tempColl:= Gear^.CollisionMask;
  3724     Gear^.CollisionMask:= $007F;
  4213     Gear^.CollisionMask:= lfObjMask;
  3725     if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) <> 0) or (GameTicks > Gear^.FlightTime) then
  4214     if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) <> 0) or (GameTicks > Gear^.FlightTime) then
  3726         t := CheckGearsCollision(Gear)
  4215         t := CheckGearsCollision(Gear)
  3727     else t := nil;
  4216     else t := nil;
  3728     Gear^.CollisionMask:= tempColl;
  4217     Gear^.CollisionMask:= tempColl;
  3729     //fixes drill not exploding when touching HH bug
  4218     //fixes drill not exploding when touching HH bug
  3801             end;
  4290             end;
  3802 
  4291 
  3803         Gear^.X:= Gear^.X+Gear^.dX*4;
  4292         Gear^.X:= Gear^.X+Gear^.dX*4;
  3804         Gear^.Y:= Gear^.Y+Gear^.dY*4;
  4293         Gear^.Y:= Gear^.Y+Gear^.dY*4;
  3805         Gear^.SoundChannel := LoopSound(sndDrillRocket);
  4294         Gear^.SoundChannel := LoopSound(sndDrillRocket);
       
  4295         Gear^.Pos:= 1;
  3806         Gear^.doStep := @doStepDrillDrilling;
  4296         Gear^.doStep := @doStepDrillDrilling;
  3807 
  4297 
  3808         if (Gear^.State and gsttmpFlag) <> 0 then
  4298         if (Gear^.State and gsttmpFlag) <> 0 then
  3809             gear^.RenderTimer:= true;
  4299             gear^.RenderTimer:= true;
  3810         if Gear^.Timer > 0 then dec(Gear^.Timer)
  4300         if Gear^.Timer > 0 then dec(Gear^.Timer)
  3843         begin
  4333         begin
  3844         rx := rndSign(getRandomf * _0_1);
  4334         rx := rndSign(getRandomf * _0_1);
  3845         ry := rndSign(getRandomf * _0_1);
  4335         ry := rndSign(getRandomf * _0_1);
  3846 
  4336 
  3847         ball:= AddGear(gx, gy, gtBall, 0, SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx, AngleCos(HHGear^.Angle) * ( - _0_8) + ry, 0);
  4337         ball:= AddGear(gx, gy, gtBall, 0, SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx, AngleCos(HHGear^.Angle) * ( - _0_8) + ry, 0);
  3848         ball^.CollisionMask:= lfNotCurrentMask;
  4338         ball^.CollisionMask:= lfNotCurHogCrate;
  3849 
  4339 
  3850         PlaySound(sndGun);
  4340         PlaySound(sndGun);
  3851         end;
  4341         end;
  3852 
  4342 
  3853     if (Gear^.Timer = 0) or ((HHGear^.State and gstHHDriven) = 0) then
  4343     if (Gear^.Timer = 0) or ((HHGear^.State and gstHHDriven) = 0) then
  3962             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
  4452             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
  3963             _0_5, 0);
  4453             _0_5, 0);
  3964             dec(Gear^.Health)
  4454             dec(Gear^.Health)
  3965             end;
  4455             end;
  3966         s:= ansistring(inttostr(Gear^.Health));
  4456         s:= ansistring(inttostr(Gear^.Health));
  3967         AddCaption(formatA(trmsg[sidRemaining], s), cWhiteColor, capgrpAmmostate);
  4457         AddCaption(formatA(trmsg[sidRemaining], s), capcolDefault, capgrpAmmostate);
  3968         end;
  4458         end;
  3969 
  4459 
  3970     if (HHGear <> nil) and ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
  4460     if (HHGear <> nil) and ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
  3971         begin
  4461         begin
  3972         Gear^.State := Gear^.State or gsttmpFlag;
  4462         Gear^.State := Gear^.State or gsttmpFlag;
  3973         PauseMusic;
  4463         PlayMusicSound(sndRideOfTheValkyries);
  3974         playSound(sndRideOfTheValkyries);
       
  3975         inCinematicMode:= true;
  4464         inCinematicMode:= true;
  3976         end;
  4465         end;
  3977 
  4466 
  3978     // pickup bonuses
  4467     // pickup bonuses
  3979     t := CheckGearNear(Gear, gtCase, 36, 36);
  4468     t := CheckGearNear(Gear, gtCase, 36, 36);
  3984 
  4473 
  3985     if ((Gear^.State and gstCollision) <> 0) or CheckGearDrowning(Gear) then
  4474     if ((Gear^.State and gstCollision) <> 0) or CheckGearDrowning(Gear) then
  3986         begin
  4475         begin
  3987         inCinematicMode:= false;
  4476         inCinematicMode:= false;
  3988         StopSoundChan(Gear^.SoundChannel);
  4477         StopSoundChan(Gear^.SoundChannel);
  3989         StopSound(sndRideOfTheValkyries);
  4478         StopMusicSound(sndRideOfTheValkyries);
  3990         ResumeMusic;
       
  3991 
  4479 
  3992         if ((Gear^.State and gstCollision) <> 0) then
  4480         if ((Gear^.State and gstCollision) <> 0) then
  3993             begin
  4481             begin
  3994             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  4482             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  3995             for i:= 0 to 15 do
  4483             for i:= 0 to 15 do
  4048     isUnderwater:= CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + Gear^.Radius);
  4536     isUnderwater:= CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + Gear^.Radius);
  4049     if Gear^.Pos > 0 then
  4537     if Gear^.Pos > 0 then
  4050         dec(Gear^.Pos);
  4538         dec(Gear^.Pos);
  4051     AllInactive := false;
  4539     AllInactive := false;
  4052     HHGear := Gear^.Hedgehog^.Gear;
  4540     HHGear := Gear^.Hedgehog^.Gear;
  4053     //dec(Gear^.Timer);
       
  4054     move := _0_2;
  4541     move := _0_2;
  4055     fuel := 50;
  4542     fuel := 50;
  4056 (*if (HHGear^.Message and gmPrecise) <> 0 then
       
  4057     begin
       
  4058     move:= _0_02;
       
  4059     fuel:= 5;
       
  4060     end;*)
       
  4061     if HHGear^.Message and gmPrecise <> 0 then
  4543     if HHGear^.Message and gmPrecise <> 0 then
  4062         HedgehogChAngle(HHGear)
  4544         HedgehogChAngle(HHGear)
  4063     else if Gear^.Health > 0 then
  4545     else if (Gear^.Health > 0) or (Gear^.Health = JETPACK_FUEL_INFINITE) then
  4064         begin
  4546         begin
  4065         if HHGear^.Message and gmUp <> 0 then
  4547         if HHGear^.Message and gmUp <> 0 then
  4066             begin
  4548             begin
  4067             if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
  4549             if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
  4068                 begin
  4550                 begin
  4080                     begin
  4562                     begin
  4081                     PlaySound(sndJetpackBoost);
  4563                     PlaySound(sndJetpackBoost);
  4082                     HHGear^.dY := HHGear^.dY - move;
  4564                     HHGear^.dY := HHGear^.dY - move;
  4083                     end
  4565                     end
  4084                 end;
  4566                 end;
  4085             dec(Gear^.Health, fuel);
  4567             if Gear^.Health <> JETPACK_FUEL_INFINITE then
       
  4568                 dec(Gear^.Health, fuel);
  4086             Gear^.MsgParam := Gear^.MsgParam or gmUp;
  4569             Gear^.MsgParam := Gear^.MsgParam or gmUp;
  4087             Gear^.Timer := GameTicks
  4570             Gear^.Timer := GameTicks
  4088             end;
  4571             end;
  4089         move.isNegative := (HHGear^.Message and gmLeft) <> 0;
  4572         move.isNegative := (HHGear^.Message and gmLeft) <> 0;
  4090         if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
  4573         if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
  4106                         else bubble^.X := bubble^.X - 28;
  4589                         else bubble^.X := bubble^.X - 28;
  4107                         end;
  4590                         end;
  4108                     end
  4591                     end
  4109                 end
  4592                 end
  4110             else PlaySound(sndJetpackBoost);
  4593             else PlaySound(sndJetpackBoost);
  4111             dec(Gear^.Health, fuel div 5);
  4594             if Gear^.Health <> JETPACK_FUEL_INFINITE then
       
  4595                 dec(Gear^.Health, fuel div 5);
  4112             Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
  4596             Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
  4113             Gear^.Timer := GameTicks
  4597             Gear^.Timer := GameTicks
  4114             end
  4598             end
  4115         end;
  4599         end;
  4116 
  4600 
  4119         begin
  4603         begin
  4120         Gear^.Timer := 0;
  4604         Gear^.Timer := 0;
  4121         Gear^.MsgParam := 0
  4605         Gear^.MsgParam := 0
  4122         end;
  4606         end;
  4123 
  4607 
  4124     if Gear^.Health < 0 then
  4608     if (Gear^.Health < 0) and (Gear^.Health <> JETPACK_FUEL_INFINITE) then
  4125         Gear^.Health := 0;
  4609         Gear^.Health := 0;
  4126 
  4610 
  4127     i:= Gear^.Health div 20;
  4611     i:= Gear^.Health div 20;
  4128 
  4612 
  4129     if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
  4613     if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
  4130         begin
  4614         begin
  4131         Gear^.Damage:= i;
  4615         Gear^.Damage:= i;
  4132         //AddCaption('Fuel: '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
       
  4133         FreeAndNilTexture(Gear^.Tex);
  4616         FreeAndNilTexture(Gear^.Tex);
  4134         Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ansistring(': ' + inttostr(i) + '%'), cWhiteColor, fntSmall)
  4617         if Gear^.Health <> JETPACK_FUEL_INFINITE then
       
  4618             Gear^.Tex := RenderStringTex(FormatA(trmsg[sidFuel], ansistring(inttostr(i))), cWhiteColor, fntSmall)
  4135         end;
  4619         end;
  4136 
  4620 
  4137     if (HHGear^.Message and (gmAttack or gmUp or gmLeft or gmRight) <> 0) and
  4621     if (HHGear^.Message and (gmAttack or gmUp or gmLeft or gmRight) <> 0) and
  4138        (HHGear^.Message and gmPrecise = 0) then
  4622        (HHGear^.Message and gmPrecise = 0) then
  4139         Gear^.State := Gear^.State and (not gsttmpFlag);
  4623         Gear^.State := Gear^.State and (not gsttmpFlag);
  4151 
  4635 
  4152     if ((Gear^.State and gsttmpFlag) = 0)
  4636     if ((Gear^.State and gsttmpFlag) = 0)
  4153     or (HHGear^.dY < _0) then
  4637     or (HHGear^.dY < _0) then
  4154         doStepHedgehogMoving(HHGear);
  4638         doStepHedgehogMoving(HHGear);
  4155 
  4639 
  4156     if // (Gear^.Health = 0)
  4640     if
  4157         (HHGear^.Damage <> 0)
  4641         (HHGear^.Damage <> 0)
  4158         //or CheckGearDrowning(HHGear)
       
  4159         // drown if too deep under water
  4642         // drown if too deep under water
  4160         or (cWaterLine + cVisibleWater * 4 < hwRound(HHGear^.Y))
  4643         or (cWaterLine + cVisibleWater * 4 < hwRound(HHGear^.Y))
  4161         or (TurnTimeLeft = 0)
  4644         or (TurnTimeLeft = 0)
  4162         // allow brief ground touches - to be fair on this, might need another counter
  4645         // allow brief ground touches - to be fair on this, might need another counter
  4163         or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and (TestCollisionYwithGear(HHGear, 1) <> 0))
  4646         or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and (TestCollisionYwithGear(HHGear, 1) <> 0))
  4167                 begin
  4650                 begin
  4168                 Message := 0;
  4651                 Message := 0;
  4169                 Active := true;
  4652                 Active := true;
  4170                 State := State or gstMoving
  4653                 State := State or gstMoving
  4171                 end;
  4654                 end;
  4172             DeleteGear(Gear);
  4655             if (GetAmmoEntry(HHGear^.Hedgehog^, amJetpack)^.Count >= 1) and ((Ammoz[HHGear^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) and (HHGear^.Hedgehog^.MultiShootAttacks = 0) then
  4173             if (GetAmmoEntry(HHGear^.Hedgehog^, amJetpack)^.Count >= 1) and ((Ammoz[HHGear^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
       
  4174                 HHGear^.Hedgehog^.CurAmmoType:= amJetpack;
  4656                 HHGear^.Hedgehog^.CurAmmoType:= amJetpack;
  4175             isCursorVisible := false;
  4657             isCursorVisible := false;
  4176             ApplyAmmoChanges(HHGear^.Hedgehog^);
  4658             ApplyAmmoChanges(HHGear^.Hedgehog^);
  4177         //    if Gear^.Tex <> nil then FreeTexture(Gear^.Tex);
  4659             DeleteGear(Gear);
  4178 
       
  4179 //    Gear^.Tex:= RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(round(Gear^.Health / 20)) + '%', cWhiteColor, fntSmall)
       
  4180 
       
  4181 //AddCaption(trmsg[sidFuel]+': '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
       
  4182             end
  4660             end
  4183 end;
  4661 end;
  4184 
  4662 
  4185 procedure doStepJetpack(Gear: PGear);
  4663 procedure doStepJetpack(Gear: PGear);
  4186 var
  4664 var
  4214     AllInactive := false;
  4692     AllInactive := false;
  4215     Gear^.Pos := 0;
  4693     Gear^.Pos := 0;
  4216     if Gear^.Timer < 2000 then
  4694     if Gear^.Timer < 2000 then
  4217         inc(Gear^.Timer, 1)
  4695         inc(Gear^.Timer, 1)
  4218     else
  4696     else
  4219         begin
  4697         DeleteGear(Gear)
  4220         DeleteGear(Gear);
       
  4221         end;
       
  4222 end;
  4698 end;
  4223 
  4699 
  4224 procedure doStepBirdyFly(Gear: PGear);
  4700 procedure doStepBirdyFly(Gear: PGear);
  4225 var
  4701 var
  4226     HHGear: PGear;
  4702     HHGear: PGear;
  4227     fuel, i: LongInt;
  4703     energy, i: LongInt;
  4228     move: hwFloat;
  4704     move: hwFloat;
  4229     s: ansistring;
  4705     s: ansistring;
  4230 begin
  4706 begin
  4231     HHGear := Gear^.Hedgehog^.Gear;
  4707     HHGear := Gear^.Hedgehog^.Gear;
  4232     if HHGear = nil then
  4708     if HHGear = nil then
  4240         AfterAttack;
  4716         AfterAttack;
  4241         exit
  4717         exit
  4242         end;
  4718         end;
  4243 
  4719 
  4244     move := _0_2;
  4720     move := _0_2;
  4245     fuel := 50;
  4721     energy:= 50;
  4246 
  4722 
  4247     if Gear^.Pos > 0 then
  4723     if Gear^.Pos > 0 then
  4248         dec(Gear^.Pos, 1)
  4724         dec(Gear^.Pos, 1)
  4249     else if (HHGear^.Message and (gmLeft or gmRight or gmUp)) <> 0 then
  4725     else if (HHGear^.Message and (gmLeft or gmRight or gmUp)) <> 0 then
  4250             Gear^.Pos := 500;
  4726             Gear^.Pos := 500;
  4258         begin
  4734         begin
  4259         if (not HHGear^.dY.isNegative)
  4735         if (not HHGear^.dY.isNegative)
  4260         or (HHGear^.Y > -_256) then
  4736         or (HHGear^.Y > -_256) then
  4261             HHGear^.dY := HHGear^.dY - move;
  4737             HHGear^.dY := HHGear^.dY - move;
  4262 
  4738 
  4263         dec(Gear^.Health, fuel);
  4739         if (Gear^.Health <> BIRDY_ENERGY_INFINITE) then
       
  4740             dec(Gear^.Health, energy);
  4264         Gear^.MsgParam := Gear^.MsgParam or gmUp;
  4741         Gear^.MsgParam := Gear^.MsgParam or gmUp;
  4265         end;
  4742         end;
  4266 
  4743 
  4267     if (HHGear^.Message and gmLeft) <> 0 then move.isNegative := true;
  4744     if (HHGear^.Message and gmLeft) <> 0 then move.isNegative := true;
  4268     if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
  4745     if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
  4269         begin
  4746         begin
  4270         HHGear^.dX := HHGear^.dX + (move * _0_1);
  4747         HHGear^.dX := HHGear^.dX + (move * _0_1);
  4271         dec(Gear^.Health, fuel div 5);
  4748         if (Gear^.Health <> BIRDY_ENERGY_INFINITE) then
       
  4749             dec(Gear^.Health, energy div 5);
  4272         Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
  4750         Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
  4273         end;
  4751         end;
  4274 
  4752 
  4275     if Gear^.Health < 0 then
  4753     if (Gear^.Health < 0) and (Gear^.Health <> BIRDY_ENERGY_INFINITE) then
  4276         Gear^.Health := 0;
  4754         Gear^.Health := 0;
  4277 
  4755 
  4278     if ((GameTicks and $FF) = 0) and (Gear^.Health < 500) then
  4756     if ((GameTicks and $FF) = 0) and (Gear^.Health < 500) and (Gear^.Health <> BIRDY_ENERGY_INFINITE) then
  4279         for i:= ((500-Gear^.Health) div 250) downto 0 do
  4757         for i:= ((500-Gear^.Health) div 250) downto 0 do
  4280             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFeather);
  4758             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFeather);
  4281 
  4759 
  4282     if (HHGear^.Message and gmAttack <> 0) then
  4760     if (HHGear^.Message and gmAttack <> 0) then
  4283         begin
  4761         begin
  4287             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + 32, gtEgg, 0, Gear^.dX * _0_5, Gear^.dY, 0);
  4765             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + 32, gtEgg, 0, Gear^.dX * _0_5, Gear^.dY, 0);
  4288             PlaySound(sndBirdyLay);
  4766             PlaySound(sndBirdyLay);
  4289             dec(Gear^.FlightTime)
  4767             dec(Gear^.FlightTime)
  4290             end;
  4768             end;
  4291         s:= ansistring(inttostr(Gear^.FlightTime));
  4769         s:= ansistring(inttostr(Gear^.FlightTime));
  4292         AddCaption(formatA(trmsg[sidRemaining], s), cWhiteColor, capgrpAmmostate);
  4770         AddCaption(formatA(trmsg[sidRemaining], s), capcolDefault, capgrpAmmostate);
  4293         end;
  4771         end;
  4294 
  4772 
  4295     if HHGear^.Message and (gmUp or gmPrecise or gmLeft or gmRight) <> 0 then
  4773     if HHGear^.Message and (gmUp or gmPrecise or gmLeft or gmRight) <> 0 then
  4296         Gear^.State := Gear^.State and (not gsttmpFlag);
  4774         Gear^.State := Gear^.State and (not gsttmpFlag);
  4297 
  4775 
  4347     if (HHGear = nil) or ((HHGear^.State and gstHHDriven) = 0) then
  4825     if (HHGear = nil) or ((HHGear^.State and gstHHDriven) = 0) then
  4348         begin
  4826         begin
  4349         Gear^.Hedgehog := nil;
  4827         Gear^.Hedgehog := nil;
  4350         Gear^.Timer := 0;
  4828         Gear^.Timer := 0;
  4351         Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
  4829         Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
  4352         Gear^.Timer := 0;
       
  4353         Gear^.doStep := @doStepBirdyDisappear;
  4830         Gear^.doStep := @doStepBirdyDisappear;
  4354         CurAmmoGear := nil;
  4831         CurAmmoGear := nil;
  4355         isCursorVisible := false;
  4832         isCursorVisible := false;
  4356         AfterAttack;
  4833         AfterAttack;
  4357         exit
  4834         exit
  4421     i: LongInt;
  4898     i: LongInt;
  4422 begin
  4899 begin
  4423     AllInactive := false;
  4900     AllInactive := false;
  4424     Gear^.dX := Gear^.dX;
  4901     Gear^.dX := Gear^.dX;
  4425     doStepFallingGear(Gear);
  4902     doStepFallingGear(Gear);
  4426     //    CheckGearDrowning(Gear); // already checked for in doStepFallingGear
       
  4427     CalcRotationDirAngle(Gear);
  4903     CalcRotationDirAngle(Gear);
  4428 
  4904 
  4429     if (Gear^.State and gstCollision) <> 0 then
  4905     if (Gear^.State and gstCollision) <> 0 then
  4430         begin
  4906         begin
  4431         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLPoisoned, $C0E0FFE0);
  4907         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLPoisoned, $C0E0FFE0);
  4450 
  4926 
  4451 ////////////////////////////////////////////////////////////////////////////////
  4927 ////////////////////////////////////////////////////////////////////////////////
  4452 procedure doPortalColorSwitch();
  4928 procedure doPortalColorSwitch();
  4453 var CurWeapon: PAmmo;
  4929 var CurWeapon: PAmmo;
  4454 begin
  4930 begin
  4455     if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and ((CurrentHedgehog^.Gear^.Message and gmSwitch) <> 0) then
  4931     if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and ((CurrentHedgehog^.Gear^.State and gstHHDriven) <> 0) and ((CurrentHedgehog^.Gear^.Message and gmSwitch) <> 0) then
  4456             with CurrentHedgehog^ do
  4932             with CurrentHedgehog^ do
  4457                 if (CurAmmoType = amPortalGun) then
  4933                 if (CurAmmoType = amPortalGun) then
  4458                     begin
  4934                     begin
  4459                     PlaySound(sndPortalSwitch);
  4935                     PlaySound(sndPortalSwitch);
  4460                     CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and (not gmSwitch);
  4936                     CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and (not gmSwitch);
  4568                 continue;
  5044                 continue;
  4569             end
  5045             end
  4570         else
  5046         else
  4571             if not ((Gear^.dX*ox + Gear^.dY*oy).isNegative) then
  5047             if not ((Gear^.dX*ox + Gear^.dY*oy).isNegative) then
  4572                 continue;
  5048                 continue;
  4573 
       
  4574         if iterator^.Kind = gtDuck then
       
  4575             // Make duck go into “falling” mode again
       
  4576             iterator^.Pos:= 0;
       
  4577 
  5049 
  4578         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot, gtMinigunBullet]);
  5050         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot, gtMinigunBullet]);
  4579 
  5051 
  4580         r:= int2hwFloat(iterator^.Radius);
  5052         r:= int2hwFloat(iterator^.Radius);
  4581 
  5053 
  4755                 iterator^.dX := resetdx;
  5227                 iterator^.dX := resetdx;
  4756                 iterator^.dY := resetdy;
  5228                 iterator^.dY := resetdy;
  4757                 continue;
  5229                 continue;
  4758                 end;
  5230                 end;
  4759             end;
  5231             end;
       
  5232 
       
  5233         if iterator^.Kind = gtKamikaze then
       
  5234             RefillProximityCache(iterator, 300);
  4760 
  5235 
  4761         //
  5236         //
  4762         // You're now officially portaled!
  5237         // You're now officially portaled!
  4763         //
  5238         //
  4764 
  5239 
  4977     newPortal^.State := newPortal^.State and (not gstCollision);
  5452     newPortal^.State := newPortal^.State and (not gstCollision);
  4978     newPortal^.State := newPortal^.State or gstMoving;
  5453     newPortal^.State := newPortal^.State or gstMoving;
  4979     newPortal^.doStep := @doStepMovingPortal;
  5454     newPortal^.doStep := @doStepMovingPortal;
  4980 end;
  5455 end;
  4981 
  5456 
       
  5457 procedure doStepPiano(Gear: PGear);
       
  5458 var valid: boolean;
       
  5459     HHGear: PGear;
       
  5460 begin
       
  5461     AllInactive := false;
       
  5462     valid := true;
       
  5463 
       
  5464     if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) then
       
  5465         HHGear := Gear^.Hedgehog^.Gear;
       
  5466 
       
  5467     if (WorldEdge = weBounce) then
       
  5468         if (hwRound(Gear^.X) - Gear^.Radius < leftX) then
       
  5469             valid := false
       
  5470         else if (hwRound(Gear^.X) + Gear^.Radius > rightX) then
       
  5471             valid := false;
       
  5472 
       
  5473     if (not valid) then
       
  5474         begin
       
  5475         if (HHGear <> nil) then
       
  5476             begin
       
  5477             HHGear^.Message := HHGear^.Message and (not gmAttack);
       
  5478             HHGear^.State := HHGear^.State and (not gstAttacking);
       
  5479             HHGear^.State := HHGear^.State or gstChooseTarget;
       
  5480             isCursorVisible := true;
       
  5481             end;
       
  5482         DeleteGear(Gear);
       
  5483         PlaySound(sndDenied);
       
  5484         exit;
       
  5485         end;
       
  5486 
       
  5487     isCursorVisible := false;
       
  5488     if (HHGear <> nil) then
       
  5489         begin
       
  5490         PlaySoundV(sndIncoming, Gear^.Hedgehog^.Team^.voicepack);
       
  5491         // Tuck the hedgehog away until the piano attack is completed
       
  5492         Gear^.Hedgehog^.Unplaced:= true;
       
  5493         HHGear^.X:= _0;
       
  5494         HHGear^.Y:= _0;
       
  5495         end;
       
  5496 
       
  5497     PauseMusic;
       
  5498     Gear^.doStep:= @doStepPianoWork;
       
  5499 end;
  4982 ////////////////////////////////////////////////////////////////////////////////
  5500 ////////////////////////////////////////////////////////////////////////////////
  4983 procedure doStepPiano(Gear: PGear);
  5501 procedure doStepPianoWork(Gear: PGear);
  4984 var
  5502 var
  4985     r0, r1: LongInt;
  5503     r0, r1: LongInt;
  4986     odY: hwFloat;
  5504     odY: hwFloat;
  4987 begin
  5505 begin
  4988     AllInactive := false;
  5506     AllInactive := false;
       
  5507     // Play piano notes with slot keys
  4989     if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and
  5508     if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and
  4990         ((CurrentHedgehog^.Gear^.Message and gmSlot) <> 0) then
  5509         ((CurrentHedgehog^.Gear^.Message and gmSlot) <> 0) then
  4991             begin
  5510             begin
       
  5511                 // Piano notes are played if sound OR music (or both) is enabled
  4992                 case CurrentHedgehog^.Gear^.MsgParam of
  5512                 case CurrentHedgehog^.Gear^.MsgParam of
  4993                 0: PlaySound(sndPiano0);
  5513                 0: PlaySound(sndPiano0, false, false, true);
  4994                 1: PlaySound(sndPiano1);
  5514                 1: PlaySound(sndPiano1, false, false, true);
  4995                 2: PlaySound(sndPiano2);
  5515                 2: PlaySound(sndPiano2, false, false, true);
  4996                 3: PlaySound(sndPiano3);
  5516                 3: PlaySound(sndPiano3, false, false, true);
  4997                 4: PlaySound(sndPiano4);
  5517                 4: PlaySound(sndPiano4, false, false, true);
  4998                 5: PlaySound(sndPiano5);
  5518                 5: PlaySound(sndPiano5, false, false, true);
  4999                 6: PlaySound(sndPiano6);
  5519                 6: PlaySound(sndPiano6, false, false, true);
  5000                 7: PlaySound(sndPiano7);
  5520                 7: PlaySound(sndPiano7, false, false, true);
  5001                 else PlaySound(sndPiano8);
  5521                 8: PlaySound(sndPiano8, false, false, true);
  5002             end;
  5522             end;
  5003         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtNote);
  5523         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtNote);
  5004         CurrentHedgehog^.Gear^.MsgParam := 0;
  5524         CurrentHedgehog^.Gear^.MsgParam := 0;
  5005         CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and (not gmSlot);
  5525         CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and (not gmSlot);
  5006         end;
  5526         end;
  5007 
  5527 
  5008     if (*((Gear^.Pos = 3) and ((GameFlags and gfSolidLand) <> 0)) or*) (Gear^.Pos = 5) then
  5528     if (Gear^.Pos = 5) then
  5009         begin
  5529         begin
  5010         Gear^.dY := Gear^.dY + cGravity * 2;
  5530         Gear^.dY := Gear^.dY + cGravity * 2;
  5011         Gear^.Y := Gear^.Y + Gear^.dY;
  5531         Gear^.Y := Gear^.Y + Gear^.dY;
  5012         if CheckGearDrowning(Gear) then
  5532         if CheckGearDrowning(Gear) then
  5013             begin
  5533             begin
  5119         x := hwRound(Gear^.X);
  5639         x := hwRound(Gear^.X);
  5120         y := hwRound(Gear^.Y);
  5640         y := hwRound(Gear^.Y);
  5121 
  5641 
  5122         if WorldEdge = weWrap then
  5642         if WorldEdge = weWrap then
  5123             begin
  5643             begin
  5124             if x > LongInt(rightX) then
  5644             if x > rightX then
  5125                 repeat
  5645                 repeat
  5126                     dec(x,  playWidth);
  5646                     dec(x,  playWidth);
  5127                     dec(rx, playWidth);
  5647                     dec(rx, playWidth);
  5128                 until x <= LongInt(rightX)
  5648                 until x <= rightX
  5129             else if x < LongInt(leftX) then
  5649             else if x < leftX then
  5130                 repeat
  5650                 repeat
  5131                     inc(x,  playWidth);
  5651                     inc(x,  playWidth);
  5132                     inc(rx, playWidth);
  5652                     inc(rx, playWidth);
  5133                 until x >= LongInt(leftX);
  5653                 until x >= leftX;
  5134             end
  5654             end
  5135         else if (WorldEdge = weBounce) then
  5655         else if (WorldEdge = weBounce) then
  5136             begin
  5656             begin
  5137             if (not justBounced) and ((x > LongInt(rightX)) or (x < LongInt(leftX))) then
  5657             if (not justBounced) and ((x > rightX) or (x < leftX)) then
  5138                 begin
  5658                 begin
  5139                 // reflect
  5659                 // reflect
  5140                 lX:= lX - ldX + ((oX - lX) * 2);
  5660                 lX:= lX - ldX + ((oX - lX) * 2);
  5141                 lY:= lY - ldY;
  5661                 lY:= lY - ldY;
  5142                 Gear^.X:= oX;
  5662                 Gear^.X:= oX;
  5185                 // if at least 5 collisions occured
  5705                 // if at least 5 collisions occured
  5186                 if Gear^.Damage > 0 then
  5706                 if Gear^.Damage > 0 then
  5187                     begin
  5707                     begin
  5188                     if ((GameFlags and gfSolidLand) = 0) then
  5708                     if ((GameFlags and gfSolidLand) = 0) then
  5189                         begin
  5709                         begin
  5190                         DrawExplosion(rX,rY,Gear^.Radius);
  5710                         doMakeExplosion(rX,rY,Gear^.Radius, Gear^.Hedgehog, EXPLNoDamage or EXPLDoNotTouchAny or EXPLNoGfx);
  5191                         end;
  5711                         end;
  5192 
  5712 
  5193                     // kick nearby hogs
  5713                     // kick nearby hogs
  5194                     AmmoShove(Gear, Gear^.Boom, 50);
  5714                     AmmoShove(Gear, Gear^.Boom, 50);
  5195 
  5715 
  5267         // push the shooting Hedgehog back
  5787         // push the shooting Hedgehog back
  5268         Gear^.dX.isNegative := not Gear^.dX.isNegative;
  5788         Gear^.dX.isNegative := not Gear^.dX.isNegative;
  5269         Gear^.dY.isNegative := not Gear^.dY.isNegative;
  5789         Gear^.dY.isNegative := not Gear^.dY.isNegative;
  5270         HHGear^.dX := Gear^.dX;
  5790         HHGear^.dX := Gear^.dX;
  5271         HHGear^.dY := Gear^.dY;
  5791         HHGear^.dY := Gear^.dY;
  5272         AmmoShove(Gear, 0, 80);
  5792         AmmoShove(Gear, 0, 79);
  5273         Gear^.dX.isNegative := not Gear^.dX.isNegative;
  5793         Gear^.dX.isNegative := not Gear^.dX.isNegative;
  5274         Gear^.dY.isNegative := not Gear^.dY.isNegative;
  5794         Gear^.dY.isNegative := not Gear^.dY.isNegative;
  5275         end;
  5795         end;
  5276 
  5796 
  5277     Gear^.doStep := @doStepSineGunShotWork;
  5797     Gear^.doStep := @doStepSineGunShotWork;
  5291 begin
  5811 begin
  5292     AllInactive := false;
  5812     AllInactive := false;
  5293     HHGear := Gear^.Hedgehog^.Gear;
  5813     HHGear := Gear^.Hedgehog^.Gear;
  5294     if HHGear = nil then
  5814     if HHGear = nil then
  5295         begin
  5815         begin
       
  5816         StopSoundChan(Gear^.SoundChannel, 300);
  5296         DeleteGear(gear);
  5817         DeleteGear(gear);
  5297         exit
  5818         exit
  5298         end;
  5819         end;
  5299     HedgehogChAngle(HHGear);
  5820     HedgehogChAngle(HHGear);
  5300     gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
  5821     gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
  5329             speed := _0_5 * (_10 / Gear^.Tag);
  5850             speed := _0_5 * (_10 / Gear^.Tag);
  5330 
  5851 
  5331             flame:= AddGear(gx, gy, gtFlame, gstTmpFlag,
  5852             flame:= AddGear(gx, gy, gtFlame, gstTmpFlag,
  5332                     SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
  5853                     SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
  5333                     AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
  5854                     AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
  5334             flame^.CollisionMask:= lfNotCurrentMask;
  5855             flame^.CollisionMask:= lfNotCurHogCrate;
  5335             //flame^.FlightTime:= 500;  use the default huge value to avoid sticky flame suddenly being damaging as opposed to other flames
       
  5336 
  5856 
  5337             if (Gear^.Health mod 30) = 0 then
  5857             if (Gear^.Health mod 30) = 0 then
  5338                 begin
  5858                 begin
  5339                 flame:= AddGear(gx, gy, gtFlame, 0,
  5859                 flame:= AddGear(gx, gy, gtFlame, 0,
  5340                         SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
  5860                         SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
  5341                         AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
  5861                         AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
  5342                 flame^.CollisionMask:= lfNotCurrentMask;
  5862                 flame^.CollisionMask:= lfNotCurHogCrate;
  5343 		//flame^.FlightTime:= 500;
       
  5344                 end
  5863                 end
  5345             end;
  5864             end;
  5346         Gear^.Timer:= Gear^.Tag
  5865         Gear^.Timer:= Gear^.Tag
  5347         end;
  5866         end;
  5348 
  5867 
  5349     if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) then
  5868     if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) then
  5350         begin
  5869         begin
       
  5870         HHGear^.Message:= HHGear^.Message and (not (gmAttack or gmLeft or gmRight));
  5351         HHGear^.State := HHGear^.State and (not gstNotKickable);
  5871         HHGear^.State := HHGear^.State and (not gstNotKickable);
       
  5872         StopSoundChan(Gear^.SoundChannel, 300);
  5352         DeleteGear(Gear);
  5873         DeleteGear(Gear);
  5353         AfterAttack
  5874         AfterAttack
  5354         end
  5875         end
  5355     else
  5876     else
  5356         begin
  5877         begin
  5357         i:= Gear^.Health div 5;
  5878         i:= Gear^.Health div 5;
  5358         if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
  5879         if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
  5359             begin
  5880             begin
  5360             Gear^.Damage:= i;
  5881             Gear^.Damage:= i;
  5361             FreeAndNilTexture(Gear^.Tex);
  5882             FreeAndNilTexture(Gear^.Tex);
  5362             Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ansistring(': ' + inttostr(i) +
  5883             Gear^.Tex := RenderStringTex(FormatA(trmsg[sidFuel], ansistring(inttostr(i))),
  5363                          '%'), cWhiteColor, fntSmall)
  5884                          cWhiteColor, fntSmall)
  5364             end
  5885             end
  5365         end
  5886         end
  5366 end;
  5887 end;
  5367 
  5888 
  5368 procedure doStepFlamethrower(Gear: PGear);
  5889 procedure doStepFlamethrower(Gear: PGear);
  5370     HHGear: PGear;
  5891     HHGear: PGear;
  5371 begin
  5892 begin
  5372     HHGear := Gear^.Hedgehog^.Gear;
  5893     HHGear := Gear^.Hedgehog^.Gear;
  5373     HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown or gmLeft or gmRight));
  5894     HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown or gmLeft or gmRight));
  5374     HHGear^.State := HHGear^.State or gstNotKickable;
  5895     HHGear^.State := HHGear^.State or gstNotKickable;
       
  5896     (* NOTE: Flamethrower sound is supposed to start instantly (no fade in),
       
  5897     but this would cause the game volume to screw up because of a bug in SDL_mixer:
       
  5898     https://bugzilla.libsdl.org/show_bug.cgi?id=4205
       
  5899     As workaround, a tiny fade-in delay was added.
       
  5900     FIXME: Remove the fade-in delay argument when the SDL bug has been fixed. *)
       
  5901     Gear^.SoundChannel := LoopSound(sndFlamethrower, 20);
  5375     Gear^.doStep := @doStepFlamethrowerWork
  5902     Gear^.doStep := @doStepFlamethrowerWork
  5376 end;
  5903 end;
  5377 
  5904 
  5378 ////////////////////////////////////////////////////////////////////////////////
  5905 ////////////////////////////////////////////////////////////////////////////////
  5379 procedure doStepLandGunWork(Gear: PGear);
  5906 procedure doStepLandGunWork(Gear: PGear);
  5384 begin
  5911 begin
  5385     AllInactive := false;
  5912     AllInactive := false;
  5386     HHGear := Gear^.Hedgehog^.Gear;
  5913     HHGear := Gear^.Hedgehog^.Gear;
  5387     if HHGear = nil then
  5914     if HHGear = nil then
  5388         begin
  5915         begin
       
  5916         StopSoundChan(gear^.SoundChannel);
  5389         DeleteGear(gear);
  5917         DeleteGear(gear);
  5390         exit
  5918         exit
  5391         end;
  5919         end;
  5392     HedgehogChAngle(HHGear);
  5920     HedgehogChAngle(HHGear);
  5393     gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
  5921     gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
  5421         speed := (_3 / Gear^.Tag);
  5949         speed := (_3 / Gear^.Tag);
  5422 
  5950 
  5423         land:= AddGear(gx, gy, gtFlake, gstTmpFlag,
  5951         land:= AddGear(gx, gy, gtFlake, gstTmpFlag,
  5424                 SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
  5952                 SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
  5425                 AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
  5953                 AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
  5426         land^.CollisionMask:= lfNotCurrentMask;
  5954         land^.CollisionMask:= lfNotCurHogCrate;
  5427 
  5955 
  5428         Gear^.Timer:= Gear^.Tag
  5956         Gear^.Timer:= Gear^.Tag
  5429         end;
  5957         end;
  5430 
  5958 
  5431     if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) or ((HHGear^.Message and gmAttack) <> 0) then
  5959     if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) or ((HHGear^.Message and gmAttack) <> 0) then
  5432         begin
  5960         begin
  5433         HHGear^.Message:= HHGear^.Message and (not gmAttack);
  5961         HHGear^.Message:= HHGear^.Message and (not (gmAttack or gmLeft or gmRight));
  5434         HHGear^.State := HHGear^.State and (not gstNotKickable);
  5962         HHGear^.State := HHGear^.State and (not gstNotKickable);
       
  5963         StopSoundChan(gear^.SoundChannel);
  5435         DeleteGear(Gear);
  5964         DeleteGear(Gear);
  5436         AfterAttack
  5965         AfterAttack
  5437         end
  5966         end
  5438     else
  5967     else
  5439         begin
  5968         begin
  5440         i:= Gear^.Health div 10;
  5969         i:= Gear^.Health div 10;
  5441         if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
  5970         if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
  5442             begin
  5971             begin
  5443             Gear^.Damage:= i;
  5972             Gear^.Damage:= i;
  5444             FreeAndNilTexture(Gear^.Tex);
  5973             FreeAndNilTexture(Gear^.Tex);
  5445             Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ansistring(': ' + inttostr(i) +
  5974             Gear^.Tex := RenderStringTex(FormatA(trmsg[sidFuel], ansistring(inttostr(i))),
  5446                          '%'), cWhiteColor, fntSmall)
  5975                          cWhiteColor, fntSmall)
  5447             end
  5976             end
  5448         end
  5977         end
  5449 end;
  5978 end;
  5450 
  5979 
  5451 procedure doStepLandGun(Gear: PGear);
  5980 procedure doStepLandGun(Gear: PGear);
  5453     HHGear: PGear;
  5982     HHGear: PGear;
  5454 begin
  5983 begin
  5455     HHGear := Gear^.Hedgehog^.Gear;
  5984     HHGear := Gear^.Hedgehog^.Gear;
  5456     HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown or gmLeft or gmRight or gmAttack));
  5985     HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown or gmLeft or gmRight or gmAttack));
  5457     HHGear^.State := HHGear^.State or gstNotKickable;
  5986     HHGear^.State := HHGear^.State or gstNotKickable;
       
  5987     Gear^.SoundChannel := LoopSound(sndLandGun);
  5458     Gear^.doStep := @doStepLandGunWork
  5988     Gear^.doStep := @doStepLandGunWork
  5459 end;
  5989 end;
  5460 
  5990 
  5461 ////////////////////////////////////////////////////////////////////////////////
  5991 ////////////////////////////////////////////////////////////////////////////////
  5462 procedure doStepPoisonCloud(Gear: PGear);
  5992 procedure doStepPoisonCloud(Gear: PGear);
  5505     tmp:= t^.ar[i];
  6035     tmp:= t^.ar[i];
  5506     if (tmp^.State and gstNoDamage) = 0 then
  6036     if (tmp^.State and gstNoDamage) = 0 then
  5507         if (tmp^.Kind = gtHedgehog) or (tmp^.Kind = gtMine) or (tmp^.Kind = gtExplosives) then
  6037         if (tmp^.Kind = gtHedgehog) or (tmp^.Kind = gtMine) or (tmp^.Kind = gtExplosives) then
  5508             begin
  6038             begin
  5509             dmg:= 0;
  6039             dmg:= 0;
  5510             //tmp^.State:= tmp^.State or gstFlatened;
       
  5511             if (tmp^.Kind <> gtHedgehog) or (tmp^.Hedgehog^.Effects[heInvulnerable] = 0) then
  6040             if (tmp^.Kind <> gtHedgehog) or (tmp^.Hedgehog^.Effects[heInvulnerable] = 0) then
  5512                 begin
  6041                 begin
  5513                 // base damage on remaining health
  6042                 // base damage on remaining health
  5514                 dmg:= (tmp^.Health - tmp^.Damage);
  6043                 dmg:= (tmp^.Health - tmp^.Damage);
  5515                 if dmg > 0 then
  6044                 if dmg > 0 then
  5516                     begin
  6045                     begin
  5517                     // always rounding down
  6046                     // always rounding down
  5518                     dmg:= dmg div Gear^.Boom;
  6047                     dmg:= dmg div Gear^.Boom;
  5519 
  6048 
  5520                     if dmg > 0 then
  6049                     if dmg > 0 then
  5521                         ApplyDamage(tmp, CurrentHedgehog, dmg, dsUnknown);
  6050                         ApplyDamage(tmp, CurrentHedgehog, dmg, dsHammer);
  5522                     end;
  6051                     end;
  5523 		tmp^.dY:= _0_03 * Gear^.Boom
  6052         tmp^.dY:= _0_03 * Gear^.Boom
  5524                 end;
  6053                 end;
  5525 
  6054 
  5526             if (tmp^.Kind <> gtHedgehog) or (dmg > 0) or (tmp^.Health > tmp^.Damage) then
  6055             if (tmp^.Kind <> gtHedgehog) or (dmg > 0) or (tmp^.Health > tmp^.Damage) then
  5527                 begin
  6056                 begin
  5528                 //DrawTunnel(tmp^.X, tmp^.Y - _1, _0, _0_5, cHHRadius * 6, cHHRadius * 3);
       
  5529                 tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0);
  6057                 tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0);
  5530                 tmp2^.LinkedGear:= tmp;
  6058                 tmp2^.LinkedGear:= tmp;
  5531                 SetAllToActive
  6059                 SetAllToActive
  5532                 end;
  6060                 end;
  5533             end;
  6061             end;
  5556         begin
  6084         begin
  5557         AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
  6085         AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
  5558 
  6086 
  5559         i := hwRound(Gear^.X) - HitGear^.Radius + 2;
  6087         i := hwRound(Gear^.X) - HitGear^.Radius + 2;
  5560         ei := hwRound(Gear^.X) + HitGear^.Radius - 2;
  6088         ei := hwRound(Gear^.X) + HitGear^.Radius - 2;
  5561         for j := 1 to 4 do DrawExplosion(i - GetRandom(5), hwRound(Gear^.Y) + 6*j, 3);
  6089         for j := 1 to 4 do doMakeExplosion(i - GetRandom(5), hwRound(Gear^.Y) + 6*j, 3, Gear^.Hedgehog, EXPLNoDamage or EXPLDoNotTouchAny or EXPLNoGfx or EXPLForceDraw);
  5562         for j := 1 to 4 do DrawExplosion(ei + LongInt(GetRandom(5)), hwRound(Gear^.Y) + 6*j, 3);
  6090         for j := 1 to 4 do doMakeExplosion(ei + LongInt(GetRandom(5)), hwRound(Gear^.Y) + 6*j, 3, Gear^.Hedgehog, EXPLNoDamage or EXPLDoNotTouchAny or EXPLNoGfx or EXPLForceDraw);
  5563         while i <= ei do
  6091         while i <= ei do
  5564             begin
  6092             begin
  5565             for j := 1 to 11 do DrawExplosion(i, hwRound(Gear^.Y) + 3*j, 3);
  6093             for j := 1 to 11 do doMakeExplosion(i, hwRound(Gear^.Y) + 3*j, 3, Gear^.Hedgehog, EXPLNoDamage or EXPLDoNotTouchAny or EXPLNoGfx or EXPLForceDraw);
  5566             inc(i, 1)
  6094             inc(i, 1)
  5567             end;
  6095             end;
  5568 
  6096 
  5569         if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9)
  6097         if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9)
  5570            , lfIndestructible) then
  6098            , lfIndestructible) then
  5571             begin
  6099             begin
  5572             //Gear^.X := Gear^.X + Gear^.dX;
       
  5573             Gear^.Y := Gear^.Y + _1_9
  6100             Gear^.Y := Gear^.Y + _1_9
  5574             end;
  6101             end;
  5575         end;
  6102         end;
  5576     if TestCollisionYwithGear(Gear, 1) <> 0 then
  6103     if TestCollisionYwithGear(Gear, 1) <> 0 then
  5577         begin
  6104         begin
  5579         SetLittle(HitGear^.dX);
  6106         SetLittle(HitGear^.dX);
  5580         HitGear^.dY := _0;
  6107         HitGear^.dY := _0;
  5581         end
  6108         end
  5582     else
  6109     else
  5583         begin
  6110         begin
  5584         //Gear^.dY := Gear^.dY + cGravity;
       
  5585         //Gear^.Y := Gear^.Y + Gear^.dY;
       
  5586         if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then
  6111         if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then
  5587             Gear^.Timer := 1
  6112             Gear^.Timer := 1
  5588         end;
  6113         end;
  5589 
  6114 
  5590     //Gear^.X := Gear^.X + HitGear^.dX;
       
  5591     HitGear^.X := Gear^.X;
  6115     HitGear^.X := Gear^.X;
  5592     HitGear^.Y := Gear^.Y;
  6116     HitGear^.Y := Gear^.Y;
  5593     SetLittle(HitGear^.dY);
  6117     SetLittle(HitGear^.dY);
  5594     HitGear^.Active:= true;
  6118     HitGear^.Active:= true;
  5595 end;
  6119 end;
  5627     resgear: PGear;
  6151     resgear: PGear;
  5628     hh: PHedgehog;
  6152     hh: PHedgehog;
  5629     i: LongInt;
  6153     i: LongInt;
  5630     s: ansistring;
  6154     s: ansistring;
  5631 begin
  6155 begin
  5632     if (TurnTimeLeft > 0) then
       
  5633         dec(TurnTimeLeft);
       
  5634 
       
  5635     AllInactive := false;
  6156     AllInactive := false;
  5636     hh := Gear^.Hedgehog;
  6157     hh := Gear^.Hedgehog;
  5637 
       
  5638     // no, you can't do that here
       
  5639     {DrawCentered(hwRound(hh^.Gear^.X) + WorldDx, hwRound(hh^.Gear^.Y) + WorldDy -
       
  5640             cHHRadius - 14 - hh^.HealthTagTex^.h, hh^.HealthTagTex);
       
  5641     }
       
  5642     (*DrawCircle(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, 1.5, 0, 0, $FF,
       
  5643             $FF);*)
       
  5644 
  6158 
  5645     if ((Gear^.Message and gmUp) <> 0) then
  6159     if ((Gear^.Message and gmUp) <> 0) then
  5646         begin
  6160         begin
  5647         if (GameTicks and $F) <> 0 then
  6161         if (GameTicks and $F) <> 0 then
  5648         exit;
  6162         exit;
  5675             hh^.Gear^.Damage:= 1;
  6189             hh^.Gear^.Damage:= 1;
  5676         RenderHealth(hh^);
  6190         RenderHealth(hh^);
  5677         RecountTeamHealth(hh^.Team);
  6191         RecountTeamHealth(hh^.Team);
  5678         inc(graves.ar^[Gear^.Tag]^.Health);
  6192         inc(graves.ar^[Gear^.Tag]^.Health);
  5679         inc(Gear^.Tag)
  6193         inc(Gear^.Tag)
  5680 {-for i:= 0 to High(graves) do begin
       
  5681             if hh^.Gear^.Health > 0 then begin
       
  5682                 dec(hh^.Gear^.Health);
       
  5683                 inc(graves[i]^.Health);
       
  5684             end;
       
  5685         end; -}
       
  5686         end
  6194         end
  5687     else
  6195     else
  5688         begin
  6196         begin
  5689         // now really resurrect the hogs with the hp saved in the graves
  6197         // now really resurrect the hogs with the hp saved in the graves
  5690         for i:= 0 to graves.size - 1 do
  6198         for i:= 0 to graves.size - 1 do
  5697                 graves.ar^[i]^.Message:= graves.ar^[i]^.Message or gmDestroy;
  6205                 graves.ar^[i]^.Message:= graves.ar^[i]^.Message or gmDestroy;
  5698                 graves.ar^[i]^.Active:= true;
  6206                 graves.ar^[i]^.Active:= true;
  5699                 RenderHealth(resgear^.Hedgehog^);
  6207                 RenderHealth(resgear^.Hedgehog^);
  5700                 RecountTeamHealth(resgear^.Hedgehog^.Team);
  6208                 RecountTeamHealth(resgear^.Hedgehog^.Team);
  5701                 resgear^.Hedgehog^.Effects[heResurrected]:= 1;
  6209                 resgear^.Hedgehog^.Effects[heResurrected]:= 1;
       
  6210                 if resgear^.Hedgehog^.King then
       
  6211                     resgear^.Hedgehog^.Team^.hasKing:= true;
       
  6212                 { Reviving a hog implies its clan is now alive, too. }
       
  6213                 resgear^.Hedgehog^.Team^.Clan^.DeathLogged:= false;
       
  6214                 if (not resgear^.Hedgehog^.Team^.Passive) then
       
  6215                     resgear^.Hedgehog^.Team^.Clan^.Passive:= false;
  5702                 s:= ansistring(resgear^.Hedgehog^.Name);
  6216                 s:= ansistring(resgear^.Hedgehog^.Name);
  5703                 AddCaption(FormatA(GetEventString(eidResurrected), s), cWhiteColor, capgrpMessage);
  6217                 AddCaption(FormatA(GetEventString(eidResurrected), s), capcolDefault, capgrpMessage);
  5704                 // only make hat-less hedgehogs look like zombies, preserve existing hats
  6218                 // only make hat-less hedgehogs look like zombies, preserve existing hats
  5705 
  6219 
  5706                 if resgear^.Hedgehog^.Hat = 'NoHat' then
  6220                 if resgear^.Hedgehog^.Hat = 'NoHat' then
  5707                     LoadHedgehogHat(resgear^.Hedgehog^, 'Reserved/Zombie');
  6221                     LoadHedgehogHat(resgear^.Hedgehog^, 'Reserved/Zombie');
  5708                 end;
  6222                 end;
  5712         doStepHedgehogMoving(hh^.Gear);
  6226         doStepHedgehogMoving(hh^.Gear);
  5713         StopSoundChan(Gear^.SoundChannel);
  6227         StopSoundChan(Gear^.SoundChannel);
  5714         Gear^.Timer := 250;
  6228         Gear^.Timer := 250;
  5715         Gear^.doStep := @doStepIdle;
  6229         Gear^.doStep := @doStepIdle;
  5716         end
  6230         end
  5717     //if hh^.Gear^.Health = 0 then doStepHedgehogFree(hh^.Gear);
       
  5718 end;
  6231 end;
  5719 
  6232 
  5720 procedure doStepResurrector(Gear: PGear);
  6233 procedure doStepResurrector(Gear: PGear);
  5721 var
  6234 var
  5722     graves: PGearArrayS;
  6235     graves: PGearArrayS;
  5790         end;
  6303         end;
  5791     if (GameTicks and $3F) = 0 then
  6304     if (GameTicks and $3F) = 0 then
  5792         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  6305         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  5793     dec(Gear^.Timer)
  6306     dec(Gear^.Timer)
  5794 end;
  6307 end;
  5795 
       
  5796 (*
       
  5797 ////////////////////////////////////////////////////////////////////////////////
       
  5798 procedure doStepStructure(Gear: PGear);
       
  5799 var
       
  5800     x, y: LongInt;
       
  5801     HH: PHedgehog;
       
  5802     t: PGear;
       
  5803 begin
       
  5804     HH:= Gear^.Hedgehog;
       
  5805 
       
  5806     if (Gear^.State and gstMoving) <> 0 then
       
  5807         begin
       
  5808         AddCI(Gear);
       
  5809         Gear^.dX:= _0;
       
  5810         Gear^.dY:= _0;
       
  5811         Gear^.State:= Gear^.State and (not gstMoving);
       
  5812         end;
       
  5813 
       
  5814     dec(Gear^.Health, Gear^.Damage);
       
  5815     Gear^.Damage:= 0;
       
  5816 
       
  5817     if Gear^.Pos = 1 then
       
  5818         begin
       
  5819         AddCI(Gear);
       
  5820         AfterAttack;
       
  5821         if Gear = CurAmmoGear then
       
  5822             CurAmmoGear:= nil;
       
  5823         if HH^.Gear <> nil then
       
  5824             HideHog(HH);
       
  5825         Gear^.Pos:= 2
       
  5826         end;
       
  5827 
       
  5828     if Gear^.Pos = 2 then
       
  5829         begin
       
  5830         if ((GameTicks mod 100) = 0) and (Gear^.Timer < 1000) then
       
  5831             begin
       
  5832             if (Gear^.Timer mod 10) = 0 then
       
  5833                 begin
       
  5834                 DeleteCI(Gear);
       
  5835                 Gear^.Y:= Gear^.Y - _0_5;
       
  5836                 AddCI(Gear);
       
  5837                 end;
       
  5838             inc(Gear^.Timer);
       
  5839             end;
       
  5840         if Gear^.Tag <= TotalRounds then
       
  5841             Gear^.Pos:= 3;
       
  5842         end;
       
  5843 
       
  5844     if Gear^.Pos = 3 then
       
  5845         if Gear^.Timer < 1000 then
       
  5846             begin
       
  5847             if (Gear^.Timer mod 10) = 0 then
       
  5848                 begin
       
  5849                 DeleteCI(Gear);
       
  5850                 Gear^.Y:= Gear^.Y - _0_5;
       
  5851                 AddCI(Gear);
       
  5852                 end;
       
  5853             inc(Gear^.Timer);
       
  5854             end
       
  5855         else
       
  5856             begin
       
  5857             if HH^.GearHidden <> nil then
       
  5858                 RestoreHog(HH);
       
  5859             Gear^.Pos:= 4;
       
  5860             end;
       
  5861 
       
  5862     if Gear^.Pos = 4 then
       
  5863         if ((GameTicks mod 1000) = 0) and ((GameFlags and gfInvulnerable) = 0) then
       
  5864             begin
       
  5865             t:= GearsList;
       
  5866             while t <> nil do
       
  5867                 begin
       
  5868                 if (t^.Kind = gtHedgehog) and (t^.Hedgehog^.Team^.Clan = HH^.Team^.Clan) then
       
  5869                     t^.Hedgehog^.Effects[heInvulnerable]:= 1;
       
  5870                 t:= t^.NextGear;
       
  5871                 end;
       
  5872             end;
       
  5873 
       
  5874     if Gear^.Health <= 0 then
       
  5875         begin
       
  5876         if HH^.GearHidden <> nil then
       
  5877             RestoreHog(HH);
       
  5878 
       
  5879         x := hwRound(Gear^.X);
       
  5880         y := hwRound(Gear^.Y);
       
  5881 
       
  5882         DeleteCI(Gear);
       
  5883         DeleteGear(Gear);
       
  5884 
       
  5885         doMakeExplosion(x, y, 50, CurrentHedgehog, EXPLAutoSound);
       
  5886         end;
       
  5887 end;
       
  5888 *)
       
  5889 
  6308 
  5890 ////////////////////////////////////////////////////////////////////////////////
  6309 ////////////////////////////////////////////////////////////////////////////////
  5891 (*
  6310 (*
  5892  TARDIS needs
  6311  TARDIS needs
  5893  Warp in.  Pos = 1
  6312  Warp in.  Pos = 1
  5905 var HH: PHedgehog;
  6324 var HH: PHedgehog;
  5906     i,j,cnt: LongWord;
  6325     i,j,cnt: LongWord;
  5907     s: ansistring;
  6326     s: ansistring;
  5908 begin
  6327 begin
  5909 HH:= Gear^.Hedgehog;
  6328 HH:= Gear^.Hedgehog;
       
  6329 if Gear^.Tag = 0 then
       
  6330     begin
       
  6331     if HH^.Gear <> nil then
       
  6332         begin
       
  6333         if (HH^.Gear^.Damage <> 0) or (HH^.Gear^.Health = 0) or
       
  6334         ((HH^.Gear^.State and (gstMoving or gstHHDeath or gstHHGone or gstDrowning)) <> 0) then
       
  6335             begin
       
  6336             Gear^.Tag:= 1;
       
  6337             HH^.Gear^.State:= HH^.Gear^.State and (not gstAttacking);
       
  6338             HH^.Gear^.Message:= HH^.Gear^.Message and (not gmAttack);
       
  6339             AfterAttack;
       
  6340             end;
       
  6341         end
       
  6342     else if HH^.GearHidden = nil then
       
  6343         Gear^.Tag:= 1;
       
  6344     if (Gear^.Tag = 1) and (Gear = CurAmmoGear) then
       
  6345         CurAmmoGear:= nil;
       
  6346     end;
       
  6347 
  5910 if Gear^.Pos = 2 then
  6348 if Gear^.Pos = 2 then
  5911     begin
  6349     begin
  5912     StopSoundChan(Gear^.SoundChannel);
  6350     StopSoundChan(Gear^.SoundChannel);
  5913     Gear^.SoundChannel:= -1;
  6351     Gear^.SoundChannel:= -1;
  5914     if (Gear^.Timer = 0) then
  6352     if (Gear^.Timer = 0) then
  5915         begin
  6353         begin
  5916         if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible = 0) then
  6354         if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible = 0) then
  5917             begin
  6355             begin
  5918             AfterAttack;
  6356             if Gear^.Tag = 0 then
  5919             if Gear = CurAmmoGear then CurAmmoGear := nil;
  6357                 AfterAttack;
  5920             if (HH^.Gear^.Damage = 0) and  (HH^.Gear^.Health > 0) and
  6358             if Gear = CurAmmoGear then
  5921             ((Gear^.State and (gstMoving or gstHHDeath or gstHHGone)) = 0) then
  6359                 CurAmmoGear:= nil;
  5922                 HideHog(HH)
  6360             if Gear^.Tag = 0 then
       
  6361                 HideHog(HH);
  5923             end
  6362             end
  5924         //else if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible <> 0) then
  6363         else if (HH^.GearHidden <> nil) then
  5925         else if (HH^.GearHidden <> nil) then// and (HH^.Gear^.State and gstInvisible <> 0) then
       
  5926             begin
  6364             begin
  5927             RestoreHog(HH);
  6365             RestoreHog(HH);
  5928             s:= ansistring(HH^.Name);
  6366             s:= ansistring(HH^.Name);
  5929             AddCaption(FormatA(GetEventString(eidTimeTravelEnd), s), cWhiteColor, capgrpMessage)
  6367             AddCaption(FormatA(GetEventString(eidTimeTravelEnd), s), capcolDefault, capgrpMessage)
  5930             end
  6368             end
  5931         end;
  6369         end;
  5932 
  6370 
  5933     inc(Gear^.Timer);
  6371     inc(Gear^.Timer);
  5934     if (Gear^.Timer > 2000) and ((GameTicks mod 2000) = 1000) then
  6372     if (Gear^.Timer > 2000) and ((GameTicks mod 2000) = 1000) then
  5940 
  6378 
  5941 if (Gear^.Pos = 1) and (GameTicks and $1F = 0) and (Gear^.Power < 255) then
  6379 if (Gear^.Pos = 1) and (GameTicks and $1F = 0) and (Gear^.Power < 255) then
  5942     begin
  6380     begin
  5943     inc(Gear^.Power);
  6381     inc(Gear^.Power);
  5944     if (Gear^.Power = 172) and (HH^.Gear <> nil) and
  6382     if (Gear^.Power = 172) and (HH^.Gear <> nil) and
  5945         (HH^.Gear^.Damage = 0) and (HH^.Gear^.Health > 0) and
  6383         (Gear^.Tag = 0) then
  5946         ((HH^.Gear^.State and (gstMoving or gstHHDeath or gstHHGone)) = 0) then
       
  5947             with HH^.Gear^ do
  6384             with HH^.Gear^ do
  5948                 begin
  6385                 begin
  5949                 State:= State or gstAnimation;
  6386                 State:= State or gstAnimation;
  5950                 Tag:= 2;
  6387                 Tag:= 2;
  5951                 Timer:= 0;
  6388                 Timer:= 0;
  6026 end;
  6463 end;
  6027 
  6464 
  6028 ////////////////////////////////////////////////////////////////////////////////
  6465 ////////////////////////////////////////////////////////////////////////////////
  6029 
  6466 
  6030 (*
  6467 (*
  6031 WIP. The ice gun will have the following effects.  It has been proposed by sheepluva that it take the appearance of a large freezer
  6468 The ice gun has the following effects:
  6032 spewing ice cubes.  The cubes will be visual gears only.  The scatter from them and the impact snow dust should help hide imprecisions in things like the GearsNear effect.
  6469 A "ray" like a deagle is projected out from the gun.
  6033 For now we assume a "ray" like a deagle projected out from the gun.
       
  6034 All these effects assume the ray's angle is not changed and that the target type was unchanged over a number of ticks.  This is a simplifying assumption for "gun was applying freezing effect to the same target".
  6470 All these effects assume the ray's angle is not changed and that the target type was unchanged over a number of ticks.  This is a simplifying assumption for "gun was applying freezing effect to the same target".
  6035   * When fired at water a layer of ice textured land is added above the water.
  6471   * When fired at water a layer of ice textured land is added above the water.
  6036   * When fired at non-ice land (land and lfLandMask and not lfIce) the land is overlaid with a thin layer of ice textured land around that point (say, 1 or 2px into land, 1px above). For attractiveness, a slope would probably be needed.
  6472   * When fired at non-ice land (land and lfLandMask and not lfIce) the land is overlaid with a thin layer of ice textured land around that point (say, 1 or 2px into land, 1px above). For attractiveness, a slope would probably be needed.
  6037   * When fired at a hog (land and $00FF <> 0), while the hog is targetted, the hog's state is set to frozen.
  6473   * When fired at a hog (land and $00FF <> 0), while the hog is targetted, the hog's state is set to frozen.
  6038     As long as the gun is on the hog, a frozen hog sprite creeps up from the feet to the head.
  6474     As long as the gun is on the hog, a frozen hog sprite creeps up from the feet to the head.
  6039     If the effect is interrupted before reaching the top, the freezing state is cleared.
  6475     If the effect is interrupted before reaching the top, the freezing state is cleared.
  6040 A frozen hog will animate differently.
  6476 A frozen hog will animate differently.
  6041     To be decided, but possibly in a similar fashion to a grave when it comes to explosions.
  6477     Frozen hogs take less damage and are harder to push.
  6042     The hog might (possibly) not be damaged by explosions.
       
  6043     This might make freezing potentially useful for friendlies in a bad position.
  6478     This might make freezing potentially useful for friendlies in a bad position.
  6044     It might be better to allow damage though.
       
  6045 A frozen hog stays frozen for a certain number of turns.
  6479 A frozen hog stays frozen for a certain number of turns.
  6046     Each turn the frozen overlay becomes fainter, until it fades and the hog animates normally again.
  6480     Each turn the frozen overlay becomes fainter, until it fades and the hog animates normally again.
  6047 *)
  6481 *)
  6048 
  6482 
  6049 
  6483 
  6054     t:= Gear^.Health div 10;
  6488     t:= Gear^.Health div 10;
  6055     if (t <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
  6489     if (t <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
  6056     begin
  6490     begin
  6057     Gear^.Damage:= t;
  6491     Gear^.Damage:= t;
  6058     FreeAndNilTexture(Gear^.Tex);
  6492     FreeAndNilTexture(Gear^.Tex);
  6059     Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ansistring(': ' + inttostr(t) +
  6493     Gear^.Tex := RenderStringTex(FormatA(trmsg[sidFuel], ansistring(inttostr(t))),
  6060               '%'), cWhiteColor, fntSmall)
  6494               cWhiteColor, fntSmall)
  6061     end;
  6495     end;
  6062     if Gear^.Message and (gmUp or gmDown) <> 0 then
  6496     if Gear^.Message and (gmUp or gmDown) <> 0 then
  6063         begin
  6497         begin
  6064         StopSoundChan(Gear^.SoundChannel);
  6498         if (Gear^.Tag <> 2) then
  6065         Gear^.SoundChannel:= -1;
  6499             begin
       
  6500             StopSoundChan(Gear^.SoundChannel);
       
  6501             Gear^.SoundChannel:= LoopSound(sndIceBeamIdle);
       
  6502             Gear^.Tag:= 2;
       
  6503             end;
  6066         if GameTicks mod 40 = 0 then dec(Gear^.Health)
  6504         if GameTicks mod 40 = 0 then dec(Gear^.Health)
  6067         end
  6505         end
  6068     else
  6506     else
  6069         begin
  6507         begin
  6070         if Gear^.SoundChannel = -1 then
  6508         if (Gear^.Tag <> 1) then
  6071             Gear^.SoundChannel := LoopSound(sndIceBeam);
  6509             begin
       
  6510             StopSoundChan(Gear^.SoundChannel);
       
  6511             Gear^.SoundChannel:= LoopSound(sndIceBeam);
       
  6512             Gear^.Tag:= 1;
       
  6513             end;
  6072         if GameTicks mod 10 = 0 then dec(Gear^.Health)
  6514         if GameTicks mod 10 = 0 then dec(Gear^.Health)
  6073         end
  6515         end
  6074 end;
  6516 end;
  6075 
  6517 
  6076 
  6518 
  6077 procedure updateTarget(Gear:PGear; newX, newY:HWFloat);
  6519 procedure updateTarget(Gear:PGear; newX, newY:HWFloat);
  6078 //    var
       
  6079 //    iter:PGear;
       
  6080 begin
  6520 begin
  6081   with Gear^ do
  6521   with Gear^ do
  6082   begin
  6522   begin
  6083     dX:= newX;
  6523     dX:= newX;
  6084     dY:= newY;
  6524     dY:= newY;
  6091 end;
  6531 end;
  6092 
  6532 
  6093 procedure doStepIceGun(Gear: PGear);
  6533 procedure doStepIceGun(Gear: PGear);
  6094 const iceWaitCollision = 0;
  6534 const iceWaitCollision = 0;
  6095 const iceCollideWithGround = 1;
  6535 const iceCollideWithGround = 1;
  6096 //const iceWaitNextTarget:Longint = 2;
       
  6097 //const iceCollideWithHog:Longint = 4;
       
  6098 const iceCollideWithWater = 5;
  6536 const iceCollideWithWater = 5;
  6099 //const waterFreezingTime:Longint = 500;
       
  6100 const groundFreezingTime = 1000;
  6537 const groundFreezingTime = 1000;
  6101 const iceRadius = 32;
  6538 const iceRadius = 32;
  6102 const iceHeight = 40;
  6539 const iceHeight = 40;
  6103 var
  6540 var
  6104     HHGear, iter: PGear;
  6541     HHGear, iter: PGear;
  6115         DeleteGear(Gear);
  6552         DeleteGear(Gear);
  6116         AfterAttack;
  6553         AfterAttack;
  6117         exit
  6554         exit
  6118         end;
  6555         end;
  6119     updateFuel(Gear);
  6556     updateFuel(Gear);
       
  6557     if (WorldEdge <> weBounce) then
       
  6558         if WorldWrap(Gear) and (WorldEdge = weWrap) and (Gear^.Target.X = NoPointX) then
       
  6559             // Use FlightTime to count number of times the gear has world-wrapped
       
  6560             inc(Gear^.FlightTime);
  6120 
  6561 
  6121     with Gear^ do
  6562     with Gear^ do
  6122         begin
  6563         begin
  6123         HedgehogChAngle(HHGear);
  6564         HedgehogChAngle(HHGear);
  6124         ndX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _4;
  6565         ndX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _4;
  6125         ndY:= -AngleCos(HHGear^.Angle) * _4;
  6566         ndY:= -AngleCos(HHGear^.Angle) * _4;
  6126         if (ndX <> dX) or (ndY <> dY) or
  6567         if (ndX <> dX) or (ndY <> dY) or (Gear^.Message and (gmUp or gmDown) <> 0) or
  6127            ((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and
  6568            (((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and
  6128              (Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0)) and
  6569              (Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0)) and
  6129              (not CheckCoordInWater(Target.X, Target.Y))) then
  6570              (not CheckCoordInWater(Target.X, Target.Y))) and (CheckGearNear(gtAirMine, int2hwFloat(Target.X),int2hwFloat(Target.Y), Gear^.Radius*3, Gear^.Radius*3) = nil) and
       
  6571              (not ((WorldEdge = weBounce) and ((Target.X > rightX) or (Target.X < leftX))))) then
  6130             begin
  6572             begin
  6131             updateTarget(Gear, ndX, ndY);
  6573             updateTarget(Gear, ndX, ndY);
  6132             Timer := iceWaitCollision;
  6574             Timer := iceWaitCollision;
       
  6575             FlightTime := 0;
  6133             end
  6576             end
  6134         else
  6577         // Extend ice beam, unless it is far outside he map boundaries
       
  6578         else if (not ((hwRound(X + dX) > max(LAND_WIDTH,4096)*2) or
       
  6579             (hwRound(X + dX) < -max(LAND_WIDTH,4096)*2) or
       
  6580             (hwRound(Y + dY) < -max(LAND_HEIGHT,4096)*2) or
       
  6581             (hwRound(Y + dY) > max(LAND_HEIGHT,4096)+512))) then
  6135             begin
  6582             begin
  6136             X:= X + dX;
  6583             X:= X + dX;
  6137             Y:= Y + dY;
  6584             Y:= Y + dY;
  6138             gX:= hwRound(X);
  6585             gX:= hwRound(X);
  6139             gY:= hwRound(Y);
  6586             gY:= hwRound(Y);
  6140             if Target.X = NoPointX then t:= hwRound(hwSqr(X-HHGear^.X)+hwSqr(Y-HHGear^.Y));
  6587             if Target.X = NoPointX then t:= hwRound(hwSqr(X-HHGear^.X)+hwSqr(Y-HHGear^.Y));
  6141 
  6588 
  6142             if Target.X <> NoPointX then
  6589             if Target.X <> NoPointX then
  6143                 begin
  6590                 begin
  6144                 CheckCollision(Gear);
  6591                 CheckCollision(Gear);
  6145                 if (State and gstCollision) <> 0 then
  6592                 if ((State and gstCollision) <> 0) or (CheckGearNear(gtAirMine, int2hwFloat(Target.X),int2hwFloat(Target.Y), Gear^.Radius*4, Gear^.Radius*4) <> nil) then
  6146                     begin
  6593                     begin
  6147                     if Timer = iceWaitCollision then
  6594                     if Timer = iceWaitCollision then
  6148                         begin
  6595                         begin
  6149                         Timer := iceCollideWithGround;
  6596                         Timer := iceCollideWithGround;
  6150                         Power := GameTicks;
  6597                         Power := GameTicks;
  6154                         ((Target.X and LAND_WIDTH_MASK  = 0) and
  6601                         ((Target.X and LAND_WIDTH_MASK  = 0) and
  6155                          (Target.Y and LAND_HEIGHT_MASK = 0) and
  6602                          (Target.Y and LAND_HEIGHT_MASK = 0) and
  6156                          (Land[Target.Y, Target.X] = lfIce) and
  6603                          (Land[Target.Y, Target.X] = lfIce) and
  6157                          ((Target.Y+iceHeight+5 > cWaterLine) or
  6604                          ((Target.Y+iceHeight+5 > cWaterLine) or
  6158                           ((WorldEdge = weSea) and
  6605                           ((WorldEdge = weSea) and
  6159                            ((Target.X+iceHeight+5 > LongInt(rightX)) or
  6606                            ((Target.X+iceHeight+5 > rightX) or
  6160                             (Target.X-iceHeight-5 < LongInt(leftX)))))
  6607                             (Target.X-iceHeight-5 < leftX))))
  6161                          ) then
  6608                          ) then
  6162                     begin
  6609                     begin
  6163                     if Timer = iceWaitCollision then
  6610                     if Timer = iceWaitCollision then
  6164                         begin
  6611                         begin
  6165                         Timer := iceCollideWithWater;
  6612                         Timer := iceCollideWithWater;
  6185                     // Freeze nearby mines/explosives/cases too
  6632                     // Freeze nearby mines/explosives/cases too
  6186                     iter := GearsList;
  6633                     iter := GearsList;
  6187                     while iter <> nil do
  6634                     while iter <> nil do
  6188                         begin
  6635                         begin
  6189                         if (iter^.State and gstFrozen = 0) and
  6636                         if (iter^.State and gstFrozen = 0) and
  6190                            ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine) or (iter^.Kind = gtSMine)) and
  6637                            ((iter^.Kind = gtExplosives) or (iter^.Kind = gtAirMine) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine) or (iter^.Kind = gtSMine)) and
  6191                            (abs(LongInt(iter^.X.Round) - target.x) + abs(LongInt(iter^.Y.Round) - target.y) + 2 < 2 * iceRadius)
  6638                            (abs(hwRound(iter^.X) - target.x) + abs(hwRound(iter^.Y) - target.y) + 2 < 2 * iceRadius)
  6192                            and (Distance(iter^.X - int2hwFloat(target.x), iter^.Y - int2hwFloat(target.y)) < int2hwFloat(iceRadius * 2)) then
  6639                            and (Distance(iter^.X - int2hwFloat(target.x), iter^.Y - int2hwFloat(target.y)) < int2hwFloat(iceRadius * 2)) then
  6193                             begin
  6640                             begin
  6194                             for t:= 0 to 5 do
  6641                             for t:= 0 to 5 do
  6195                                 begin
  6642                                 begin
  6196                                 vg:= AddVisualGear(hwRound(iter^.X)+random(4)-8, hwRound(iter^.Y)+random(8), vgtDust, 1);
  6643                                 vg:= AddVisualGear(hwRound(iter^.X)+random(4)-8, hwRound(iter^.Y)+random(8), vgtDust, 1);
  6229                                 begin
  6676                                 begin
  6230                                 DeleteCI(iter);
  6677                                 DeleteCI(iter);
  6231                                 iter^.State:= iter^.State or gstFrozen;
  6678                                 iter^.State:= iter^.State or gstFrozen;
  6232                                 AddCI(iter)
  6679                                 AddCI(iter)
  6233                                 end
  6680                                 end
       
  6681                             else if iter^.Kind = gtAirMine then
       
  6682                                 begin
       
  6683                                 iter^.Damage:= 0;
       
  6684                                 iter^.State:= iter^.State or gstFrozen;
       
  6685                                 if (hwRound(iter^.X) < RightX-16) and (hwRound(iter^.X) > LeftX+16) and 
       
  6686                                     (hwRound(iter^.Y) > topY+16) and (hwRound(iter^.Y) < LAND_HEIGHT-16) then
       
  6687                                     begin
       
  6688                                     AddCI(iter);
       
  6689                                     iter^.X:= int2hwFloat(min(RightX-16,max(hwRound(iter^.X), LeftX+16)));
       
  6690                                     iter^.Y:= int2hwFloat(min(LAND_HEIGHT-16,max(hwRound(iter^.Y),TopY+16)));
       
  6691                                     ForcePlaceOnLand(hwRound(iter^.X)-16, hwRound(iter^.Y)-16, sprFrozenAirMine, 0, lfIce, $FFFFFFFF, false, false, false);    
       
  6692                                     iter^.State:= iter^.State or gstInvisible
       
  6693                                     end
       
  6694                                 else
       
  6695                                     begin
       
  6696                                     updateTarget(Gear, ndX, ndY);
       
  6697                                     FlightTime := 0;
       
  6698                                     Timer := iceWaitCollision;
       
  6699                                     Power := GameTicks;
       
  6700                                     iter^.State:= iter^.State and (not gstNoGravity)
       
  6701                                     end
       
  6702                                 end
  6234                             else // gtExplosives
  6703                             else // gtExplosives
  6235                                 begin
  6704                                 begin
  6236                                 iter^.State:= iter^.State or gstFrozen;
  6705                                 iter^.State:= iter^.State or gstFrozen;
  6237                                 iter^.Health:= iter^.Health + cBarrelHealth
  6706                                 iter^.Health:= iter^.Health + cBarrelHealth
  6238                                 end
  6707                                 end
  6239                             end;
  6708                             end;
  6240                         iter:= iter^.NextGear
  6709                         iter:= iter^.NextGear
  6241                         end;
  6710                         end;
  6242 
  6711 
  6243                     // FillRoundInLandWithIce(Target.X, Target.Y, iceRadius);
       
  6244                     SetAllHHToActive;
  6712                     SetAllHHToActive;
  6245                     Timer := iceWaitCollision;
  6713                     Timer := iceWaitCollision;
       
  6714                     Power:= GameTicks
  6246                     end;
  6715                     end;
  6247 
  6716 
  6248                 if (Timer = iceCollideWithWater) and ((GameTicks - Power) > groundFreezingTime div 2) then
  6717                 if (Timer = iceCollideWithWater) and ((GameTicks - Power) > groundFreezingTime div 2) then
  6249                     begin
  6718                     begin
  6250                     PlaySound(sndHogFreeze);
  6719                     PlaySound(sndHogFreeze);
  6251                     if CheckCoordInWater(Target.X, Target.Y) then
  6720                     if CheckCoordInWater(Target.X, Target.Y) then
  6252                         DrawIceBreak(Target.X, Target.Y, iceRadius, iceHeight)
  6721                         DrawIceBreak(Target.X, Target.Y, iceRadius, iceHeight)
  6253                     else if Target.Y+iceHeight+5 > cWaterLine then
  6722                     else if Target.Y+iceHeight+5 > cWaterLine then
  6254                         DrawIceBreak(Target.X, Target.Y+iceHeight+5, iceRadius, iceHeight)
  6723                         DrawIceBreak(Target.X, Target.Y+iceHeight+5, iceRadius, iceHeight)
  6255                     else if Target.X+iceHeight+5 > LongInt(rightX) then
  6724                     else if Target.X+iceHeight+5 > rightX then
  6256                         DrawIceBreak(Target.X+iceHeight+5, Target.Y, iceRadius, iceHeight)
  6725                         DrawIceBreak(Target.X+iceHeight+5, Target.Y, iceRadius, iceHeight)
  6257                     else
  6726                     else
  6258                         DrawIceBreak(Target.X-iceHeight-5, Target.Y, iceRadius, iceHeight);
  6727                         DrawIceBreak(Target.X-iceHeight-5, Target.Y, iceRadius, iceHeight);
  6259                     SetAllHHToActive;
  6728                     SetAllHHToActive;
  6260                     Timer := iceWaitCollision;
  6729                     Timer := iceWaitCollision;
  6261                     end;
  6730                     end;
  6262 (*
       
  6263  Any ideas for something that would look good here?
       
  6264                 if (Target.X <> NoPointX) and ((Timer = iceCollideWithGround) or (Timer = iceCollideWithWater)) and (GameTicks mod max((groundFreezingTime-((GameTicks - Power)*2)),2) = 0) then //and CheckLandValue(Target.X, Target.Y, lfIce) then
       
  6265                     begin
       
  6266                         vg:= AddVisualGear(Target.X+random(20)-10, Target.Y+random(40)-10, vgtDust, 1);
       
  6267                         if vg <> nil then
       
  6268                             begin
       
  6269                             i:= random(100) + 155;
       
  6270                             vg^.Tint:= IceColor or $FF;
       
  6271                             vg^.Angle:= random(360);
       
  6272                             vg^.dx:= 0.001 * random(80);
       
  6273                             vg^.dy:= 0.001 * random(80)
       
  6274                             end
       
  6275                     end;
       
  6276 *)
       
  6277 
       
  6278 // freeze nearby hogs
  6731 // freeze nearby hogs
  6279                 hogs := GearsNear(int2hwFloat(Target.X), int2hwFloat(Target.Y), gtHedgehog, Gear^.Radius*2);
  6732                 hogs := GearsNear(int2hwFloat(Target.X), int2hwFloat(Target.Y), gtHedgehog, Gear^.Radius*2);
  6280                 if hogs.size > 0 then
  6733                 if hogs.size > 0 then
  6281                     for i:= 0 to hogs.size - 1 do
  6734                     for i:= 0 to hogs.size - 1 do
  6282                         if hogs.ar^[i] <> HHGear then
  6735                         if hogs.ar^[i] <> HHGear then
  6299                 begin
  6752                 begin
  6300                 Target.X:= gX;
  6753                 Target.X:= gX;
  6301                 Target.Y:= gY;
  6754                 Target.Y:= gY;
  6302                 X:= HHGear^.X;
  6755                 X:= HHGear^.X;
  6303                 Y:= HHGear^.Y
  6756                 Y:= HHGear^.Y
  6304                 end;
  6757                 end
  6305             if (gX > max(LAND_WIDTH,4096)*2) or
  6758             else if (WorldEdge = weBounce) and ((gX > rightX) or (gX < leftX)) then
  6306                     (gX < -max(LAND_WIDTH,4096)) or
  6759                 begin
  6307                     (gY < -max(LAND_HEIGHT,4096)) or
       
  6308                     (gY > max(LAND_HEIGHT,4096)+512) then
       
  6309                 begin
       
  6310                 //X:= HHGear^.X;
       
  6311                 //Y:= HHGear^.Y
       
  6312                 Target.X:= gX;
  6760                 Target.X:= gX;
  6313                 Target.Y:= gY;
  6761                 Target.Y:= gY;
       
  6762                 X:= HHGear^.X;
       
  6763                 Y:= HHGear^.Y
  6314                 end
  6764                 end
       
  6765             else
       
  6766                 begin
       
  6767                 iter:= CheckGearNear(Gear, gtAirMine, Gear^.Radius*2, Gear^.Radius*2);
       
  6768                 if (iter <> nil) and (iter^.State <> gstFrozen) then
       
  6769                     begin
       
  6770                     Target.X:= gX;
       
  6771                     Target.Y:= gY;
       
  6772                     X:= HHGear^.X;
       
  6773                     Y:= HHGear^.Y
       
  6774                     end 
       
  6775                 end;
  6315         end
  6776         end
  6316     end;
  6777     end;
  6317 end;
  6778 end;
  6318 
  6779 
  6319 procedure doStepAddAmmo(Gear: PGear);
  6780 procedure doStepAddAmmo(Gear: PGear);
  6352         exit
  6813         exit
  6353         end;
  6814         end;
  6354 if (Gear^.State and gstTmpFlag <> 0) or (GameTicks and $7 = 0) then
  6815 if (Gear^.State and gstTmpFlag <> 0) or (GameTicks and $7 = 0) then
  6355     begin
  6816     begin
  6356     doStepFallingGear(Gear);
  6817     doStepFallingGear(Gear);
  6357     if (Gear^.Tag = 1) and (GameTicks and $FF = 0) and (hwRound(Gear^.X) < LongInt(leftX)) or (hwRound(Gear^.X) > LongInt(rightX)) or (hwRound(Gear^.Y) < LongInt(topY)) then
  6818     if (Gear^.Tag = 1) and (GameTicks and $FF = 0) and (hwRound(Gear^.X) < leftX) or (hwRound(Gear^.X) > rightX) or (hwRound(Gear^.Y) < topY) then
  6358         begin
  6819         begin
  6359         Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
  6820         Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
  6360         Gear^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
  6821         Gear^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
  6361         Gear^.dX:= _90-(GetRandomf*_360);
  6822         Gear^.dX:= _90-(GetRandomf*_360);
  6362         Gear^.dY:= _90-(GetRandomf*_360)
  6823         Gear^.dY:= _90-(GetRandomf*_360)
  6363         end;
  6824         end;
  6364     end
  6825     end
  6365 end;
  6826 end;
  6366 (*
  6827 
       
  6828 // TODO: Finish creeper implementation
  6367 procedure doStepCreeper(Gear: PGear);
  6829 procedure doStepCreeper(Gear: PGear);
  6368 var hogs: PGearArrayS;
  6830 var i,t,targDist,tmpDist: LongWord;
  6369     HHGear: PGear;
  6831     targ, tmpG: PGear;
  6370     tdX: hwFloat;
  6832     tX, tY: hwFloat;
  6371     dir: LongInt;
  6833     vg: PVisualGear;
  6372 begin
  6834 begin
  6373 doStepFallingGear(Gear);
  6835     targ:= nil;
  6374 if Gear^.Timer > 0 then dec(Gear^.Timer);
  6836     doStepFallingGear(Gear);
  6375 // creeper sleep phase
  6837     if (Gear^.State and gstFrozen) <> 0 then
  6376 if (Gear^.Hedgehog = nil) and (Gear^.Timer > 0) then exit;
  6838         begin
  6377 
  6839         if Gear^.Damage > 0 then
  6378 if Gear^.Hedgehog <> nil then HHGear:= Gear^.Hedgehog^.Gear
  6840             begin
  6379 else HHGear:= nil;
  6841             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  6380 
  6842             DeleteGear(Gear)
  6381 // creeper boom phase
  6843             end;
  6382 if (Gear^.State and gstTmpFlag <> 0) then
       
  6383     begin
       
  6384     if (Gear^.Timer = 0) then
       
  6385         begin
       
  6386         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 300, CurrentHedgehog, EXPLAutoSound);
       
  6387         DeleteGear(Gear)
       
  6388         end;
       
  6389     // ssssss he essssscaped
       
  6390     if (Gear^.Timer > 250) and ((HHGear = nil) or
       
  6391             (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) >  180) and
       
  6392             (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > _180))) then
       
  6393         begin
       
  6394         Gear^.State:= Gear^.State and (not gstTmpFlag);
       
  6395         Gear^.Timer:= 0
       
  6396         end;
       
  6397     exit
       
  6398     end;
       
  6399 
       
  6400 // Search out a new target, as target seek time has expired, target is dead, target is out of range, or we did not have a target
       
  6401 if (HHGear = nil) or (Gear^.Timer = 0) or
       
  6402    (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) >  Gear^.Angle) and
       
  6403         (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle)))
       
  6404     then
       
  6405     begin
       
  6406     hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Angle);
       
  6407     if hogs.size > 1 then
       
  6408         Gear^.Hedgehog:= hogs.ar^[GetRandom(hogs.size)]^.Hedgehog
       
  6409     else if hogs.size = 1 then Gear^.Hedgehog:= hogs.ar^[0]^.Hedgehog
       
  6410     else Gear^.Hedgehog:= nil;
       
  6411     if Gear^.Hedgehog <> nil then Gear^.Timer:= 5000;
       
  6412     exit
       
  6413     end;
       
  6414 
       
  6415 // we have a target. move the creeper.
       
  6416 if HHGear <> nil then
       
  6417     begin
       
  6418     // GOTCHA
       
  6419     if ((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) <  50) and
       
  6420          (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) < _50) then
       
  6421         begin
       
  6422         // hisssssssssss
       
  6423         Gear^.State:= Gear^.State or gstTmpFlag;
       
  6424         Gear^.Timer:= 1500;
       
  6425         exit
  6844         exit
  6426         end;
  6845         end;
  6427     if (Gear^.State and gstMoving <> 0) then
  6846     if (TurnTimeLeft = 0) or (Gear^.Angle = 0) or (Gear^.Hedgehog = nil) or (Gear^.Hedgehog^.Gear = nil) then
  6428         begin
  6847         begin
  6429         Gear^.dY:= _0;
  6848         Gear^.Hedgehog:= nil;
  6430         Gear^.dX:= _0;
  6849         targ:= nil;
  6431         end
  6850         end
  6432     else if (GameTicks and $FF = 0) then
  6851     else if Gear^.Hedgehog <> nil then
  6433         begin
  6852         targ:= Gear^.Hedgehog^.Gear;
  6434         tdX:= HHGear^.X-Gear^.X;
  6853     if (targ <> nil) and ((GameTicks and $3F) = 0) and (TestCollisionYKick(Gear, 1) <> 0) then
  6435         dir:= hwSign(tdX);
  6854         begin
  6436         if TestCollisionX(Gear, dir) = 0 then
  6855         vg:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeWhite);
  6437             Gear^.X:= Gear^.X + signAs(_1,tdX);
  6856         if vg <> nil then vg^.Tint:= $FF0000FF;
  6438         if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) <> 0 then
  6857         if (Gear^.X < targ^.X) then // need to add collision checks to avoid walking off edges or getting too close to obstacles where jumping is needed
  6439             begin
  6858             if (WorldEdge = weWrap) and ((targ^.X - Gear^.X) > ((Gear^.X - int2hwFloat(LeftX)) + (int2hwFloat(RightX) - targ^.X))) then
  6440             Gear^.dX:= SignAs(_0_15, tdX);
  6859                  Gear^.dX:= -cLittle
  6441             Gear^.dY:= -_0_3;
  6860             else
  6442             Gear^.State:= Gear^.State or gstMoving
  6861                  Gear^.dX:= cLittle
       
  6862         else if (Gear^.X > targ^.X) then
       
  6863             if (WorldEdge = weWrap) and ((Gear^.X - targ^.X) > ((targ^.X - int2hwFloat(LeftX)) + (int2hwFloat(RightX) - Gear^.X))) then
       
  6864                 Gear^.dX:= cLittle
       
  6865             else
       
  6866                 Gear^.dX:= -cLittle;
       
  6867         if (GetRandom(30) = 0) then
       
  6868             begin
       
  6869             Gear^.dY := -_0_15;
       
  6870             Gear^.dX:= SignAs(_0_15, Gear^.dX);
       
  6871             end;
       
  6872         MakeHedgehogsStep(Gear);
       
  6873         end;
       
  6874     if (TurnTimeLeft = 0) and ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) > _0_02.QWordValue) then
       
  6875         AllInactive := false;
       
  6876 
       
  6877     if targ <> nil then
       
  6878         begin
       
  6879         tX:=Gear^.X-targ^.X;
       
  6880         tY:=Gear^.Y-targ^.Y;
       
  6881         // allow escaping - should maybe flag this too
       
  6882         if (GameTicks > Gear^.FlightTime+10000) or 
       
  6883             ((tX.Round+tY.Round > Gear^.Angle*6) and
       
  6884             (hwRound(hwSqr(tX) + hwSqr(tY)) > sqr(Gear^.Angle*6))) then
       
  6885             targ:= nil
       
  6886         end;
       
  6887 
       
  6888     // If in ready timer, or after turn, or in first 5 seconds of turn (really a window due to extra time utility)
       
  6889     // or mine is inactive due to lack of gsttmpflag or hunting is disabled due to seek radius of 0
       
  6890     // then we aren't hunting
       
  6891     if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or 
       
  6892         ((TurnTimeLeft < cHedgehogTurnTime) and (cHedgehogTurnTime-TurnTimeLeft < 5000)) or
       
  6893         (Gear^.State and gsttmpFlag = 0) or
       
  6894         (Gear^.Angle = 0) then
       
  6895         gear^.State:= gear^.State and (not gstChooseTarget)
       
  6896     else if
       
  6897     // todo, allow not finding new target, set timeout on target retention
       
  6898         (Gear^.State and gstAttacking = 0) and
       
  6899         ((GameTicks and $FF) = 17) and
       
  6900         (GameTicks > Gear^.FlightTime) then // recheck hunted hog
       
  6901         begin
       
  6902         gear^.State:= gear^.State or gstChooseTarget;
       
  6903         if targ <> nil then
       
  6904              targDist:= Distance(Gear^.X-targ^.X,Gear^.Y-targ^.Y).Round
       
  6905         else targDist:= 0;
       
  6906         for t:= 0 to Pred(TeamsCount) do
       
  6907             with TeamsArray[t]^ do
       
  6908                 for i:= 0 to cMaxHHIndex do
       
  6909                     if Hedgehogs[i].Gear <> nil then
       
  6910                         begin
       
  6911                         tmpG:= Hedgehogs[i].Gear;
       
  6912                         tX:=Gear^.X-tmpG^.X;
       
  6913                         tY:=Gear^.Y-tmpG^.Y;
       
  6914                         if (Gear^.Angle = $FFFFFFFF) or
       
  6915                             ((tX.Round+tY.Round < Gear^.Angle) and
       
  6916                             (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Angle))) then
       
  6917                             begin
       
  6918                             if targ <> nil then tmpDist:= Distance(tX,tY).Round;
       
  6919                             if (targ = nil) or (tmpDist < targDist) then
       
  6920                                 begin
       
  6921                                 if targ = nil then targDist:= Distance(tX,tY).Round
       
  6922                                 else targDist:= tmpDist;
       
  6923                                 Gear^.Hedgehog:= @Hedgehogs[i];
       
  6924                                 targ:= tmpG;
       
  6925                                 end
       
  6926                             end
       
  6927                         end;
       
  6928         if targ <> nil then Gear^.FlightTime:= GameTicks + 5000
       
  6929         end;
       
  6930 
       
  6931     if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
       
  6932         begin
       
  6933         if ((Gear^.State and gstAttacking) = 0) then
       
  6934             begin
       
  6935             if ((GameTicks and $1F) = 0) then
       
  6936                 begin
       
  6937                 if targ <> nil then
       
  6938                     begin
       
  6939                     tX:=Gear^.X-targ^.X;
       
  6940                     tY:=Gear^.Y-targ^.Y;
       
  6941                     if (tX.Round+tY.Round < Gear^.Boom) and
       
  6942                        (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Boom)) then
       
  6943                     Gear^.State := Gear^.State or gstAttacking
       
  6944                     end
       
  6945                 else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Boom, Gear^.Boom) <> nil) then
       
  6946                     Gear^.State := Gear^.State or gstAttacking
       
  6947                 end
  6443             end
  6948             end
  6444         end;
  6949         else // gstAttacking <> 0
  6445     end;
  6950             begin
  6446 end;
  6951             AllInactive := false;
  6447 *)
  6952             if (Gear^.Timer and $1FF) = 0 then
       
  6953                 PlaySound(sndVaporize);
       
  6954             if Gear^.Timer = 0 then
       
  6955                 begin
       
  6956                 // recheck
       
  6957                 if targ <> nil then
       
  6958                     begin
       
  6959                     tX:=Gear^.X-targ^.X;
       
  6960                     tY:=Gear^.Y-targ^.Y;
       
  6961                     if (tX.Round+tY.Round < Gear^.Boom) and
       
  6962                        (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Boom)) then
       
  6963                         begin
       
  6964                         Gear^.Hedgehog:= CurrentHedgehog;
       
  6965                         tmpG:= FollowGear;
       
  6966                         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
       
  6967                         FollowGear:= tmpG;
       
  6968                         DeleteGear(Gear);
       
  6969                         exit
       
  6970                         end
       
  6971                     end
       
  6972                 else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Boom, Gear^.Boom) <> nil) then
       
  6973                     begin
       
  6974                     Gear^.Hedgehog:= CurrentHedgehog;
       
  6975                     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
       
  6976                     DeleteGear(Gear);
       
  6977                     exit
       
  6978                     end;
       
  6979                 Gear^.State:= Gear^.State and (not gstAttacking);
       
  6980                 Gear^.Timer:= Gear^.WDTimer
       
  6981                 end;
       
  6982             if Gear^.Timer > 0 then
       
  6983                 dec(Gear^.Timer);
       
  6984             end
       
  6985         end
       
  6986     else // gsttmpFlag = 0
       
  6987         if (TurnTimeLeft = 0)
       
  6988         or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime))
       
  6989         or (CurrentHedgehog^.Gear = nil) then
       
  6990         begin
       
  6991         Gear^.FlightTime:= GameTicks;
       
  6992         Gear^.State := Gear^.State or gsttmpFlag
       
  6993         end
       
  6994 end;
       
  6995 
  6448 ////////////////////////////////////////////////////////////////////////////////
  6996 ////////////////////////////////////////////////////////////////////////////////
  6449 procedure doStepKnife(Gear: PGear);
  6997 procedure doStepKnife(Gear: PGear);
  6450 //var ox, oy: LongInt;
       
  6451 //    la: hwFloat;
       
  6452 var   a: real;
  6998 var   a: real;
  6453 begin
  6999 begin
  6454     // Gear is shrunk so it can actually escape the hog without carving into the terrain
  7000     // Gear is shrunk so it can actually escape the hog without carving into the terrain
  6455     if (Gear^.Radius = 4) and (Gear^.CollisionMask = $FFFF) then Gear^.Radius:= 7;
  7001     if (Gear^.Radius = 4) and (Gear^.CollisionMask = lfAll) then Gear^.Radius:= 7;
  6456     if Gear^.Damage > 100 then Gear^.CollisionMask:= 0
  7002     if Gear^.Damage > 100 then Gear^.CollisionMask:= 0
  6457     else if Gear^.Damage > 30 then
  7003     else if Gear^.Damage > 30 then
  6458         if GetRandom(max(4,18-Gear^.Damage div 10)) < 3 then Gear^.CollisionMask:= 0;
  7004         if GetRandom(max(4,18-Gear^.Damage div 10)) < 3 then Gear^.CollisionMask:= 0;
  6459     Gear^.Damage:= 0;
  7005     Gear^.Damage:= 0;
  6460     if Gear^.Timer > 0 then dec(Gear^.Timer);
  7006     if Gear^.Timer > 0 then dec(Gear^.Timer);
  6470         CalcRotationDirAngle(Gear);
  7016         CalcRotationDirAngle(Gear);
  6471         Gear^.DirAngle:= a+(Gear^.DirAngle-a)*2*hwSign(Gear^.dX) // double rotation
  7017         Gear^.DirAngle:= a+(Gear^.DirAngle-a)*2*hwSign(Gear^.dX) // double rotation
  6472         end
  7018         end
  6473     else if (Gear^.CollisionIndex = -1) and (Gear^.Timer = 0) then
  7019     else if (Gear^.CollisionIndex = -1) and (Gear^.Timer = 0) then
  6474         begin
  7020         begin
  6475         (*ox:= 0; oy:= 0;
       
  6476         if TestCollisionYwithGear(Gear, -1) <> 0 then oy:= -1;
       
  6477         if TestCollisionXwithGear(Gear, 1)  <> 0 then ox:=  1;
       
  6478         if TestCollisionXwithGear(Gear, -1) <> 0 then ox:= -1;
       
  6479         if TestCollisionYwithGear(Gear, 1)  <> 0 then oy:=  1;
       
  6480 
       
  6481         la:= _10000;
       
  6482         if (ox <> 0) or (oy <> 0) then
       
  6483             la:= CalcSlopeNearGear(Gear, ox, oy);
       
  6484         if la = _10000 then
       
  6485             begin
       
  6486             // debug for when we couldn't get an angle
       
  6487             //AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeWhite);
       
  6488 *)
       
  6489         if Gear^.Health > 0 then
  7021         if Gear^.Health > 0 then
  6490             PlaySound(Gear^.ImpactSound);
  7022             PlaySound(Gear^.ImpactSound);
  6491 
  7023 
  6492             Gear^.DirAngle:= DxDy2Angle(Gear^.dX, Gear^.dY) + (random(30)-15);
  7024             Gear^.DirAngle:= DxDy2Angle(Gear^.dX, Gear^.dY) + (random(30)-15);
  6493             if (Gear^.dX.isNegative and Gear^.dY.isNegative) or
  7025             if (Gear^.dX.isNegative and Gear^.dY.isNegative) or
  6494              ((not Gear^.dX.isNegative) and (not Gear^.dY.isNegative)) then Gear^.DirAngle:= Gear^.DirAngle-90;
  7026              ((not Gear^.dX.isNegative) and (not Gear^.dY.isNegative)) then Gear^.DirAngle:= Gear^.DirAngle-90;
  6495  //           end
       
  6496  //       else Gear^.DirAngle:= hwFloat2Float(la)*90; // sheepluva's comment claims 45deg = 0.5 - yet orientation doesn't seem consistent?
       
  6497  //       AddFileLog('la: '+floattostr(la)+' DirAngle: '+inttostr(round(Gear^.DirAngle)));
       
  6498         Gear^.dX:= _0;
  7027         Gear^.dX:= _0;
  6499         Gear^.dY:= _0;
  7028         Gear^.dY:= _0;
  6500         Gear^.State:= Gear^.State and (not gstMoving) or gstCollision;
  7029         Gear^.State:= Gear^.State and (not gstMoving) or gstCollision;
  6501         Gear^.Radius:= 16;
  7030         Gear^.Radius:= 16;
  6502         if Gear^.Health > 0 then AmmoShove(Gear, Gear^.Health, 0);
  7031         if Gear^.Health > 0 then AmmoShove(Gear, Gear^.Health, 0);
  6512         and (TestCollisionYwithGear(Gear, 1) = 0) then Gear^.State:= Gear^.State and (not gstCollision) or gstMoving;
  7041         and (TestCollisionYwithGear(Gear, 1) = 0) then Gear^.State:= Gear^.State and (not gstCollision) or gstMoving;
  6513         end
  7042         end
  6514 end;
  7043 end;
  6515 
  7044 
  6516 ////////////////////////////////////////////////////////////////////////////////
  7045 ////////////////////////////////////////////////////////////////////////////////
  6517 procedure doStepDuck(Gear: PGear);
       
  6518 begin
       
  6519     // Mirror duck on bounce world edge, even turn around later
       
  6520     if WorldWrap(Gear) and (WorldEdge = weBounce) then
       
  6521         begin
       
  6522         Gear^.Tag:= Gear^.Tag * -1;
       
  6523         if Gear^.Pos = 2 then
       
  6524             Gear^.Pos:= 1
       
  6525         else if Gear^.Pos = 1 then
       
  6526             Gear^.Pos:= 2
       
  6527         else if Gear^.Pos = 5 then
       
  6528             Gear^.Pos:= 6
       
  6529         else if Gear^.Pos = 5 then
       
  6530             Gear^.Pos:= 5;
       
  6531         end;
       
  6532 
       
  6533     AllInactive := false;
       
  6534 
       
  6535     // Duck falls (Pos = 0)
       
  6536     if Gear^.Pos = 0 then
       
  6537         doStepFallingGear(Gear);
       
  6538 
       
  6539     (* Check if duck is near water surface
       
  6540            (Karma is distance from water) *)
       
  6541     if (Gear^.Pos <> 1) and (Gear^.Pos <> 2) and (cWaterLine <= hwRound(Gear^.Y) + Gear^.Karma) then
       
  6542         begin
       
  6543         if cWaterLine = hwRound(Gear^.Y) + Gear^.Karma then
       
  6544             begin
       
  6545             // Let's make that duck swim!
       
  6546             // Does the duck come FROM the Sea edge? (left or right)
       
  6547             if (((Gear^.Pos = 3) or (Gear^.Pos = 7)) and (cWindSpeed > _0)) or (((Gear^.Pos = 4) or (Gear^.Pos = 8)) and (cWindSpeed < _0)) then
       
  6548                 begin
       
  6549                 PlaySound(sndDuckWater);
       
  6550                 Gear^.DirAngle:= 0;
       
  6551                 Gear^.Pos:= 1;
       
  6552                 Gear^.dY:= _0;
       
  6553                 end;
       
  6554 
       
  6555             // Duck comes either falling (usual case) or was rising from below
       
  6556             if (Gear^.Pos = 0) or (Gear^.Pos = 5) or (Gear^.Pos = 6) then
       
  6557                 begin
       
  6558                 PlaySound(sndDroplet2);
       
  6559                 if Gear^.dY > _0_4 then
       
  6560                     PlaySound(sndDuckWater);
       
  6561                 Gear^.Pos:= 1;
       
  6562                 Gear^.dY:= _0;
       
  6563                 end;
       
  6564             end
       
  6565         else if Gear^.Pos = 0 then
       
  6566             Gear^.Pos:= 5;
       
  6567         end;
       
  6568 
       
  6569     // Manual speed handling when duck is on water
       
  6570     if Gear^.Pos <> 0 then
       
  6571         begin
       
  6572         Gear^.X:= Gear^.X + Gear^.dX;
       
  6573         Gear^.Y:= Gear^.Y + Gear^.dY;
       
  6574         end;
       
  6575 
       
  6576     // Handle speed
       
  6577     // 1-4: On water: Let's swim!
       
  6578     if Gear^.Pos = 1 then
       
  6579         // On water (normal)
       
  6580         Gear^.dX:= cWindSpeed * Gear^.Damage
       
  6581     else if Gear^.Pos = 2 then
       
  6582         // On water, mirrored (after bounce edge bounce)
       
  6583         Gear^.dX:= -cWindSpeed * Gear^.Damage
       
  6584     else if Gear^.Pos = 3 then
       
  6585         // On left Sea edge
       
  6586         Gear^.dY:= cWindSpeed * Gear^.Damage
       
  6587     else if Gear^.Pos = 4 then
       
  6588         // On right Sea edge
       
  6589         Gear^.dY:= -cWindSpeed * Gear^.Damage
       
  6590     // 5-8: Underwater: Slowly rise to the surface and slightly follow wind
       
  6591     else if Gear^.Pos = 5 then
       
  6592         // Underwater (normal)
       
  6593         begin
       
  6594         Gear^.dX:= (cWindSpeed / 4) * Gear^.Damage;
       
  6595         Gear^.dY:= -_0_07;
       
  6596         end
       
  6597     else if Gear^.Pos = 6 then
       
  6598         // Underwater, mirrored duck (after bounce edge bounce)
       
  6599         begin
       
  6600         Gear^.dX:= -(cWindSpeed / 4) * Gear^.Damage;
       
  6601         Gear^.dY:= -_0_07;
       
  6602         end
       
  6603     else if Gear^.Pos = 7 then
       
  6604         // Inside left Sea edge
       
  6605         begin
       
  6606         Gear^.dX:= _0_07;
       
  6607         Gear^.dY:= (cWindSpeed / 4) * Gear^.Damage;
       
  6608         end
       
  6609     else if Gear^.Pos = 8 then
       
  6610         // Inside right Sea edge
       
  6611         begin
       
  6612         Gear^.dX:= -_0_07;
       
  6613         Gear^.dY:= -(cWindSpeed / 4) * Gear^.Damage;
       
  6614         end;
       
  6615  
       
  6616     
       
  6617     // Rotate duck and change direction when reaching Sea world edge (Pos 3 or 4)
       
  6618     if (WorldEdge = weSea) and (Gear^.Pos <> 3) and (Gear^.Pos <> 4) then
       
  6619         // Swimming TOWARDS left edge
       
  6620         if (LeftX >= hwRound(Gear^.X) - Gear^.Karma) and ((cWindSpeed < _0) or ((Gear^.Pos = 0) or (Gear^.Pos = 7))) then
       
  6621             begin
       
  6622             // Turn duck when reaching edge the first time
       
  6623             if (Gear^.Pos <> 3) and (Gear^.Pos <> 7) then
       
  6624                 begin
       
  6625                 if Gear^.Tag = 1 then
       
  6626                     Gear^.DirAngle:= 90
       
  6627                 else
       
  6628                     Gear^.DirAngle:= 270;
       
  6629                 end;
       
  6630 
       
  6631             // Reaching the edge surface
       
  6632             if (LeftX = hwRound(Gear^.X) - Gear^.Karma) and (Gear^.Pos <> 3) then
       
  6633                 // We are coming from the horizontal side
       
  6634                 begin
       
  6635                 PlaySound(sndDuckWater);
       
  6636                 Gear^.dX:= _0;
       
  6637                 Gear^.Pos:= 3;
       
  6638                 end
       
  6639             else 
       
  6640                 // We are coming from inside the Sea, go into “surfacing” mode
       
  6641                 Gear^.Pos:= 7;
       
  6642 
       
  6643             end
       
  6644 
       
  6645         // Swimming TOWARDS right edge (similar to left edge)
       
  6646         else if (RightX <= hwRound(Gear^.X) + Gear^.Karma) and ((cWindSpeed > _0) or ((Gear^.Pos = 0) or (Gear^.Pos = 8))) then
       
  6647             begin
       
  6648             if (Gear^.Pos <> 4) and (Gear^.Pos <> 8) then
       
  6649                 begin
       
  6650                 if Gear^.Tag = 1 then
       
  6651                     Gear^.DirAngle:= 270
       
  6652                 else
       
  6653                     Gear^.DirAngle:= 90;
       
  6654                 end;
       
  6655 
       
  6656             if (RightX = hwRound(Gear^.X) + Gear^.Karma) and (Gear^.Pos <> 4) then
       
  6657                 begin
       
  6658                 PlaySound(sndDuckWater);
       
  6659                 Gear^.dX:= _0;
       
  6660                 Gear^.Pos:= 4;
       
  6661                 end
       
  6662             else 
       
  6663                 Gear^.Pos:= 8;
       
  6664 
       
  6665             end;
       
  6666 
       
  6667 
       
  6668     if Gear^.Pos <> 0 then
       
  6669         // Manual collision check required because we don't use onStepFallingGear in this case
       
  6670         CheckCollision(Gear);
       
  6671     if (Gear^.Timer = 0) or ((Gear^.State and gstCollision) <> 0) then
       
  6672         // Explode duck
       
  6673         begin
       
  6674         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
       
  6675         PlaySound(sndDuckDie);
       
  6676         DeleteGear(Gear);
       
  6677         exit;
       
  6678         end;
       
  6679 
       
  6680     // Update timer stuff
       
  6681     if Gear^.Timer < 6000 then
       
  6682         Gear^.RenderTimer:= true
       
  6683     else
       
  6684         Gear^.RenderTimer:= false;
       
  6685 
       
  6686     dec(Gear^.Timer);
       
  6687 end;
       
  6688 
       
  6689 ////////////////////////////////////////////////////////////////////////////////
       
  6690 procedure doStepMinigunWork(Gear: PGear);
  7046 procedure doStepMinigunWork(Gear: PGear);
  6691 var HHGear: PGear;
  7047 var HHGear: PGear;
  6692     bullet: PGear;
  7048     bullet: PGear;
  6693     rx, ry: hwFloat;
  7049     rx, ry: hwFloat;
  6694     gX, gY: LongInt;
  7050     gX, gY: LongInt;
  6713         gY := hwRound(Gear^.Y) + GetLaunchY(amMinigun, HHGear^.Angle);
  7069         gY := hwRound(Gear^.Y) + GetLaunchY(amMinigun, HHGear^.Angle);
  6714         rx := rndSign(getRandomf * _0_2);
  7070         rx := rndSign(getRandomf * _0_2);
  6715         ry := rndSign(getRandomf * _0_2);
  7071         ry := rndSign(getRandomf * _0_2);
  6716 
  7072 
  6717         bullet:= AddGear(gx, gy, gtMinigunBullet, 0, SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx, AngleCos(HHGear^.Angle) * ( - _0_8) + ry, 0);
  7073         bullet:= AddGear(gx, gy, gtMinigunBullet, 0, SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx, AngleCos(HHGear^.Angle) * ( - _0_8) + ry, 0);
  6718         bullet^.CollisionMask:= lfNotCurrentMask;
  7074         bullet^.CollisionMask:= lfNotCurHogCrate;
  6719         bullet^.WDTimer := Gear^.WDTimer;
  7075         bullet^.WDTimer := Gear^.WDTimer;
  6720         Inc(Gear^.WDTimer);
  7076         Inc(Gear^.WDTimer);
  6721 
  7077 
  6722         CreateShellForGear(Gear, Gear^.Tag and 1);
  7078         CreateShellForGear(Gear, Gear^.Tag and 1);
  6723     end;
  7079     end;
  6767     Gear^.Y := Gear^.Y + Gear^.dY * 2;
  7123     Gear^.Y := Gear^.Y + Gear^.dY * 2;
  6768     Gear^.FlightTime := 0;
  7124     Gear^.FlightTime := 0;
  6769     Gear^.doStep := @doStepBulletWork
  7125     Gear^.doStep := @doStepBulletWork
  6770 end;
  7126 end;
  6771 
  7127 
  6772 (*
       
  6773  This didn't end up getting used, but, who knows, might be reasonable for javellin or something
       
  6774 // Make the knife initial angle based on the hog attack angle, or is that too hard?
       
  6775 procedure doStepKnife(Gear: PGear);
       
  6776 var t,
       
  6777     gx, gy, ga,  // gear x,y,angle
       
  6778     lx, ly, la, // land x,y,angle
       
  6779     ox, oy, // x,y offset
       
  6780     w, h,   // wXh of clip area
       
  6781     tx, ty  // tip position in sprite
       
  6782     : LongInt;
       
  6783     surf: PSDL_Surface;
       
  6784     s: hwFloat;
       
  6785 
       
  6786 begin
       
  6787     Gear^.dY := Gear^.dY + cGravity;
       
  6788     if (GameFlags and gfMoreWind) <> 0 then
       
  6789         Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density;
       
  6790     Gear^.X := Gear^.X + Gear^.dX;
       
  6791     Gear^.Y := Gear^.Y + Gear^.dY;
       
  6792     CheckGearDrowning(Gear);
       
  6793     gx:= hwRound(Gear^.X);
       
  6794     gy:= hwRound(Gear^.Y);
       
  6795     if Gear^.State and gstDrowning <> 0 then exit;
       
  6796     with Gear^ do
       
  6797         begin
       
  6798         if CheckLandValue(gx, gy, lfLandMask) then
       
  6799             begin
       
  6800             t:= Angle + hwRound((hwAbs(dX)+hwAbs(dY)) * _10);
       
  6801 
       
  6802             if t < 0 then inc(t, 4096)
       
  6803             else if 4095 < t then dec(t, 4096);
       
  6804             Angle:= t;
       
  6805 
       
  6806             DirAngle:= Angle / 4096 * 360
       
  6807             end
       
  6808         else
       
  6809             begin
       
  6810 //This is the set of postions for the knife.
       
  6811 //Using FlipSurface and copyToXY the knife can be written to the LandPixels at 32 positions, and an appropriate line drawn in Land.
       
  6812             t:= Angle mod 1024;
       
  6813             case t div 128 of
       
  6814                 0:  begin
       
  6815                     ox:=   2; oy:= 5;
       
  6816                     w :=  25;  h:= 5;
       
  6817                     tx:=   0; ty:= 2
       
  6818                     end;
       
  6819                 1:  begin
       
  6820                     ox:=   2; oy:= 15;
       
  6821                      w:=  24;  h:=  8;
       
  6822                     tx:=   0; ty:=  7
       
  6823                     end;
       
  6824                 2:  begin
       
  6825                     ox:=   2; oy:= 27;
       
  6826                      w:=  23;  h:= 12;
       
  6827                     tx:= -12; ty:= -5
       
  6828                     end;
       
  6829                 3:  begin
       
  6830                     ox:=   2; oy:= 43;
       
  6831                      w:=  21;  h:= 15;
       
  6832                     tx:=   0; ty:= 14
       
  6833                     end;
       
  6834                 4:  begin
       
  6835                     ox:= 29; oy:=  8;
       
  6836                      w:= 19;  h:= 19;
       
  6837                     tx:=  0; ty:= 17
       
  6838                     end;
       
  6839                 5:  begin
       
  6840                     ox:= 29; oy:=  32;
       
  6841                      w:= 15;  h:=  21;
       
  6842                     tx:=  0; ty:=  20
       
  6843                     end;
       
  6844                 6:  begin
       
  6845                     ox:= 51; oy:=   3;
       
  6846                      w:= 11;  h:=  23;
       
  6847                     tx:=  0; ty:=  22
       
  6848                     end;
       
  6849                 7:  begin
       
  6850                     ox:= 51; oy:=  34;
       
  6851                      w:=  7;  h:=  24;
       
  6852                     tx:=  0; ty:=  23
       
  6853                     end
       
  6854                 end;
       
  6855 
       
  6856             surf:= SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, RMask, GMask, BMask, AMask);
       
  6857             copyToXYFromRect(SpritesData[sprKnife].Surface, surf, ox, oy, w, h, 0, 0);
       
  6858             // try to make the knife hit point first
       
  6859             lx := 0;
       
  6860             ly := 0;
       
  6861             if CalcSlopeTangent(Gear, gx, gy, lx, ly, 255) then
       
  6862                 begin
       
  6863                 la:= vector2Angle(int2hwFloat(lx), int2hwFloat(ly));
       
  6864                 ga:= vector2Angle(dX, dY);
       
  6865                 AddFileLog('la: '+inttostr(la)+' ga: '+inttostr(ga)+' Angle: '+inttostr(Angle));
       
  6866                 // change  to 0 to 4096 forced by LongWord in Gear
       
  6867                 if la < 0 then la:= 4096+la;
       
  6868                 if ga < 0 then ga:= 4096+ga;
       
  6869                 if ((Angle > ga) and (Angle < la)) or ((Angle < ga) and (Angle > la)) then
       
  6870                     begin
       
  6871                     if Angle >= 2048 then dec(Angle, 2048)
       
  6872                     else if Angle < 2048 then inc(Angle, 2048)
       
  6873                     end;
       
  6874                 AddFileLog('la: '+inttostr(la)+' ga: '+inttostr(ga)+' Angle: '+inttostr(Angle))
       
  6875                 end;
       
  6876             case Angle div 1024 of
       
  6877                 0:  begin
       
  6878                     flipSurface(surf, true);
       
  6879                     flipSurface(surf, true);
       
  6880                     BlitImageAndGenerateCollisionInfo(gx-(w-tx), gy-(h-ty), w, surf)
       
  6881                     end;
       
  6882                 1:  begin
       
  6883                     flipSurface(surf, false);
       
  6884                     BlitImageAndGenerateCollisionInfo(gx-(w-tx), gy-ty, w, surf)
       
  6885                     end;
       
  6886                 2:  begin // knife was actually drawn facing this way...
       
  6887                     BlitImageAndGenerateCollisionInfo(gx-tx, gy-ty, w, surf)
       
  6888                     end;
       
  6889                 3:  begin
       
  6890                     flipSurface(surf, true);
       
  6891                     BlitImageAndGenerateCollisionInfo(gx-tx, gy-(h-ty), w, surf)
       
  6892                     end
       
  6893                 end;
       
  6894             SDL_FreeSurface(surf);
       
  6895             // this needs to calculate actual width/height + land clipping since update texture doesn't.
       
  6896             // i.e. this will crash if you fire near sides of map, but until I get the blit right, not going to put real values
       
  6897             UpdateLandTexture(hwRound(X)-32, 64, hwRound(Y)-32, 64, true);
       
  6898             DeleteGear(Gear);
       
  6899             exit
       
  6900             end
       
  6901         end;
       
  6902 end;
       
  6903 *)
       
  6904 
       
  6905 end.
  7128 end.