hedgewars/uGearsHandlersMess.pas
branchwebgl
changeset 9950 2759212a27de
parent 9521 8054d9d775fd
parent 9885 34e8880f1f0a
child 9954 bf51bc7e2808
equal deleted inserted replaced
9521:8054d9d775fd 9950:2759212a27de
   206     while gi <> nil do
   206     while gi <> nil do
   207         begin
   207         begin
   208         if (gi^.Kind = gtHedgehog) then
   208         if (gi^.Kind = gtHedgehog) then
   209             begin
   209             begin
   210             d := r - hwRound(Distance(gi^.X - x, gi^.Y - y));
   210             d := r - hwRound(Distance(gi^.X - x, gi^.Y - y));
   211             if (d > 1) and (not gi^.Invulnerable) and (GetRandom(2) = 0) then
   211             if (d > 1) and ((gi^.Hedgehog^.Effects[heInvulnerable] = 0)) and (GetRandom(2) = 0) then
   212                 begin
   212                 begin
   213                 if (CurrentHedgehog^.Gear = gi) then
   213                 if (CurrentHedgehog^.Gear = gi) then
   214                     PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack)
   214                     PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack)
   215 
   215 
   216                 else
   216                 else
   261     begin
   261     begin
   262     AllInactive := false;
   262     AllInactive := false;
   263     Gear^.Y := Gear^.Y + cDrownSpeed;
   263     Gear^.Y := Gear^.Y + cDrownSpeed;
   264     Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed;
   264     Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed;
   265     // Create some bubbles (0.5% might be better but causes too few bubbles sometimes)
   265     // Create some bubbles (0.5% might be better but causes too few bubbles sometimes)
   266     if (((not SuddenDeathDmg) and (WaterOpacity < $FF))
   266     if ((not SuddenDeathDmg and (WaterOpacity < $FF))
   267     or (SuddenDeathDmg and (SDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then
   267     or (SuddenDeathDmg and (SDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then
   268         if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
   268         if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
   269             AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble)
   269             AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble)
   270     else if Random(12) = 0 then
   270     else if Random(12) = 0 then
   271              AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble);
   271              AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble);
   272     if ((not SuddenDeathDmg) and (WaterOpacity > $FE))
   272     if (not SuddenDeathDmg and (WaterOpacity > $FE))
   273     or (SuddenDeathDmg and (SDWaterOpacity > $FE))
   273     or (SuddenDeathDmg and (SDWaterOpacity > $FE))
   274     or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then
   274     or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then
   275         DeleteGear(Gear);
   275         DeleteGear(Gear);
   276     end;
   276     end;
   277 
   277 
   278 ////////////////////////////////////////////////////////////////////////////////
   278 ////////////////////////////////////////////////////////////////////////////////
   279 procedure doStepFallingGear(Gear: PGear);
   279 procedure doStepFallingGear(Gear: PGear);
   280 var
   280 var
   281     isFalling: boolean;
   281     isFalling: boolean;
   282     //tmp: QWord;
   282     //tmp: QWord;
   283     tdX, tdY: hwFloat;
   283     tX, tdX, tdY: hwFloat;
   284     collV, collH: LongInt;
   284     collV, collH, gX, gY: LongInt;
   285     land: word;
   285     land, xland: word;
   286 begin
   286     boing: PVisualGear;
   287     WorldWrap(Gear);
   287 begin
       
   288     tX:= Gear^.X;
       
   289     gX:= hwRound(Gear^.X);
       
   290     gY:= hwRound(Gear^.Y);
       
   291     if (Gear^.Kind <> gtGenericFaller) and WorldWrap(Gear) and (WorldEdge = weWrap) and (Gear^.AdvBounce <> 0) and
       
   292       ((TestCollisionXwithGear(Gear, 1) <> 0) or (TestCollisionXwithGear(Gear, -1) <> 0))  then
       
   293         begin
       
   294         Gear^.X:= tX;
       
   295         Gear^.dX.isNegative:= (gX > LongInt(leftX) + Gear^.Radius*2)
       
   296         end;
   288 
   297 
   289     // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems.
   298     // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems.
   290 {$IFNDEF WEBGL}
       
   291     if Gear^.dX.Round > 2 then
   299     if Gear^.dX.Round > 2 then
   292         Gear^.dX.QWordValue:= 8589934592;
   300         Gear^.dX.QWordValue:= 8589934592;
   293     if Gear^.dY.Round > 2 then
   301     if Gear^.dY.Round > 2 then
   294         Gear^.dY.QWordValue:= 8589934592;
   302         Gear^.dY.QWordValue:= 8589934592;
   295 {$ELSE}
   303 
   296     if Gear^.dX.Round > 2 then
   304     if (Gear^.State and gstSubmersible <> 0) and (gY > cWaterLine) then
   297         begin
   305         begin
   298         Gear^.dX.Round:= 2;
   306         Gear^.dX:= Gear^.dX * _0_999;
   299         Gear^.dX.Frac:= 0
   307         Gear^.dY:= Gear^.dY * _0_999
   300         end;
   308         end;
   301     if Gear^.dY.QWordValue > 2 then
   309 
   302         begin
       
   303         Gear^.dY.Round:= 2;
       
   304         Gear^.dY.Frac:= 0
       
   305         end;
       
   306 {$ENDIF}
       
   307     Gear^.State := Gear^.State and (not gstCollision);
   310     Gear^.State := Gear^.State and (not gstCollision);
   308     collV := 0;
   311     collV := 0;
   309     collH := 0;
   312     collH := 0;
   310     tdX := Gear^.dX;
   313     tdX := Gear^.dX;
   311     tdY := Gear^.dY;
   314     tdY := Gear^.dY;
   312 
   315 
   313 // might need some testing/adjustments - just to avoid projectiles to fly forever (accelerated by wind/skips)
   316 // might need some testing/adjustments - just to avoid projectiles to fly forever (accelerated by wind/skips)
   314     if (hwRound(Gear^.X) < min(LAND_WIDTH div -2, -2048))
   317     if (gX < min(LAND_WIDTH div -2, -2048))
   315     or (hwRound(Gear^.X) > max(LAND_WIDTH * 3 div 2, 6144)) then
   318     or (gX > max(LAND_WIDTH * 3 div 2, 6144)) then
   316         Gear^.State := Gear^.State or gstCollision;
   319         Gear^.State := Gear^.State or gstCollision;
   317 
   320 
   318     if Gear^.dY.isNegative then
   321     if Gear^.dY.isNegative then
   319         begin
   322         begin
   320         isFalling := true;
       
   321         land:= TestCollisionYwithGear(Gear, -1);
   323         land:= TestCollisionYwithGear(Gear, -1);
       
   324         isFalling := land = 0;
   322         if land <> 0 then
   325         if land <> 0 then
   323             begin
   326             begin
   324             collV := -1;
   327             collV := -1;
   325             if land and lfIce <> 0 then
   328             if land and lfIce <> 0 then
   326                 Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
   329                  Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
   327             else
   330             else Gear^.dX := Gear^.dX * Gear^.Friction;
   328                 Gear^.dX := Gear^.dX * Gear^.Friction;
   331             if (Gear^.AdvBounce = 0) or (land and lfBouncy = 0) then
   329 
   332                  begin
   330             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
   333                  Gear^.dY := - Gear^.dY * Gear^.Elasticity;
   331             Gear^.State := Gear^.State or gstCollision
   334                  Gear^.State := Gear^.State or gstCollision
       
   335                  end
       
   336             else Gear^.dY := - Gear^.dY * cElastic
   332             end
   337             end
   333         else if (Gear^.AdvBounce=1) and (TestCollisionYwithGear(Gear, 1) <> 0) then
   338         else if Gear^.AdvBounce = 1 then
   334             collV := 1;
   339             begin
       
   340             land:= TestCollisionYwithGear(Gear, 1);
       
   341             if land <> 0 then collV := 1
       
   342             end
   335         end
   343         end
   336     else
   344     else
   337         begin // Gear^.dY.isNegative is false
   345         begin // Gear^.dY.isNegative is false
   338         land:= TestCollisionYwithGear(Gear, 1);
   346         land:= TestCollisionYwithGear(Gear, 1);
   339         if land <> 0 then
   347         if land <> 0 then
   343             if land and lfIce <> 0 then
   351             if land and lfIce <> 0 then
   344                 Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
   352                 Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
   345             else
   353             else
   346                 Gear^.dX := Gear^.dX * Gear^.Friction;
   354                 Gear^.dX := Gear^.dX * Gear^.Friction;
   347 
   355 
   348             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
   356             if (Gear^.AdvBounce = 0) or (land and lfBouncy = 0) then
       
   357                  begin
       
   358                  Gear^.dY := - Gear^.dY * Gear^.Elasticity;
       
   359                  Gear^.State := Gear^.State or gstCollision
       
   360                  end
       
   361             else Gear^.dY := - Gear^.dY * cElastic
       
   362             end
       
   363         else
       
   364             begin
       
   365             isFalling := true;
       
   366             if Gear^.AdvBounce = 1 then
       
   367                 begin
       
   368                 land:= TestCollisionYwithGear(Gear, -1);
       
   369                 if land <> 0 then collV := -1
       
   370                 end
       
   371             end
       
   372         end;
       
   373 
       
   374 
       
   375     xland:= TestCollisionXwithGear(Gear, hwSign(Gear^.dX));
       
   376     if xland <> 0 then
       
   377         begin
       
   378         collH := hwSign(Gear^.dX);
       
   379         if (Gear^.AdvBounce = 0) or (xland and lfBouncy = 0) then
       
   380             begin
       
   381             Gear^.dX := - Gear^.dX * Gear^.Elasticity;
       
   382             Gear^.dY :=   Gear^.dY * Gear^.Elasticity;
   349             Gear^.State := Gear^.State or gstCollision
   383             Gear^.State := Gear^.State or gstCollision
   350             end
   384             end
   351         else
   385         else
   352             begin
   386             begin
   353             isFalling := true;
   387             Gear^.dX := - Gear^.dX * cElastic;
   354             if (Gear^.AdvBounce=1) and (TestCollisionYwithGear(Gear, -1) <> 0) then
   388             Gear^.dY :=   Gear^.dY * cElastic
   355                 collV := -1
       
   356             end
   389             end
   357         end;
   390         end
   358 
   391     else if Gear^.AdvBounce = 1 then
   359 
   392         begin
   360     if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
   393         xland:= TestCollisionXwithGear(Gear, -hwSign(Gear^.dX));
   361         begin
   394         if xland <> 0 then collH := -hwSign(Gear^.dX)
   362         collH := hwSign(Gear^.dX);
   395         end;
   363         Gear^.dX := - Gear^.dX * Gear^.Elasticity;
       
   364         Gear^.dY :=   Gear^.dY * Gear^.Elasticity;
       
   365         Gear^.State := Gear^.State or gstCollision
       
   366         end
       
   367     else if (Gear^.AdvBounce=1) and TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)) then
       
   368         collH := -hwSign(Gear^.dX);
       
   369     //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
   396     //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
   370     if (Gear^.AdvBounce=1) and (collV <>0) and (collH <> 0) and ((collV=-1)
   397     if (collV <> 0) and (collH <> 0) and 
   371     or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)) then
   398        (((Gear^.AdvBounce=1) and ((collV=-1) or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)))) then
   372         begin
   399  //or ((xland or land) and lfBouncy <> 0)) then
   373         Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
   400         begin
   374         Gear^.dY := tdX*Gear^.Elasticity;
   401         if (xland or land) and lfBouncy = 0 then
   375         //*Gear^.Friction;
   402             begin
   376         Gear^.dY.isNegative := (not tdY.isNegative);
   403             Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
       
   404             Gear^.dY := tdX*Gear^.Elasticity;
       
   405             Gear^.State := Gear^.State or gstCollision
       
   406             end
       
   407         else
       
   408             begin
       
   409             Gear^.dX := tdY*cElastic*Gear^.Friction;
       
   410             Gear^.dY := tdX*cElastic
       
   411             end;
       
   412 
       
   413         Gear^.dY.isNegative := not tdY.isNegative;
   377         isFalling := false;
   414         isFalling := false;
   378         Gear^.AdvBounce := 10;
   415         Gear^.AdvBounce := 10;
   379         end;
   416         end;
   380 
   417 
   381     if Gear^.AdvBounce > 1 then
   418     if Gear^.AdvBounce > 1 then
   384     if isFalling then
   421     if isFalling then
   385         begin
   422         begin
   386         Gear^.dY := Gear^.dY + cGravity;
   423         Gear^.dY := Gear^.dY + cGravity;
   387         if (GameFlags and gfMoreWind) <> 0 then
   424         if (GameFlags and gfMoreWind) <> 0 then
   388             Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
   425             Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
   389             end;
   426         end;
   390 
   427 
   391     Gear^.X := Gear^.X + Gear^.dX;
   428     Gear^.X := Gear^.X + Gear^.dX;
   392     Gear^.Y := Gear^.Y + Gear^.dY;
   429     Gear^.Y := Gear^.Y + Gear^.dY;
   393     CheckGearDrowning(Gear);
   430     CheckGearDrowning(Gear);
   394     //if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) < _0_0002) and
   431     //if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) < _0_0002) and
   395     if (not isFalling) and ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_02.QWordValue) then
   432     if (not isFalling) and ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_02.QWordValue) then
   396         Gear^.State := Gear^.State and (not gstMoving)
   433         Gear^.State := Gear^.State and (not gstMoving)
   397     else
   434     else
   398         Gear^.State := Gear^.State or gstMoving;
   435         Gear^.State := Gear^.State or gstMoving;
   399 
   436 
   400     if (Gear^.nImpactSounds > 0) and
   437     if ((xland or land) and lfBouncy <> 0) and (Gear^.dX.QWordValue < _0_15.QWordValue) and (Gear^.dY.QWordValue < _0_15.QWordValue) then
       
   438         Gear^.State := Gear^.State or gstCollision;
       
   439     
       
   440     if ((xland or land) and lfBouncy <> 0) and (Gear^.Radius >= 3) and
       
   441        ((Gear^.dX.QWordValue > _0_15.QWordValue) or (Gear^.dY.QWordValue > _0_15.QWordValue)) then
       
   442         begin
       
   443         boing:= AddVisualGear(gX, gY, vgtStraightShot, 0, false, 1);
       
   444         if boing <> nil then
       
   445             with boing^ do
       
   446                 begin
       
   447                 Angle:= random(360);
       
   448                 dx:= 0;
       
   449                 dy:= 0;
       
   450                 FrameTicks:= 200;
       
   451                 tX:= _0;
       
   452                 tX.QWordValue:= Gear^.dY.QWordValue + Gear^.dX.QWordValue;
       
   453                 Scale:= hwFloat2Float(Gear^.Density * tX) / 1.5;
       
   454                 State:= ord(sprBoing)
       
   455                 end;
       
   456         PlaySound(sndMelonImpact, true)
       
   457         end
       
   458     else if (Gear^.nImpactSounds > 0) and
   401         (Gear^.State and gstCollision <> 0) and
   459         (Gear^.State and gstCollision <> 0) and
   402         (((Gear^.Kind <> gtMine) and (Gear^.Damage <> 0)) or (Gear^.State and gstMoving <> 0)) and
   460         (((Gear^.Kind <> gtMine) and (Gear^.Damage <> 0)) or (Gear^.State and gstMoving <> 0)) and
   403         (((Gear^.Radius < 3) and (Gear^.dY < -_0_1)) or
   461         (((Gear^.Radius < 3) and (Gear^.dY < -_0_1)) or
   404             ((Gear^.Radius >= 3) and
   462             ((Gear^.Radius >= 3) and
   405                 ((Gear^.dX.QWordValue > _0_1.QWordValue) or (Gear^.dY.QWordValue > _0_1.QWordValue)))) then
   463                 ((Gear^.dX.QWordValue > _0_1.QWordValue) or (Gear^.dY.QWordValue > _0_1.QWordValue)))) then
   698     CheckCollision(Gear);
   756     CheckCollision(Gear);
   699     if ((Gear^.State and gstCollision) <> 0) or ((Gear^.State and gstMoving) = 0) then
   757     if ((Gear^.State and gstCollision) <> 0) or ((Gear^.State and gstMoving) = 0) then
   700         draw:= true;
   758         draw:= true;
   701     xx:= hwRound(Gear^.X);
   759     xx:= hwRound(Gear^.X);
   702     yy:= hwRound(Gear^.Y);
   760     yy:= hwRound(Gear^.Y);
       
   761     if draw and (WorldEdge = weWrap) and ((xx < LongInt(leftX) + 3) or (xx > LongInt(rightX) - 3)) then
       
   762         begin
       
   763         if xx < LongInt(leftX) + 3 then 
       
   764              xx:= rightX-3
       
   765         else xx:= leftX+3;
       
   766         Gear^.X:= int2hwFloat(xx)
       
   767         end
   703     end
   768     end
   704 else if GameTicks and $7 = 0 then
   769 else if GameTicks and $7 = 0 then
   705     begin
   770     begin
   706     with Gear^ do
   771     with Gear^ do
   707         begin
   772         begin
   862         end;
   927         end;
   863 
   928 
   864     AllInactive := false;
   929     AllInactive := false;
   865 
   930 
   866     if Gear^.dY.isNegative then
   931     if Gear^.dY.isNegative then
   867         if TestCollisionY(Gear, -1) then
   932         if TestCollisionY(Gear, -1) <> 0 then
   868             Gear^.dY := _0;
   933             Gear^.dY := _0;
   869 
   934 
   870     if (not Gear^.dY.isNegative) then
   935     if not Gear^.dY.isNegative then
   871         if TestCollisionY(Gear, 1) then
   936         if TestCollisionY(Gear, 1) <> 0 then
   872         begin
   937             begin
   873             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
   938             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
   874             if Gear^.dY > - _1div1024 then
   939             if Gear^.dY > - _1div1024 then
   875             begin
   940                 begin
   876                 Gear^.Active := false;
   941                 Gear^.Active := false;
   877                 exit
   942                 exit
   878             end
   943                 end
   879             else if Gear^.dY < - _0_03 then
   944             else if Gear^.dY < - _0_03 then
   880                 PlaySound(Gear^.ImpactSound)
   945                 PlaySound(Gear^.ImpactSound)
   881         end;
   946             end;
   882 
   947 
   883     Gear^.Y := Gear^.Y + Gear^.dY;
   948     Gear^.Y := Gear^.Y + Gear^.dY;
   884     CheckGearDrowning(Gear);
   949     CheckGearDrowning(Gear);
   885     Gear^.dY := Gear^.dY + cGravity
   950     Gear^.dY := Gear^.dY + cGravity
   886 end;
   951 end;
   922             end;
   987             end;
   923         end;
   988         end;
   924 
   989 
   925 
   990 
   926     if Gear^.Timer = 0 then
   991     if Gear^.Timer = 0 then
   927         Gear^.RenderTimer:= false
   992         begin
       
   993         // no "fuel"? just fall
       
   994         doStepFallingGear(Gear);
       
   995         // if drowning, stop bee sound
       
   996         if (Gear^.State and gstDrowning) <> 0 then
       
   997             StopSoundChan(Gear^.SoundChannel);
       
   998         end
   928     else
   999     else
   929         begin
  1000         begin
   930         if (GameTicks and $F) = 0 then
  1001         if (GameTicks and $F) = 0 then
   931             begin
  1002             begin
   932             if (GameTicks and $30) = 0 then
  1003             if (GameTicks and $30) = 0 then
   933                 AddVisualGear(gX, gY, vgtBeeTrace);
  1004                 begin
       
  1005                 if nuw then
       
  1006                     AddVisualGear(gX, gY, vgtBubble)
       
  1007                 else
       
  1008                     AddVisualGear(gX, gY, vgtBeeTrace);
       
  1009                 end;
   934             Gear^.dX := Gear^.Elasticity * (Gear^.dX + _0_000064 * (Gear^.Target.X - gX));
  1010             Gear^.dX := Gear^.Elasticity * (Gear^.dX + _0_000064 * (Gear^.Target.X - gX));
   935             Gear^.dY := Gear^.Elasticity * (Gear^.dY + _0_000064 * (Gear^.Target.Y - gY));
  1011             Gear^.dY := Gear^.Elasticity * (Gear^.dY + _0_000064 * (Gear^.Target.Y - gY));
   936             // make sure new speed isn't higher than original one (which we stored in Friction variable)
  1012             // make sure new speed isn't higher than original one (which we stored in Friction variable)
   937             t := Gear^.Friction / Distance(Gear^.dX, Gear^.dY);
  1013             t := Gear^.Friction / Distance(Gear^.dX, Gear^.dY);
   938             Gear^.dX := Gear^.dX * t;
  1014             Gear^.dX := Gear^.dX * t;
   969             end;
  1045             end;
   970         DeleteGear(Gear);
  1046         DeleteGear(Gear);
   971     end;
  1047     end;
   972 
  1048 
   973     if (Gear^.Timer > 0) then
  1049     if (Gear^.Timer > 0) then
   974         dec(Gear^.Timer)
  1050         begin
   975     else
  1051         dec(Gear^.Timer);
   976         begin
  1052         if Gear^.Timer = 0 then
   977         Gear^.State:= Gear^.State and (not gstSubmersible);
  1053             begin
   978         if nuw then
  1054             // no need to display remaining time anymore
   979            begin
  1055             Gear^.RenderTimer:= false;
   980             StopSoundChan(Gear^.SoundChannel);
  1056             // bee can drown when timer reached 0
   981             CheckGearDrowning(Gear);
  1057             Gear^.State:= Gear^.State and not gstSubmersible;
   982             end
  1058             end;
   983         else
       
   984             doStepFallingGear(Gear);
       
   985         end;
  1059         end;
   986 end;
  1060 end;
   987 
  1061 
   988 procedure doStepBee(Gear: PGear);
  1062 procedure doStepBee(Gear: PGear);
   989 begin
  1063 begin
  1139     repeat
  1213     repeat
  1140         Gear^.X := Gear^.X + Gear^.dX;
  1214         Gear^.X := Gear^.X + Gear^.dX;
  1141         Gear^.Y := Gear^.Y + Gear^.dY;
  1215         Gear^.Y := Gear^.Y + Gear^.dY;
  1142         tX:= Gear^.X;
  1216         tX:= Gear^.X;
  1143         tY:= Gear^.Y;
  1217         tY:= Gear^.Y;
  1144         if WorldWrap(Gear) then
  1218         if (Gear^.PortalCounter < 30) and WorldWrap(Gear) then
  1145             begin
  1219             begin
  1146             cX:= Gear^.X;
  1220             cX:= Gear^.X;
  1147             cY:= Gear^.Y;
  1221             cY:= Gear^.Y;
  1148             Gear^.X:= tX;
  1222             Gear^.X:= tX;
  1149             Gear^.Y:= tY;
  1223             Gear^.Y:= tY;
  1159         y := hwRound(Gear^.Y);
  1233         y := hwRound(Gear^.Y);
  1160 
  1234 
  1161         if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then
  1235         if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then
  1162             inc(Gear^.Damage);
  1236             inc(Gear^.Damage);
  1163         // let's interrupt before a collision to give portals a chance to catch the bullet
  1237         // let's interrupt before a collision to give portals a chance to catch the bullet
  1164         if (Gear^.Damage = 1) and (Gear^.Tag = 0) and (not(CheckLandValue(x, y, lfLandMask))) then
  1238         if (Gear^.Damage = 1) and (Gear^.Tag = 0) and not(CheckLandValue(x, y, lfLandMask)) then
  1165             begin
  1239             begin
  1166             Gear^.Tag := 1;
  1240             Gear^.Tag := 1;
  1167             Gear^.Damage := 0;
  1241             Gear^.Damage := 0;
  1168             Gear^.X := Gear^.X - Gear^.dX;
  1242             Gear^.X := Gear^.X - Gear^.dX;
  1169             Gear^.Y := Gear^.Y - Gear^.dY;
  1243             Gear^.Y := Gear^.Y - Gear^.dY;
  1186         begin
  1260         begin
  1187         DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 82 - i, 1);
  1261         DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 82 - i, 1);
  1188         dec(Gear^.Health, Gear^.Damage);
  1262         dec(Gear^.Health, Gear^.Damage);
  1189         Gear^.Damage := 0
  1263         Gear^.Damage := 0
  1190         end;
  1264         end;
  1191     if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and (((not SuddenDeathDmg) and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) then
  1265     if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and ((not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) then
  1192         begin
  1266         begin
  1193         for i:=(Gear^.Health - Gear^.Damage) * 4 downto 0 do
  1267         for i:=(Gear^.Health - Gear^.Damage) * 4 downto 0 do
  1194             begin
  1268             begin
  1195             if Random(6) = 0 then
  1269             if Random(6) = 0 then
  1196                 AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
  1270                 AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
  1372         if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9), lfIndestructible) then
  1446         if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9), lfIndestructible) then
  1373             begin
  1447             begin
  1374             Gear^.X := Gear^.X + Gear^.dX;
  1448             Gear^.X := Gear^.X + Gear^.dX;
  1375             Gear^.Y := Gear^.Y + _1_9;
  1449             Gear^.Y := Gear^.Y + _1_9;
  1376             end;
  1450             end;
  1377         SetAllHHToActive(true);
  1451         SetAllHHToActive;
  1378         end;
  1452         end;
  1379     if TestCollisionYwithGear(Gear, 1) <> 0 then
  1453     if TestCollisionYwithGear(Gear, 1) <> 0 then
  1380         begin
  1454         begin
  1381         Gear^.dY := _0;
  1455         Gear^.dY := _0;
  1382         SetLittle(HHGear^.dX);
  1456         SetLittle(HHGear^.dX);
  1647             Gear^.State := Gear^.State or gsttmpFlag;
  1721             Gear^.State := Gear^.State or gsttmpFlag;
  1648 end;
  1722 end;
  1649 
  1723 
  1650 ////////////////////////////////////////////////////////////////////////////////
  1724 ////////////////////////////////////////////////////////////////////////////////
  1651 procedure doStepSMine(Gear: PGear);
  1725 procedure doStepSMine(Gear: PGear);
       
  1726     var land: Word;
  1652 begin
  1727 begin
  1653     // TODO: do real calculation?
  1728     // TODO: do real calculation?
  1654     if TestCollisionXwithGear(Gear, 2)
  1729     land:= TestCollisionXwithGear(Gear, 2);
  1655     or (TestCollisionYwithGear(Gear, -2) <> 0)
  1730     if land = 0 then land:= TestCollisionYwithGear(Gear,-2);
  1656     or TestCollisionXwithGear(Gear, -2)
  1731     if land = 0 then land:= TestCollisionXwithGear(Gear,-2);
  1657     or (TestCollisionYwithGear(Gear, 2) <> 0) then
  1732     if land = 0 then land:= TestCollisionYwithGear(Gear, 2);
       
  1733     if (land <> 0) and (land and lfBouncy = 0) then
  1658         begin
  1734         begin
  1659         if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
  1735         if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
  1660             begin
  1736             begin
  1661             PlaySound(sndRopeAttach);
  1737             PlaySound(sndRopeAttach);
  1662             Gear^.dX:= _0;
  1738             Gear^.dX:= _0;
  1679             if ((GameTicks and $1F) = 0) then
  1755             if ((GameTicks and $1F) = 0) then
  1680                 if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then
  1756                 if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then
  1681                     Gear^.State := Gear^.State or gstAttacking
  1757                     Gear^.State := Gear^.State or gstAttacking
  1682             end
  1758             end
  1683         else // gstAttacking <> 0
  1759         else // gstAttacking <> 0
  1684         begin
  1760             begin
  1685             AllInactive := false;
  1761             AllInactive := false;
  1686             if Gear^.Timer = 0 then
  1762             if Gear^.Timer = 0 then
  1687                 begin
  1763                 begin
  1688                 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
  1764                 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
  1689                 DeleteGear(Gear);
  1765                 DeleteGear(Gear);
  1690                 exit
  1766                 exit
  1691             end else
  1767                 end
       
  1768             else
  1692                 if (Gear^.Timer and $FF) = 0 then
  1769                 if (Gear^.Timer and $FF) = 0 then
  1693                     PlaySound(sndMineTick);
  1770                     PlaySound(sndMineTick);
  1694 
  1771                 dec(Gear^.Timer);
  1695             dec(Gear^.Timer);
       
  1696                 end
  1772                 end
  1697         end
  1773             end
  1698     else // gsttmpFlag = 0
  1774     else // gsttmpFlag = 0
  1699         if (TurnTimeLeft = 0)
  1775         if ((GameFlags and gfInfAttack = 0) and ((TurnTimeLeft = 0) or (Gear^.Hedgehog^.Gear = nil))) 
  1700         or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime))
  1776         or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime)) then
  1701         or (Gear^.Hedgehog^.Gear = nil) then
       
  1702             Gear^.State := Gear^.State or gsttmpFlag;
  1777             Gear^.State := Gear^.State or gsttmpFlag;
  1703 end;
  1778 end;
  1704 
  1779 
  1705 ////////////////////////////////////////////////////////////////////////////////
  1780 ////////////////////////////////////////////////////////////////////////////////
  1706 procedure doStepDynamite(Gear: PGear);
  1781 procedure doStepDynamite(Gear: PGear);
  1729     dxdy: hwFloat;
  1804     dxdy: hwFloat;
  1730 begin
  1805 begin
  1731     if (Gear^.dY.QWordValue = 0) and (Gear^.dY.QWordValue = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then
  1806     if (Gear^.dY.QWordValue = 0) and (Gear^.dY.QWordValue = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then
  1732         SetLittle(Gear^.dY);
  1807         SetLittle(Gear^.dY);
  1733     Gear^.State := Gear^.State or gstAnimation;
  1808     Gear^.State := Gear^.State or gstAnimation;
  1734     if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and (not gstFrozen);
  1809     if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and not gstFrozen;
  1735 
  1810 
  1736     if ((Gear^.dX.QWordValue <> 0)
  1811     if ((Gear^.dX.QWordValue <> 0)
  1737     or (Gear^.dY.QWordValue <> 0))  then
  1812     or (Gear^.dY.QWordValue <> 0))  then
  1738         begin
  1813         begin
  1739         DeleteCI(Gear);
  1814         DeleteCI(Gear);
  1777                 Gear^.dX:= _0_08;
  1852                 Gear^.dX:= _0_08;
  1778             end;
  1853             end;
  1779     if Gear^.dX.QWordValue = 0 then AddCI(Gear)
  1854     if Gear^.dX.QWordValue = 0 then AddCI(Gear)
  1780     end; *)
  1855     end; *)
  1781 
  1856 
  1782     if (not Gear^.dY.isNegative) and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then
  1857     if not Gear^.dY.isNegative and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then
  1783         Gear^.dY := _0;
  1858         Gear^.dY := _0;
  1784     if hwAbs(Gear^.dX) < _0_001 then
  1859     if hwAbs(Gear^.dX) < _0_001 then
  1785         Gear^.dX := _0;
  1860         Gear^.dX := _0;
  1786 
  1861 
  1787     if (Gear^.Health > 0) and ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
  1862     if (Gear^.Health > 0) and ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
  1815         with CurrentHedgehog^ do
  1890         with CurrentHedgehog^ do
  1816             if Gear <> nil then
  1891             if Gear <> nil then
  1817                 Gear^.Message := Gear^.Message and (not (gmLJump or gmHJump));
  1892                 Gear^.Message := Gear^.Message and (not (gmLJump or gmHJump));
  1818         exit
  1893         exit
  1819         end;
  1894         end;
  1820     if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and (not gstFrozen);
  1895     if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and not gstFrozen;
  1821 
  1896 
  1822     if ((k <> gtExplosives) and (Gear^.Damage > 0)) or ((k = gtExplosives) and (Gear^.Health<=0)) then
  1897     if ((k <> gtExplosives) and (Gear^.Damage > 0)) or ((k = gtExplosives) and (Gear^.Health<=0)) then
  1823         begin
  1898         begin
  1824         x := hwRound(Gear^.X);
  1899         x := hwRound(Gear^.X);
  1825         y := hwRound(Gear^.Y);
  1900         y := hwRound(Gear^.Y);
  1922         begin
  1997         begin
  1923         AllInactive := false;
  1998         AllInactive := false;
  1924 
  1999 
  1925         Gear^.dY := Gear^.dY + cGravity;
  2000         Gear^.dY := Gear^.dY + cGravity;
  1926 
  2001 
  1927         if (Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, -1) <> 0) then
  2002         if ((not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0)) or
  1928             Gear^.dY := _0;
  2003            (Gear^.dY.isNegative and (TestCollisionYwithGear(Gear, -1) <> 0)) then
  1929 
  2004              Gear^.dY := _0
  1930         Gear^.Y := Gear^.Y + Gear^.dY;
  2005         else Gear^.Y := Gear^.Y + Gear^.dY;
  1931 
  2006 
  1932         if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then
  2007         if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then
  1933             SetAllHHToActive(false);
  2008             SetAllHHToActive(false);
  1934 
  2009 
  1935         if (not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0) then
  2010         if (not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0) then
  1960 ////////////////////////////////////////////////////////////////////////////////
  2035 ////////////////////////////////////////////////////////////////////////////////
  1961 
  2036 
  1962 procedure doStepTarget(Gear: PGear);
  2037 procedure doStepTarget(Gear: PGear);
  1963 begin
  2038 begin
  1964     if (Gear^.Timer = 0) and (Gear^.Tag = 0) then
  2039     if (Gear^.Timer = 0) and (Gear^.Tag = 0) then
       
  2040         begin
  1965         PlaySound(sndWarp);
  2041         PlaySound(sndWarp);
       
  2042         // workaround: save spawn Y for doStepCase (which is a mess atm)
       
  2043         Gear^.Angle:= hwRound(Gear^.Y);
       
  2044         end;
  1966 
  2045 
  1967     if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then
  2046     if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then
  1968         inc(Gear^.Timer)
  2047         inc(Gear^.Timer)
  1969     else if Gear^.Tag = 1 then
  2048     else if Gear^.Tag = 1 then
  1970         Gear^.Tag := 2
  2049         Gear^.Tag := 2
  2018     HHGear^.State := HHGear^.State or gstNoDamage;
  2097     HHGear^.State := HHGear^.State or gstNoDamage;
  2019     DeleteCI(HHGear);
  2098     DeleteCI(HHGear);
  2020 
  2099 
  2021     for i:= 0 to 3 do
  2100     for i:= 0 to 3 do
  2022         begin
  2101         begin
       
  2102         AddVisualGear(hwRound(Gear^.X) + hwSign(Gear^.dX) * (10 + 6 * i), hwRound(Gear^.Y) + 12 + Random(6), vgtDust);
  2023         AmmoShove(Gear, 30, 25);
  2103         AmmoShove(Gear, 30, 25);
  2024         Gear^.X := Gear^.X + Gear^.dX * 5
  2104         Gear^.X := Gear^.X + Gear^.dX * 5
  2025         end;
  2105         end;
  2026 
  2106 
  2027     HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
  2107     HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
  2039     tdX,tdY: HWFloat;
  2119     tdX,tdY: HWFloat;
  2040     landPixel: Word;
  2120     landPixel: Word;
  2041 begin
  2121 begin
  2042     WorldWrap(Gear);
  2122     WorldWrap(Gear);
  2043     sticky:= (Gear^.State and gsttmpFlag) <> 0;
  2123     sticky:= (Gear^.State and gsttmpFlag) <> 0;
  2044     if (not sticky) then AllInactive := false;
  2124     if not sticky then AllInactive := false;
  2045 
  2125 
  2046     landPixel:= TestCollisionYwithGear(Gear, 1);
  2126     landPixel:= TestCollisionYwithGear(Gear, 1);
  2047     if landPixel = 0 then
  2127     if landPixel = 0 then
  2048         begin
  2128         begin
  2049         AllInactive := false;
  2129         AllInactive := false;
  2122         else
  2202         else
  2123             begin
  2203             begin
  2124             gX := hwRound(Gear^.X);
  2204             gX := hwRound(Gear^.X);
  2125             gY := hwRound(Gear^.Y);
  2205             gY := hwRound(Gear^.Y);
  2126             // Standard fire
  2206             // Standard fire
  2127             if (not sticky) then
  2207             if not sticky then
  2128                 begin
  2208                 begin
  2129                 if ((GameTicks and $1) = 0) then
  2209                 if ((GameTicks and $1) = 0) then
  2130                     begin
  2210                     begin
  2131                     Gear^.Radius := 7;
  2211                     Gear^.Radius := 7;
  2132                     tdX:= Gear^.dX;
  2212                     tdX:= Gear^.dX;
  2148                     for i:= Random(2) downto 0 do
  2228                     for i:= Random(2) downto 0 do
  2149                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2229                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2150 
  2230 
  2151                 if Gear^.Health > 0 then
  2231                 if Gear^.Health > 0 then
  2152                     dec(Gear^.Health);
  2232                     dec(Gear^.Health);
  2153                 Gear^.Timer := 450 - Gear^.Tag * 8 + GetRandom(2)
  2233                 Gear^.Timer := 450 - Gear^.Tag * 8 + LongInt(GetRandom(2))
  2154                 end
  2234                 end
  2155             else
  2235             else
  2156                 begin
  2236                 begin
  2157                 // Modified fire
  2237                 // Modified fire
  2158                 if ((GameTicks and $7FF) = 0) and ((GameFlags and gfSolidLand) = 0) then
  2238                 if ((GameTicks and $7FF) = 0) and ((GameFlags and gfSolidLand) = 0) then
  2162                     for i:= Random(3) downto 0 do
  2242                     for i:= Random(3) downto 0 do
  2163                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2243                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2164                     end;
  2244                     end;
  2165 
  2245 
  2166 // 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.
  2246 // 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.
  2167                 Gear^.Timer := 100 - Gear^.Tag * 3 + GetRandom(2);
  2247                 Gear^.Timer := 100 - Gear^.Tag * 3 + LongInt(GetRandom(2));
  2168                 if (Gear^.Damage > 3000+Gear^.Tag*1500) then
  2248                 if (Gear^.Damage > 3000+Gear^.Tag*1500) then
  2169                     Gear^.Health := 0
  2249                     Gear^.Health := 0
  2170                 end
  2250                 end
  2171             end
  2251             end
  2172         end;
  2252         end;
  2173     if Gear^.Health = 0 then
  2253     if Gear^.Health = 0 then
  2174         begin
  2254         begin
  2175         gX := hwRound(Gear^.X);
  2255         gX := hwRound(Gear^.X);
  2176         gY := hwRound(Gear^.Y);
  2256         gY := hwRound(Gear^.Y);
  2177         if (not sticky) then
  2257         if not sticky then
  2178             begin
  2258             begin
  2179             if ((GameTicks and $3) = 0) and (Random(1) = 0) then
  2259             if ((GameTicks and $3) = 0) and (Random(1) = 0) then
  2180                 for i:= Random(2) downto 0 do
  2260                 for i:= Random(2) downto 0 do
  2181                     AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2261                     AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
  2182             end
  2262             end
  2211         AmmoShove(Gear, 30, 40);
  2291         AmmoShove(Gear, 30, 40);
  2212         HHGear^.State := HHGear^.State and (not gstNoDamage)
  2292         HHGear^.State := HHGear^.State and (not gstNoDamage)
  2213         end;
  2293         end;
  2214 
  2294 
  2215     HHGear^.dY := HHGear^.dY + cGravity;
  2295     HHGear^.dY := HHGear^.dY + cGravity;
  2216     if (not HHGear^.dY.isNegative) then
  2296     if Gear^.Timer > 0 then dec(Gear^.Timer);
       
  2297     if not (HHGear^.dY.isNegative) or (Gear^.Timer = 0) then
  2217         begin
  2298         begin
  2218         HHGear^.State := HHGear^.State or gstMoving;
  2299         HHGear^.State := HHGear^.State or gstMoving;
  2219         DeleteGear(Gear);
  2300         DeleteGear(Gear);
  2220         AfterAttack;
  2301         AfterAttack;
  2221         exit
  2302         exit
  2288 
  2369 
  2289     else if (Gear^.Message and gmDown) <> 0 then
  2370     else if (Gear^.Message and gmDown) <> 0 then
  2290         HHGear^.Y := HHGear^.Y + cGravity * 40;
  2371         HHGear^.Y := HHGear^.Y + cGravity * 40;
  2291 
  2372 
  2292     // don't drift into obstacles
  2373     // don't drift into obstacles
  2293     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
  2374     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) <> 0 then
  2294         HHGear^.X := HHGear^.X - int2hwFloat(hwSign(HHGear^.dX));
  2375         HHGear^.X := HHGear^.X - int2hwFloat(hwSign(HHGear^.dX));
  2295     HHGear^.Y := HHGear^.Y + cGravity * 100;
  2376     HHGear^.Y := HHGear^.Y + cGravity * 100;
  2296     Gear^.X := HHGear^.X;
  2377     Gear^.X := HHGear^.X;
  2297     Gear^.Y := HHGear^.Y
  2378     Gear^.Y := HHGear^.Y
  2298 end;
  2379 end;
  2320 procedure doStepAirAttackWork(Gear: PGear);
  2401 procedure doStepAirAttackWork(Gear: PGear);
  2321 begin
  2402 begin
  2322     AllInactive := false;
  2403     AllInactive := false;
  2323     Gear^.X := Gear^.X + cAirPlaneSpeed * Gear^.Tag;
  2404     Gear^.X := Gear^.X + cAirPlaneSpeed * Gear^.Tag;
  2324 
  2405 
  2325     if (Gear^.Health > 0) and (not (Gear^.X < Gear^.dX)) and (Gear^.X < Gear^.dX + cAirPlaneSpeed) then
  2406     if (Gear^.Health > 0)and(not (Gear^.X < Gear^.dX))and(Gear^.X < Gear^.dX + cAirPlaneSpeed) then
  2326         begin
  2407         begin
  2327         dec(Gear^.Health);
  2408         dec(Gear^.Health);
  2328             case Gear^.State of
  2409             case Gear^.State of
  2329                 0: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
  2410                 0: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
  2330                 1: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine,    0, cBombsSpeed * Gear^.Tag, _0, 0);
  2411                 1: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine,    0, cBombsSpeed * Gear^.Tag, _0, 0);
  2388     doStepFallingGear(Gear);
  2469     doStepFallingGear(Gear);
  2389     if (Gear^.State and gstCollision) <> 0 then
  2470     if (Gear^.State and gstCollision) <> 0 then
  2390         begin
  2471         begin
  2391         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
  2472         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
  2392         DeleteGear(Gear);
  2473         DeleteGear(Gear);
  2393         {$IFNDEF PAS2C}
       
  2394         with mobileRecord do
  2474         with mobileRecord do
  2395             if (performRumble <> nil) and (not fastUntilLag) then
  2475             if (performRumble <> nil) and (not fastUntilLag) then
  2396                 performRumble(kSystemSoundID_Vibrate);
  2476                 performRumble(kSystemSoundID_Vibrate);
  2397         {$ENDIF}
       
  2398         exit
  2477         exit
  2399         end;
  2478         end;
  2400     if (GameTicks and $3F) = 0 then
  2479     if (GameTicks and $3F) = 0 then
  2401         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
  2480         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
  2402 end;
  2481 end;
  2406 procedure doStepGirder(Gear: PGear);
  2485 procedure doStepGirder(Gear: PGear);
  2407 var
  2486 var
  2408     HHGear: PGear;
  2487     HHGear: PGear;
  2409     x, y, tx, ty: hwFloat;
  2488     x, y, tx, ty: hwFloat;
  2410     rx: LongInt;
  2489     rx: LongInt;
       
  2490     LandFlags: Word;
  2411 begin
  2491 begin
  2412     AllInactive := false;
  2492     AllInactive := false;
  2413 
  2493 
  2414     HHGear := Gear^.Hedgehog^.Gear;
  2494     HHGear := Gear^.Hedgehog^.Gear;
  2415     tx := int2hwFloat(Gear^.Target.X);
  2495     tx := int2hwFloat(Gear^.Target.X);
  2416     ty := int2hwFloat(Gear^.Target.Y);
  2496     ty := int2hwFloat(Gear^.Target.Y);
  2417     x := HHGear^.X;
  2497     x := HHGear^.X;
  2418     y := HHGear^.Y;
  2498     y := HHGear^.Y;
  2419     rx:= hwRound(x);
  2499     rx:= hwRound(x);
  2420 
  2500 
       
  2501     LandFlags:= 0;
       
  2502     if Gear^.AmmoType = amRubber then LandFlags:= lfBouncy
       
  2503     else if cIce then LandFlags:= lfIce;
       
  2504 
  2421     if ((Distance(tx - x, ty - y) > _256) and ((WorldEdge <> weWrap) or 
  2505     if ((Distance(tx - x, ty - y) > _256) and ((WorldEdge <> weWrap) or 
  2422             (
  2506             (
  2423             (Distance(tx - int2hwFloat(rightX+(rx-leftX)), ty - y) > _256) and
  2507             (Distance(tx - int2hwFloat(rightX+(rx-leftX)), ty - y) > _256) and
  2424             (Distance(tx - int2hwFloat(leftX-(rightX-rx)), ty - y) > _256)
  2508             (Distance(tx - int2hwFloat(leftX-(rightX-rx)), ty - y) > _256)
  2425             )))
  2509             )))
  2426     or (not TryPlaceOnLand(Gear^.Target.X - SpritesData[sprAmGirder].Width div 2, Gear^.Target.Y - SpritesData[sprAmGirder].Height div 2, sprAmGirder, Gear^.State, true, false)) then
  2510     or (not TryPlaceOnLand(Gear^.Target.X - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Width div 2, Gear^.Target.Y - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Height div 2, Ammoz[Gear^.AmmoType].PosSprite, Gear^.State, true, false, LandFlags)) then
  2427         begin
  2511         begin
  2428         PlaySound(sndDenied);
  2512         PlaySound(sndDenied);
  2429         HHGear^.Message := HHGear^.Message and (not gmAttack);
  2513         HHGear^.Message := HHGear^.Message and (not gmAttack);
  2430         HHGear^.State := HHGear^.State and (not gstAttacking);
  2514         HHGear^.State := HHGear^.State and (not gstAttacking);
  2431         HHGear^.State := HHGear^.State or gstHHChooseTarget;
  2515         HHGear^.State := HHGear^.State or gstHHChooseTarget;
  2483     HHGear: PGear;
  2567     HHGear: PGear;
  2484 begin
  2568 begin
  2485     AllInactive := false;
  2569     AllInactive := false;
  2486 
  2570 
  2487     HHGear := Gear^.Hedgehog^.Gear;
  2571     HHGear := Gear^.Hedgehog^.Gear;
  2488     if (not (TryPlaceOnLand(Gear^.Target.X - SpritesData[sprHHTelepMask].Width div 2,
  2572     if not TryPlaceOnLand(Gear^.Target.X - SpritesData[sprHHTelepMask].Width div 2,
  2489         Gear^.Target.Y - SpritesData[sprHHTelepMask].Height div 2,
  2573         Gear^.Target.Y - SpritesData[sprHHTelepMask].Height div 2,
  2490         sprHHTelepMask, 0, false, false))) then
  2574         sprHHTelepMask, 0, false, false) then
  2491         begin
  2575         begin
  2492         HHGear^.Message := HHGear^.Message and (not gmAttack);
  2576         HHGear^.Message := HHGear^.Message and (not gmAttack);
  2493         HHGear^.State := HHGear^.State and (not gstAttacking);
  2577         HHGear^.State := HHGear^.State and (not gstAttacking);
  2494         HHGear^.State := HHGear^.State or gstHHChooseTarget;
  2578         HHGear^.State := HHGear^.State or gstHHChooseTarget;
  2495         DeleteGear(Gear);
  2579         DeleteGear(Gear);
  2497         PlaySound(sndDenied)
  2581         PlaySound(sndDenied)
  2498         end
  2582         end
  2499     else
  2583     else
  2500         begin
  2584         begin
  2501         DeleteCI(HHGear);
  2585         DeleteCI(HHGear);
  2502         SetAllHHToActive(true);
  2586         SetAllHHToActive;
  2503         Gear^.doStep := @doStepTeleportAnim;
  2587         Gear^.doStep := @doStepTeleportAnim;
  2504 
  2588 
  2505   // copy old HH position and direction to Gear (because we need them for drawing the vanishing hog)
  2589   // copy old HH position and direction to Gear (because we need them for drawing the vanishing hog)
  2506         Gear^.dX := HHGear^.dX;
  2590         Gear^.dX := HHGear^.dX;
  2507         // retrieve the cursor direction (it was previously copied to X so it doesn't get lost)
  2591         // retrieve the cursor direction (it was previously copied to X so it doesn't get lost)
  2819                 tdY:= gi^.Y-fY;
  2903                 tdY:= gi^.Y-fY;
  2820                 if hwRound(hwAbs(tdX)+hwAbs(tdY)) < dmgBase then
  2904                 if hwRound(hwAbs(tdX)+hwAbs(tdY)) < dmgBase then
  2821                     dmg:= dmgBase - max(hwRound(Distance(tdX, tdY)),gi^.Radius);
  2905                     dmg:= dmgBase - max(hwRound(Distance(tdX, tdY)),gi^.Radius);
  2822                 if (dmg > 1) then dmg:= ModifyDamage(min(dmg div 2, cakeDmg), gi);
  2906                 if (dmg > 1) then dmg:= ModifyDamage(min(dmg div 2, cakeDmg), gi);
  2823                 if (dmg > 1) then
  2907                 if (dmg > 1) then
  2824                     if (CurrentHedgehog^.Gear = gi) and (not gi^.Invulnerable) then
  2908                     if (CurrentHedgehog^.Gear = gi) and ((gi^.Hedgehog^.Effects[heInvulnerable] = 0)) then
  2825                         gi^.State := gi^.State or gstLoser
  2909                         gi^.State := gi^.State or gstLoser
  2826                     else
  2910                     else
  2827                         gi^.State := gi^.State or gstWinner;
  2911                         gi^.State := gi^.State or gstWinner;
  2828                 end;
  2912                 end;
  2829             gi := gi^.NextGear
  2913             gi := gi^.NextGear
  3070         exit
  3154         exit
  3071     end;
  3155     end;
  3072 
  3156 
  3073     tempColl:= Gear^.CollisionMask;
  3157     tempColl:= Gear^.CollisionMask;
  3074     Gear^.CollisionMask:= $007F;
  3158     Gear^.CollisionMask:= $007F;
  3075     if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) or (GameTicks > Gear^.FlightTime) then
  3159     if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) <> 0) or (GameTicks > Gear^.FlightTime) then
  3076         t := CheckGearsCollision(Gear)
  3160         t := CheckGearsCollision(Gear)
  3077     else t := nil;
  3161     else t := nil;
  3078     Gear^.CollisionMask:= tempColl;
  3162     Gear^.CollisionMask:= tempColl;
  3079     //fixes drill not exploding when touching HH bug
  3163     //fixes drill not exploding when touching HH bug
  3080 
  3164 
  3081     if (Gear^.Timer = 0) or ((t <> nil) and (t^.Count <> 0))
  3165     if (Gear^.Timer = 0) or ((t <> nil) and (t^.Count <> 0))
  3082     or ( ((Gear^.State and gsttmpFlag) = 0) and (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not TestCollisionXWithGear(Gear, hwSign(Gear^.dX))))
  3166     or ( ((Gear^.State and gsttmpFlag) = 0) and (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) = 0))
  3083 // CheckLandValue returns true if the type isn't matched
  3167 // CheckLandValue returns true if the type isn't matched
  3084     or (not (CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible))) then
  3168     or (not CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible)) then
  3085         begin
  3169         begin
  3086         //out of time or exited ground
  3170         //out of time or exited ground
  3087         StopSoundChan(Gear^.SoundChannel);
  3171         StopSoundChan(Gear^.SoundChannel);
  3088         if (Gear^.State and gsttmpFlag) <> 0 then
  3172         if (Gear^.State and gsttmpFlag) <> 0 then
  3089             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound)
  3173             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound)
  3091             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
  3175             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
  3092         DeleteGear(Gear);
  3176         DeleteGear(Gear);
  3093         exit
  3177         exit
  3094         end
  3178         end
  3095 
  3179 
  3096     else if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))) then
  3180     else if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) = 0) then
  3097         begin
  3181         begin
  3098         StopSoundChan(Gear^.SoundChannel);
  3182         StopSoundChan(Gear^.SoundChannel);
  3099         Gear^.Tag := 1;
  3183         Gear^.Tag := 1;
  3100         Gear^.doStep := @doStepDrill
  3184         Gear^.doStep := @doStepDrill
  3101         end;
  3185         end;
  3249 
  3333 
  3250     if Gear^.Timer > 0 then
  3334     if Gear^.Timer > 0 then
  3251         dec(Gear^.Timer);
  3335         dec(Gear^.Timer);
  3252 
  3336 
  3253     fChanged := false;
  3337     fChanged := false;
  3254     if ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then
  3338     if (HHGear = nil) or ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then
  3255         begin
  3339         begin
  3256         fChanged := true;
  3340         fChanged := true;
  3257         if Gear^.Angle > 2048 then
  3341         if Gear^.Angle > 2048 then
  3258             dec(Gear^.Angle)
  3342             dec(Gear^.Angle)
  3259         else if Gear^.Angle < 2048 then
  3343         else if Gear^.Angle < 2048 then
  3294         if Gear^.Timer < 3500 then
  3378         if Gear^.Timer < 3500 then
  3295             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
  3379             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
  3296     else
  3380     else
  3297         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  3381         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  3298 
  3382 
  3299     if ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
  3383     if (HHGear <> nil) and ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
  3300         begin
  3384         begin
  3301         HHGear^.Message := HHGear^.Message and (not gmAttack);
  3385         HHGear^.Message := HHGear^.Message and (not gmAttack);
  3302         AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
  3386         AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
  3303         _0_5, 0);
  3387         _0_5, 0);
  3304         dec(Gear^.Health)
  3388         dec(Gear^.Health)
  3305         end;
  3389         end;
  3306 
  3390 
  3307     if ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
  3391     if (HHGear <> nil) and ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
  3308         begin
  3392         begin
  3309         Gear^.State := Gear^.State or gsttmpFlag;
  3393         Gear^.State := Gear^.State or gsttmpFlag;
  3310         PauseMusic;
  3394         PauseMusic;
  3311         playSound(sndRideOfTheValkyries);
  3395         playSound(sndRideOfTheValkyries);
  3312         end;
  3396         end;
  3469     HHGear^.State := HHGear^.State or gstMoving;
  3553     HHGear^.State := HHGear^.State or gstMoving;
  3470 
  3554 
  3471     Gear^.X := HHGear^.X;
  3555     Gear^.X := HHGear^.X;
  3472     Gear^.Y := HHGear^.Y;
  3556     Gear^.Y := HHGear^.Y;
  3473 
  3557 
  3474     if (not isUnderWater) and hasBorder and ((HHGear^.X < _0)
  3558     if not isUnderWater and hasBorder and ((HHGear^.X < _0)
  3475     or (hwRound(HHGear^.X) > LAND_WIDTH)) then
  3559     or (hwRound(HHGear^.X) > LAND_WIDTH)) then
  3476         HHGear^.dY.isNegative:= false;
  3560         HHGear^.dY.isNegative:= false;
  3477 
  3561 
  3478     if ((Gear^.State and gsttmpFlag) = 0)
  3562     if ((Gear^.State and gsttmpFlag) = 0)
  3479     or (HHGear^.dY < _0) then
  3563     or (HHGear^.dY < _0) then
  3548     move: hwFloat;
  3632     move: hwFloat;
  3549 begin
  3633 begin
  3550     HHGear := Gear^.Hedgehog^.Gear;
  3634     HHGear := Gear^.Hedgehog^.Gear;
  3551     if HHGear = nil then
  3635     if HHGear = nil then
  3552         begin
  3636         begin
  3553         DeleteGear(Gear);
  3637         Gear^.Timer := 0;
       
  3638         Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
       
  3639         Gear^.Timer := 0;
       
  3640         Gear^.doStep := @doStepBirdyDisappear;
       
  3641         CurAmmoGear := nil;
       
  3642         isCursorVisible := false;
       
  3643         AfterAttack;
  3554         exit
  3644         exit
  3555         end;
  3645         end;
  3556 
  3646 
  3557     move := _0_2;
  3647     move := _0_2;
  3558     fuel := 50;
  3648     fuel := 50;
  3650 procedure doStepBirdyDescend(Gear: PGear);
  3740 procedure doStepBirdyDescend(Gear: PGear);
  3651 var
  3741 var
  3652     HHGear: PGear;
  3742     HHGear: PGear;
  3653 begin
  3743 begin
  3654     if Gear^.Timer > 0 then
  3744     if Gear^.Timer > 0 then
  3655         dec(Gear^.Timer, 1)
  3745         dec(Gear^.Timer, 1);
  3656     else if Gear^.Hedgehog^.Gear = nil then
  3746 
  3657         begin
  3747     HHGear := Gear^.Hedgehog^.Gear;
  3658         DeleteGear(Gear);
  3748     if HHGear = nil then
       
  3749         begin
       
  3750         Gear^.Timer := 0;
       
  3751         Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
       
  3752         Gear^.Timer := 0;
       
  3753         Gear^.doStep := @doStepBirdyDisappear;
       
  3754         CurAmmoGear := nil;
       
  3755         isCursorVisible := false;
  3659         AfterAttack;
  3756         AfterAttack;
  3660         exit
  3757         exit
  3661         end;
  3758         end;
  3662     HHGear := Gear^.Hedgehog^.Gear;
  3759 
  3663     HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight));
  3760     HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight));
  3664     if abs(hwRound(HHGear^.Y - Gear^.Y)) > 32 then
  3761     if abs(hwRound(HHGear^.Y - Gear^.Y)) > 32 then
  3665         begin
  3762         begin
  3666         if Gear^.Timer = 0 then
  3763         if Gear^.Timer = 0 then
  3667             Gear^.Y := Gear^.Y + _0_1
  3764             Gear^.Y := Gear^.Y + _0_1
  3722 var
  3819 var
  3723     vg: PVisualGear;
  3820     vg: PVisualGear;
  3724     i: LongInt;
  3821     i: LongInt;
  3725 begin
  3822 begin
  3726     AllInactive := false;
  3823     AllInactive := false;
  3727     {$IFNDEF PAS2C}
       
  3728     Gear^.dX := Gear^.dX;
  3824     Gear^.dX := Gear^.dX;
  3729     {$ENDIF}
       
  3730     doStepFallingGear(Gear);
  3825     doStepFallingGear(Gear);
  3731     //    CheckGearDrowning(Gear); // already checked for in doStepFallingGear
  3826     //    CheckGearDrowning(Gear); // already checked for in doStepFallingGear
  3732     CalcRotationDirAngle(Gear);
  3827     CalcRotationDirAngle(Gear);
  3733 
  3828 
  3734     if (Gear^.State and gstCollision) <> 0 then
  3829     if (Gear^.State and gstCollision) <> 0 then
  3865         iscake:= (iterator^.Kind = gtCake);
  3960         iscake:= (iterator^.Kind = gtCake);
  3866 
  3961 
  3867         // won't port stuff that does not move towards the front/portal entrance
  3962         // won't port stuff that does not move towards the front/portal entrance
  3868         if iscake then
  3963         if iscake then
  3869             begin
  3964             begin
  3870             if (not (((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative)) then
  3965             if not (((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative) then
  3871                 continue;
  3966                 continue;
  3872             end
  3967             end
  3873         else
  3968         else
  3874             if (not ((Gear^.dX*ox + Gear^.dY*oy).isNegative)) then
  3969             if not ((Gear^.dX*ox + Gear^.dY*oy).isNegative) then
  3875                 continue;
  3970                 continue;
  3876 
  3971 
  3877         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]);
  3972         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]);
  3878 
  3973 
  3879         r:= int2hwFloat(iterator^.Radius);
  3974         r:= int2hwFloat(iterator^.Radius);
  3880 
  3975 
  3881         if (not (isbullet or iscake)) then
  3976         if not (isbullet or iscake) then
  3882             begin
  3977             begin
  3883             // wow! good candidate there, let's see if the distance and direction is okay!
  3978             // wow! good candidate there, let's see if the distance and direction is okay!
  3884             if hasdxy then
  3979             if hasdxy then
  3885                 begin
  3980                 begin
  3886                 s := Distance(iterator^.dX, iterator^.dY);
  3981                 s := Distance(iterator^.dX, iterator^.dY);
  3908         // calc gear offset in portal vector direction
  4003         // calc gear offset in portal vector direction
  3909         ox := (iterator^.X - Gear^.X);
  4004         ox := (iterator^.X - Gear^.X);
  3910         oy := (iterator^.Y - Gear^.Y);
  4005         oy := (iterator^.Y - Gear^.Y);
  3911         poffs:= (Gear^.dX * ox + Gear^.dY * oy);
  4006         poffs:= (Gear^.dX * ox + Gear^.dY * oy);
  3912 
  4007 
  3913         if (not isBullet) and poffs.isNegative then
  4008         if not isBullet and poffs.isNegative then
  3914             continue;
  4009             continue;
  3915 
  4010 
  3916         // only port bullets close to the portal
  4011         // only port bullets close to the portal
  3917         if isBullet and (not (hwAbs(poffs) < _3)) then
  4012         if isBullet and (not (hwAbs(poffs) < _3)) then
  3918             continue;
  4013             continue;
  3935         ny := Gear^.dX;
  4030         ny := Gear^.dX;
  3936         // ... decide where the top is based on the hog's direction when firing the portal
  4031         // ... decide where the top is based on the hog's direction when firing the portal
  3937         if Gear^.Elasticity.isNegative then
  4032         if Gear^.Elasticity.isNegative then
  3938             nx.isNegative := (not nx.isNegative)
  4033             nx.isNegative := (not nx.isNegative)
  3939         else
  4034         else
  3940             ny.isNegative := (not ny.isNegative);
  4035             ny.isNegative := not ny.isNegative;
  3941 
  4036 
  3942         // calc gear offset in portal normal vector direction
  4037         // calc gear offset in portal normal vector direction
  3943         noffs:= (nx * ox + ny * oy);
  4038         noffs:= (nx * ox + ny * oy);
  3944 
  4039 
  3945         if isBullet and (noffs.Round >= Longword(Gear^.Radius)) then
  4040         if isBullet and (noffs.Round >= Longword(Gear^.Radius)) then
  3946             continue;
  4041             continue;
  3947 
  4042 
  3948         // avoid gravity related loops of not really moving gear
  4043         // avoid gravity related loops of not really moving gear
  3949         if (not (iscake or isbullet))
  4044         if not (iscake or isbullet)
  3950         and (Gear^.dY.isNegative)
  4045         and (Gear^.dY.isNegative)
  3951         and (conPortal^.dY.isNegative)
  4046         and (conPortal^.dY.isNegative)
  3952         and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue)
  4047         and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue)
  3953         and (iterator^.PortalCounter > 0) then
  4048         and (iterator^.PortalCounter > 0) then
  3954             continue;
  4049             continue;
  3969         nx := conPortal^.dY;
  4064         nx := conPortal^.dY;
  3970         ny := conPortal^.dX;
  4065         ny := conPortal^.dX;
  3971         if conPortal^.Elasticity.isNegative then
  4066         if conPortal^.Elasticity.isNegative then
  3972             nx.isNegative := (not nx.isNegative)
  4067             nx.isNegative := (not nx.isNegative)
  3973         else
  4068         else
  3974             ny.isNegative := (not ny.isNegative);
  4069             ny.isNegative := not ny.isNegative;
  3975 
  4070 
  3976         // inverse cake's normal movement direction,
  4071         // inverse cake's normal movement direction,
  3977         // as if it just walked through a hole
  4072         // as if it just walked through a hole
  3978         //if iscake then nspeed.isNegative:= not nspeed.isNegative;
  4073         //if iscake then nspeed.isNegative:= not nspeed.isNegative;
  3979 
  4074 
  4005             end;
  4100             end;
  4006 
  4101 
  4007         iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx;
  4102         iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx;
  4008         iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny;
  4103         iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny;
  4009 
  4104 
  4010         if (not hasdxy) and (not (conPortal^.dY.isNegative)) then
  4105         if not hasdxy and (not (conPortal^.dY.isNegative)) then
  4011             begin
  4106             begin
  4012             iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y))
  4107             iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y))
  4013             end;
  4108             end;
  4014 
  4109 
  4015         // see if the space on the exit side actually is enough
  4110         // see if the space on the exit side actually is enough
  4016 
  4111 
  4017         if (not (isBullet or isCake)) then
  4112         if not (isBullet or isCake) then
  4018             begin
  4113             begin
  4019             // TestCollisionXwithXYShift requires a hwFloat for xShift
  4114             // TestCollisionXwithXYShift requires a hwFloat for xShift
  4020             ox.QWordValue := _1.QWordValue;
  4115             ox.QWordValue := _1.QWordValue;
  4021             ox.isNegative := not iterator^.dX.isNegative;
  4116             ox.isNegative := not iterator^.dX.isNegative;
  4022 
  4117 
  4025 
  4120 
  4026             if iterator^.Radius > 1 then
  4121             if iterator^.Radius > 1 then
  4027                 iterator^.Radius := iterator^.Radius - 1;
  4122                 iterator^.Radius := iterator^.Radius - 1;
  4028 
  4123 
  4029             // check front
  4124             // check front
  4030             isCollision := TestCollisionY(iterator, sy)
  4125             isCollision := (TestCollisionY(iterator, sy) <> 0) or (TestCollisionX(iterator, sx) <> 0);
  4031                         or TestCollisionX(iterator, sx);
  4126 
  4032 
  4127             if not isCollision then
  4033             if (not isCollision) then
       
  4034                 begin
  4128                 begin
  4035                 // check center area (with half the radius so that the
  4129                 // check center area (with half the radius so that the
  4036                 // the square check won't check more pixels than we want to)
  4130                 // the square check won't check more pixels than we want to)
  4037                 iterator^.Radius := 1 + resetr div 2;
  4131                 iterator^.Radius := 1 + resetr div 2;
  4038                 rh := resetr div 4;
  4132                 rh := resetr div 4;
  4039                 isCollision := TestCollisionYwithXYShift(iterator,       0, -sy * rh, sy, false)
  4133                 isCollision := (TestCollisionYwithXYShift(iterator,       0, -sy * rh, sy, false) <> 0)
  4040                             or TestCollisionXwithXYShift(iterator, ox * rh,        0, sx, false);
  4134                             or (TestCollisionXwithXYShift(iterator, ox * rh,        0, sx, false) <> 0);
  4041                 end;
  4135                 end;
  4042 
  4136 
  4043             iterator^.Radius := resetr;
  4137             iterator^.Radius := resetr;
  4044 
  4138 
  4045             if isCollision then
  4139             if isCollision then
  4080             resetdx.QWordValue:= 4294967296 * 1152;
  4174             resetdx.QWordValue:= 4294967296 * 1152;
  4081 
  4175 
  4082             resetdy:=hwAbs(iterator^.dX*4);
  4176             resetdy:=hwAbs(iterator^.dX*4);
  4083             resetdy:= resetdy + hwPow(resetdy,3)/_6 + _3 * hwPow(resetdy,5) / _40 + _5 * hwPow(resetdy,7) / resety + resetx * hwPow(resetdy,9) / resetdx;
  4177             resetdy:= resetdy + hwPow(resetdy,3)/_6 + _3 * hwPow(resetdy,5) / _40 + _5 * hwPow(resetdy,7) / resety + resetx * hwPow(resetdy,9) / resetdx;
  4084             iterator^.Angle:= hwRound(resetdy*_2048 / _PI);
  4178             iterator^.Angle:= hwRound(resetdy*_2048 / _PI);
  4085             if (not iterator^.dY.isNegative) then iterator^.Angle:= 2048-iterator^.Angle;
  4179             if not iterator^.dY.isNegative then iterator^.Angle:= 2048-iterator^.Angle;
  4086             if iterator^.dX.isNegative then iterator^.Angle:= 4096-iterator^.Angle;
  4180             if iterator^.dX.isNegative then iterator^.Angle:= 4096-iterator^.Angle;
  4087             end
  4181             end
  4088         // VISUAL USE OF ANGLE ONLY
  4182         // VISUAL USE OF ANGLE ONLY
  4089         else if (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtKamikaze) and (CurAmmoGear^.Hedgehog = iterator^.Hedgehog) then
  4183         else if (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtKamikaze) and (CurAmmoGear^.Hedgehog = iterator^.Hedgehog) then
  4090             begin
  4184             begin
  4094             end;
  4188             end;
  4095 
  4189 
  4096         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
  4190         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
  4097         and (iterator = CurrentHedgehog^.Gear)
  4191         and (iterator = CurrentHedgehog^.Gear)
  4098         and (CurAmmoGear <> nil)
  4192         and (CurAmmoGear <> nil)
  4099         and (CurAmmoGear^.Kind =gtRope) then
  4193         and (CurAmmoGear^.Kind = gtRope)
       
  4194         and (CurAmmoGear^.Elasticity <> _0) then
  4100                CurAmmoGear^.PortalCounter:= 1;
  4195                CurAmmoGear^.PortalCounter:= 1;
  4101 
  4196 
  4102         if (not isbullet) and (iterator^.State and gstInvisible = 0)
  4197         if not isbullet and (iterator^.State and gstInvisible = 0)
  4103         and (iterator^.Kind <> gtFlake) then
  4198         and (iterator^.Kind <> gtFlake) then
  4104             FollowGear := iterator;
  4199             FollowGear := iterator;
  4105 
  4200 
  4106         // store X/Y values of exit for net bullet trail
  4201         // store X/Y values of exit for net bullet trail
  4107         if isbullet then
  4202         if isbullet then
  4160         begin
  4255         begin
  4161         Gear^.State := Gear^.State or gstCollision;
  4256         Gear^.State := Gear^.State or gstCollision;
  4162         Gear^.State := Gear^.State and (not gstMoving);
  4257         Gear^.State := Gear^.State and (not gstMoving);
  4163 
  4258 
  4164         if (Land[y, x] and lfBouncy <> 0)
  4259         if (Land[y, x] and lfBouncy <> 0)
  4165         or (not (CalcSlopeTangent(Gear, x, y, tx, ty, 255)))
  4260         or (not CalcSlopeTangent(Gear, x, y, tx, ty, 255))
  4166         or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
  4261         or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
  4167             begin
  4262             begin
  4168             loadNewPortalBall(Gear, true);
  4263             loadNewPortalBall(Gear, true);
  4169             EXIT;
  4264             EXIT;
  4170             end;
  4265             end;
  4173         s := _1/DistanceI(tx,ty);
  4268         s := _1/DistanceI(tx,ty);
  4174         Gear^.dX :=  s * ty;
  4269         Gear^.dX :=  s * ty;
  4175         Gear^.dY := -s * tx;
  4270         Gear^.dY := -s * tx;
  4176 
  4271 
  4177         Gear^.DirAngle := DxDy2Angle(-Gear^.dY,Gear^.dX);
  4272         Gear^.DirAngle := DxDy2Angle(-Gear^.dY,Gear^.dX);
  4178         if (not Gear^.dX.isNegative) then
  4273         if not Gear^.dX.isNegative then
  4179             Gear^.DirAngle := 180-Gear^.DirAngle;
  4274             Gear^.DirAngle := 180-Gear^.DirAngle;
  4180 
  4275 
  4181         if ((Gear^.LinkedGear = nil)
  4276         if ((Gear^.LinkedGear = nil)
  4182         or (hwRound(Distance(Gear^.X - Gear^.LinkedGear^.X,Gear^.Y-Gear^.LinkedGear^.Y)) >=Gear^.Radius*2)) then
  4277         or (hwRound(Distance(Gear^.X - Gear^.LinkedGear^.X,Gear^.Y-Gear^.LinkedGear^.Y)) >=Gear^.Radius*2)) then
  4183             begin
  4278             begin
  4263                 begin
  4358                 begin
  4264                 // This jiggles gears, to ensure a portal connection just placed under a gear takes effect.
  4359                 // This jiggles gears, to ensure a portal connection just placed under a gear takes effect.
  4265                 iterator:= GearsList;
  4360                 iterator:= GearsList;
  4266                 while iterator <> nil do
  4361                 while iterator <> nil do
  4267                     begin
  4362                     begin
  4268                     if (not (iterator^.Kind in [gtPortal, gtAirAttack, gtKnife])) and ((iterator^.Hedgehog <> CurrentHedgehog)
  4363                     if not (iterator^.Kind in [gtPortal, gtAirAttack, gtKnife]) and ((iterator^.Hedgehog <> CurrentHedgehog)
  4269                     or ((iterator^.Message and gmAllStoppable) = 0)) then
  4364                     or ((iterator^.Message and gmAllStoppable) = 0)) then
  4270                             begin
  4365                             begin
  4271                             iterator^.Active:= true;
  4366                             iterator^.Active:= true;
  4272                             if iterator^.dY.QWordValue = 0 then
  4367                             if iterator^.dY.QWordValue = 0 then
  4273                                 iterator^.dY.isNegative:= false;
  4368                                 iterator^.dY.isNegative:= false;
  4518     AmmoShove(Gear, 0, 80);
  4613     AmmoShove(Gear, 0, 80);
  4519     Gear^.dX.isNegative := not Gear^.dX.isNegative;
  4614     Gear^.dX.isNegative := not Gear^.dX.isNegative;
  4520     Gear^.dY.isNegative := not Gear^.dY.isNegative;
  4615     Gear^.dY.isNegative := not Gear^.dY.isNegative;
  4521 
  4616 
  4522     Gear^.doStep := @doStepSineGunShotWork;
  4617     Gear^.doStep := @doStepSineGunShotWork;
  4523     {$IFNDEF PAS2C}
       
  4524     with mobileRecord do
  4618     with mobileRecord do
  4525         if (performRumble <> nil) and (not fastUntilLag) then
  4619         if (performRumble <> nil) and (not fastUntilLag) then
  4526             performRumble(kSystemSoundID_Vibrate);
  4620             performRumble(kSystemSoundID_Vibrate);
  4527     {$ENDIF}
       
  4528 end;
  4621 end;
  4529 
  4622 
  4530 ////////////////////////////////////////////////////////////////////////////////
  4623 ////////////////////////////////////////////////////////////////////////////////
  4531 procedure doStepFlamethrowerWork(Gear: PGear);
  4624 procedure doStepFlamethrowerWork(Gear: PGear);
  4532 var
  4625 var
  4703     Gear^.Y:= Gear^.Y + Gear^.dY;
  4796     Gear^.Y:= Gear^.Y + Gear^.dY;
  4704     Gear^.dX := Gear^.dX + cWindSpeed / 4;
  4797     Gear^.dX := Gear^.dX + cWindSpeed / 4;
  4705     Gear^.dY := Gear^.dY + cGravity / 100;
  4798     Gear^.dY := Gear^.dY + cGravity / 100;
  4706     if (GameTicks and $FF) = 0 then
  4799     if (GameTicks and $FF) = 0 then
  4707         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx or EXPLNoDamage or EXPLDoNotTouchAny or EXPLPoisoned);
  4800         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx or EXPLNoDamage or EXPLDoNotTouchAny or EXPLPoisoned);
  4708     AllInactive:= false;
  4801     if Gear^.State and gstTmpFlag = 0 then
       
  4802         AllInactive:= false;
  4709 end;
  4803 end;
  4710 
  4804 
  4711 ////////////////////////////////////////////////////////////////////////////////
  4805 ////////////////////////////////////////////////////////////////////////////////
  4712 procedure doStepHammer(Gear: PGear);
  4806 procedure doStepHammer(Gear: PGear);
  4713 var HHGear, tmp, tmp2: PGear;
  4807 var HHGear, tmp, tmp2: PGear;
  4730     tmp:= t^.ar[i];
  4824     tmp:= t^.ar[i];
  4731     if (tmp^.State and gstNoDamage) = 0 then
  4825     if (tmp^.State and gstNoDamage) = 0 then
  4732         if (tmp^.Kind = gtHedgehog) or (tmp^.Kind = gtMine) or (tmp^.Kind = gtExplosives) then
  4826         if (tmp^.Kind = gtHedgehog) or (tmp^.Kind = gtMine) or (tmp^.Kind = gtExplosives) then
  4733             begin
  4827             begin
  4734             //tmp^.State:= tmp^.State or gstFlatened;
  4828             //tmp^.State:= tmp^.State or gstFlatened;
  4735             if not tmp^.Invulnerable then
  4829             if (tmp^.Hedgehog^.Effects[heInvulnerable] = 0) then
  4736                 ApplyDamage(tmp, CurrentHedgehog, tmp^.Health div 3, dsUnknown);
  4830                 ApplyDamage(tmp, CurrentHedgehog, tmp^.Health div 3, dsUnknown);
  4737             //DrawTunnel(tmp^.X, tmp^.Y - _1, _0, _0_5, cHHRadius * 6, cHHRadius * 3);
  4831             //DrawTunnel(tmp^.X, tmp^.Y - _1, _0, _0_5, cHHRadius * 6, cHHRadius * 3);
  4738             tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0);
  4832             tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0);
  4739             tmp2^.LinkedGear:= tmp;
  4833             tmp2^.LinkedGear:= tmp;
  4740             SetAllToActive
  4834             SetAllToActive
  5071             begin
  5165             begin
  5072             t:= GearsList;
  5166             t:= GearsList;
  5073             while t <> nil do
  5167             while t <> nil do
  5074                 begin
  5168                 begin
  5075                 if (t^.Kind = gtHedgehog) and (t^.Hedgehog^.Team^.Clan = HH^.Team^.Clan) then
  5169                 if (t^.Kind = gtHedgehog) and (t^.Hedgehog^.Team^.Clan = HH^.Team^.Clan) then
  5076                     t^.Invulnerable:= true;
  5170                     t^.Hedgehog^.Effects[heInvulnerable]:= 1;
  5077                 t:= t^.NextGear;
  5171                 t:= t^.NextGear;
  5078                 end;
  5172                 end;
  5079             end;
  5173             end;
  5080 
  5174 
  5081     if Gear^.Health <= 0 then
  5175     if Gear^.Health <= 0 then
  5385                     Y:= HHGear^.Y
  5479                     Y:= HHGear^.Y
  5386                     end;
  5480                     end;
  5387 
  5481 
  5388                 if (Timer = iceCollideWithGround) and ((GameTicks - Power) > groundFreezingTime) then
  5482                 if (Timer = iceCollideWithGround) and ((GameTicks - Power) > groundFreezingTime) then
  5389                     begin
  5483                     begin
  5390                     FillRoundInLand2(target.x, target.y, iceRadius, icePixel);
  5484                     FillRoundInLandFT(target.x, target.y, iceRadius, icePixel);
  5391                     landRect.x := min(max(target.x - iceRadius, 0), LAND_WIDTH - 1);
  5485                     landRect.x := min(max(target.x - iceRadius, 0), LAND_WIDTH - 1);
  5392                     landRect.y := min(max(target.y - iceRadius, 0), LAND_HEIGHT - 1);
  5486                     landRect.y := min(max(target.y - iceRadius, 0), LAND_HEIGHT - 1);
  5393                     landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1);
  5487                     landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1);
  5394                     landRect.h := min(2*iceRadius, LAND_HEIGHT - landRect.y - 1);
  5488                     landRect.h := min(2*iceRadius, LAND_HEIGHT - landRect.y - 1);
  5395                     UpdateLandTexture(landRect.x, landRect.w, landRect.y, landRect.h, true);
  5489                     UpdateLandTexture(landRect.x, landRect.w, landRect.y, landRect.h, true);
  5398                     iter := GearsList;
  5492                     iter := GearsList;
  5399                     while iter <> nil do
  5493                     while iter <> nil do
  5400                         begin
  5494                         begin
  5401                         if (iter^.State and gstFrozen = 0) and
  5495                         if (iter^.State and gstFrozen = 0) and
  5402                            ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine)) and 
  5496                            ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine)) and 
  5403                            (Distance(iter^.X-int2hwFloat(target.x),iter^.Y-int2hwFloat(target.y))<int2hwFloat(iceRadius*2)) then
  5497                            (abs(iter^.X.Round-target.x)+abs(iter^.Y.Round-target.y)+2<2*iceRadius) and (Distance(iter^.X-int2hwFloat(target.x),iter^.Y-int2hwFloat(target.y))<int2hwFloat(iceRadius*2)) then
  5404                             begin
  5498                             begin
  5405                             for t:= 0 to 5 do
  5499                             for t:= 0 to 5 do
  5406                                 begin
  5500                                 begin
  5407                                 vg:= AddVisualGear(hwRound(iter^.X)+random(4)-8, hwRound(iter^.Y)+random(8), vgtDust, 1);
  5501                                 vg:= AddVisualGear(hwRound(iter^.X)+random(4)-8, hwRound(iter^.Y)+random(8), vgtDust, 1);
  5408                                 if vg <> nil then
  5502                                 if vg <> nil then
  5440                             end;
  5534                             end;
  5441                         iter:= iter^.NextGear
  5535                         iter:= iter^.NextGear
  5442                         end;
  5536                         end;
  5443 
  5537 
  5444                     // FillRoundInLandWithIce(Target.X, Target.Y, iceRadius);
  5538                     // FillRoundInLandWithIce(Target.X, Target.Y, iceRadius);
  5445                     SetAllHHToActive(true);
  5539                     SetAllHHToActive;
  5446                     Timer := iceWaitCollision;
  5540                     Timer := iceWaitCollision;
  5447                     end;
  5541                     end;
  5448 
  5542 
  5449                 if (Timer = iceCollideWithWater) and ((GameTicks - Power) > groundFreezingTime) then
  5543                 if (Timer = iceCollideWithWater) and ((GameTicks - Power) > groundFreezingTime) then
  5450                     begin
  5544                     begin
  5451                     PlaySound(sndHogFreeze);
  5545                     PlaySound(sndHogFreeze);
  5452                     DrawIceBreak(Target.X, cWaterLine - iceHeight, iceRadius, iceHeight);
  5546                     DrawIceBreak(Target.X, cWaterLine - iceHeight, iceRadius, iceHeight);
  5453                     SetAllHHToActive(true);
  5547                     SetAllHHToActive;
  5454                     Timer := iceWaitCollision;
  5548                     Timer := iceWaitCollision;
  5455                     end;
  5549                     end;
  5456 (*
  5550 (*
  5457  Any ideas for something that would look good here?
  5551  Any ideas for something that would look good here?
  5458                 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
  5552                 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
  5525     gi := GearsList;
  5619     gi := GearsList;
  5526     while gi <> nil do
  5620     while gi <> nil do
  5527         begin
  5621         begin
  5528         with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac;
  5622         with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac;
  5529         AddRandomness(CheckSum);
  5623         AddRandomness(CheckSum);
  5530         if gi^.Kind = gtGenericFaller then gi^.State:= gi^.State and (not gstTmpFlag);
  5624         if gi^.Kind = gtGenericFaller then gi^.State:= gi^.State and not gstTmpFlag;
  5531         gi := gi^.NextGear
  5625         gi := gi^.NextGear
  5532         end;
  5626         end;
  5533     AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y));
  5627     AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y));
  5534     DeleteGear(Gear)
  5628     DeleteGear(Gear)
  5535     end;
  5629     end;
  5591     exit
  5685     exit
  5592     end;
  5686     end;
  5593 
  5687 
  5594 // 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
  5688 // 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
  5595 if (HHGear = nil) or (Gear^.Timer = 0) or
  5689 if (HHGear = nil) or (Gear^.Timer = 0) or
  5596    (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle))
  5690    (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) >  Gear^.Angle) and
       
  5691         (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle)))
  5597     then
  5692     then
  5598     begin
  5693     begin
  5599     hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Angle);
  5694     hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Angle);
  5600     if hogs.size > 1 then
  5695     if hogs.size > 1 then
  5601         Gear^.Hedgehog:= hogs.ar^[GetRandom(hogs.size)]^.Hedgehog
  5696         Gear^.Hedgehog:= hogs.ar^[GetRandom(hogs.size)]^.Hedgehog
  5624         end
  5719         end
  5625     else if (GameTicks and $FF = 0) then
  5720     else if (GameTicks and $FF = 0) then
  5626         begin
  5721         begin
  5627         tdX:= HHGear^.X-Gear^.X;
  5722         tdX:= HHGear^.X-Gear^.X;
  5628         dir:= hwSign(tdX);
  5723         dir:= hwSign(tdX);
  5629         if (not TestCollisionX(Gear, dir)) then
  5724         if TestCollisionX(Gear, dir) = 0 then
  5630             Gear^.X:= Gear^.X + signAs(_1,tdX);
  5725             Gear^.X:= Gear^.X + signAs(_1,tdX);
  5631         if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) then
  5726         if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) <> 0 then
  5632             begin
  5727             begin
  5633             Gear^.dX:= SignAs(_0_15, tdX);
  5728             Gear^.dX:= SignAs(_0_15, tdX);
  5634             Gear^.dY:= -_0_3;
  5729             Gear^.dY:= -_0_3;
  5635             Gear^.State:= Gear^.State or gstMoving
  5730             Gear^.State:= Gear^.State or gstMoving
  5636             end
  5731             end
  5665         end
  5760         end
  5666     else if (Gear^.CollisionIndex = -1) and (Gear^.Timer = 0) then
  5761     else if (Gear^.CollisionIndex = -1) and (Gear^.Timer = 0) then
  5667         begin
  5762         begin
  5668         (*ox:= 0; oy:= 0;
  5763         (*ox:= 0; oy:= 0;
  5669         if TestCollisionYwithGear(Gear, -1) <> 0 then oy:= -1;
  5764         if TestCollisionYwithGear(Gear, -1) <> 0 then oy:= -1;
  5670         if TestCollisionXwithGear(Gear, 1)       then ox:=  1;
  5765         if TestCollisionXwithGear(Gear, 1)  <> 0 then ox:=  1;
  5671         if TestCollisionXwithGear(Gear, -1)      then ox:= -1;
  5766         if TestCollisionXwithGear(Gear, -1) <> 0 then ox:= -1;
  5672         if TestCollisionYwithGear(Gear, 1) <> 0  then oy:=  1;
  5767         if TestCollisionYwithGear(Gear, 1)  <> 0 then oy:=  1;
  5673         if Gear^.Health > 0 then
  5768         if Gear^.Health > 0 then
  5674             PlaySound(sndRopeAttach);
  5769             PlaySound(sndRopeAttach);
  5675 
  5770 
  5676         la:= _10000;
  5771         la:= _10000;
  5677         if (ox <> 0) or (oy <> 0) then
  5772         if (ox <> 0) or (oy <> 0) then
  5696         Gear^.Timer:= 500;
  5791         Gear^.Timer:= 500;
  5697         AddCI(Gear)
  5792         AddCI(Gear)
  5698         end
  5793         end
  5699     else if GameTicks and $3F = 0 then
  5794     else if GameTicks and $3F = 0 then
  5700         begin
  5795         begin
  5701         if  (TestCollisionYwithGear(Gear, -1) = 0)
  5796         if  (TestCollisionYwithGear(Gear,-1) = 0)
  5702         and (not (TestCollisionXwithGear(Gear, 1)))
  5797         and (TestCollisionXwithGear(Gear, 1) = 0)
  5703         and (not (TestCollisionXwithGear(Gear, -1)))
  5798         and (TestCollisionXwithGear(Gear,-1) = 0)
  5704         and (TestCollisionYwithGear(Gear, 1) = 0) then Gear^.State:= Gear^.State and (not gstCollision) or gstMoving;
  5799         and (TestCollisionYwithGear(Gear, 1) = 0) then Gear^.State:= Gear^.State and (not gstCollision) or gstMoving;
  5705         end
  5800         end
  5706 end;
  5801 end;
  5707 (*
  5802 (*
  5708  This didn't end up getting used, but, who knows, might be reasonable for javellin or something
  5803  This didn't end up getting used, but, who knows, might be reasonable for javellin or something