hedgewars/GSHandlers.inc
changeset 3454 a9bef74bd6e0
parent 3440 dee31c5149e0
child 3455 f33e7ad2261c
equal deleted inserted replaced
3453:d65657c94bb9 3454:a9bef74bd6e0
    15  * along with this program; if not, write to the Free Software
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    17  *)
    17  *)
    18 
    18 
    19 procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
    19 procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
    20 var gi: PGear;
    20 var 
    21      d: LongInt;
    21     gi: PGear;
    22 begin
    22     d: LongInt;
    23     gi:= GearsList;
    23 begin
       
    24     gi := GearsList;
    24     while gi <> nil do
    25     while gi <> nil do
    25         begin
    26     begin
    26         if (gi^.Kind = gtHedgehog) then
    27         if (gi^.Kind = gtHedgehog) then
       
    28         begin
       
    29             d := r - hwRound(Distance(gi^.X - x, gi^.Y - y));
       
    30             if (d > 1) and not gi^.Invulnerable and (GetRandom(2) = 0) then
    27             begin
    31             begin
    28             d:= r - hwRound(Distance(gi^.X - x, gi^.Y - y));
       
    29             if (d > 1) and not gi^.Invulnerable and (GetRandom(2) = 0) then
       
    30                 begin
       
    31                 if (CurrentHedgehog^.Gear = gi) then
    32                 if (CurrentHedgehog^.Gear = gi) then
    32                     PlaySound(sndOops, PHedgehog(gi^.Hedgehog)^.Team^.voicepack)
    33                     PlaySound(sndOops, PHedgehog(gi^.Hedgehog)^.Team^.voicepack)
    33                 else
    34                 else
    34                     begin
    35                 begin
    35                     if (gi^.State and gstMoving) = 0 then
    36                     if (gi^.State and gstMoving) = 0 then
    36                         gi^.State:= gi^.State or gstLoser;
    37                         gi^.State := gi^.State or gstLoser;
    37                     if d > r div 2 then
    38                     if d > r div 2 then
    38                         PlaySound(sndNooo, PHedgehog(gi^.Hedgehog)^.Team^.voicepack)
    39                         PlaySound(sndNooo, PHedgehog(gi^.Hedgehog)^.Team^.voicepack)
    39                     else
    40                     else
    40                         PlaySound(sndUhOh, PHedgehog(gi^.Hedgehog)^.Team^.voicepack);
    41                         PlaySound(sndUhOh, PHedgehog(gi^.Hedgehog)^.Team^.voicepack);
    41                     end;
       
    42                 end;
    42                 end;
    43             end;
    43             end;
    44         gi:= gi^.NextGear
    44         end;
    45         end;
    45         gi := gi^.NextGear
    46 end;
    46     end;
    47 ////////////////////////////////////////////////////////////////////////////////
    47 end;
    48 procedure doStepDrowningGear(Gear: PGear); forward;
    48 ////////////////////////////////////////////////////////////////////////////////
       
    49 procedure doStepDrowningGear(Gear: PGear);
       
    50 forward;
    49 
    51 
    50 function CheckGearDrowning(Gear: PGear): boolean;
    52 function CheckGearDrowning(Gear: PGear): boolean;
    51 var skipSpeed, skipAngle, skipDecay: hwFloat;
    53 var 
       
    54     skipSpeed, skipAngle, skipDecay: hwFloat;
    52     i, maxDrops: LongInt;
    55     i, maxDrops: LongInt;
    53     particle: PVisualGear;
    56     particle: PVisualGear;
    54 begin
    57 begin
    55 // probably needs tweaking. might need to be in a case statement based upon gear type
    58     // probably needs tweaking. might need to be in a case statement based upon gear type
    56 if cWaterLine < hwRound(Gear^.Y) + Gear^.Radius then
    59     if cWaterLine < hwRound(Gear^.Y) + Gear^.Radius then
    57     begin
    60     begin
    58     skipSpeed:= _0_25;
    61         skipSpeed := _0_25;
    59     skipAngle:= _1_9;  
    62         skipAngle := _1_9;
    60     skipDecay:= _0_87;  // this could perhaps be a tiny bit higher.
    63         skipDecay := _0_87;
    61     if  (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed) and
    64         // this could perhaps be a tiny bit higher.
    62         (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)) then
    65         if  (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed) and
    63        begin
    66            (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)) then
    64        Gear^.dY.isNegative:= true;
    67         begin
    65        Gear^.dY:= Gear^.dY * skipDecay;
    68             Gear^.dY.isNegative := true;
    66        Gear^.dX:= Gear^.dX * skipDecay;
    69             Gear^.dY := Gear^.dY * skipDecay;
    67        CheckGearDrowning:= false;
    70             Gear^.dX := Gear^.dX * skipDecay;
    68        PlaySound(sndSkip)
    71             CheckGearDrowning := false;
    69        end
    72             PlaySound(sndSkip)
    70     else
    73         end
    71         begin
    74         else
    72         CheckGearDrowning:= true;
    75         begin
    73         Gear^.State:= gstDrowning;
    76             CheckGearDrowning := true;
    74         Gear^.RenderTimer:= false;
    77             Gear^.State := gstDrowning;
    75         if (Gear^.Kind <> gtSniperRifleShot) and (Gear^.Kind <> gtShotgunShot) and (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot) then
    78             Gear^.RenderTimer := false;
    76           Gear^.doStep:= @doStepDrowningGear;
    79             if (Gear^.Kind <> gtSniperRifleShot) and (Gear^.Kind <> gtShotgunShot) and (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot) then
    77         if Gear^.Kind = gtHedgehog then
    80                 Gear^.doStep := @doStepDrowningGear;
       
    81             if Gear^.Kind = gtHedgehog then
    78             begin
    82             begin
    79             Gear^.State:= Gear^.State and (not gstHHDriven);
    83                 Gear^.State := Gear^.State and (not gstHHDriven);
    80             AddCaption(Format(GetEventString(eidDrowned), PHedgehog(Gear^.Hedgehog)^.Name), cWhiteColor, capgrpMessage);
    84                 AddCaption(Format(GetEventString(eidDrowned), PHedgehog(Gear^.Hedgehog)^.Name),
       
    85                 cWhiteColor, capgrpMessage);
    81             end;
    86             end;
    82         if hwRound(Gear^.Y) < cWaterLine + 64 + Gear^.Radius then // don't play splash if they are already way past the surface
    87             if hwRound(Gear^.Y) < cWaterLine + 64 + Gear^.Radius then
    83             PlaySound(sndSplash)
    88                 // don't play splash if they are already way past the surface
    84         end;
    89                 PlaySound(sndSplash)
    85     
    90         end;
    86     if not cReducedQuality and (hwRound(Gear^.Y) < cWaterLine + 64 + Gear^.Radius) then 
    91 
    87         begin
    92         if not cReducedQuality and (hwRound(Gear^.Y) < cWaterLine + 64 + Gear^.Radius) then
    88         AddVisualGear(hwRound(Gear^.X), cWaterLine, vgtSplash);
    93         begin
    89        
    94             AddVisualGear(hwRound(Gear^.X), cWaterLine, vgtSplash);
    90         maxDrops := (Gear^.Radius div 2) + hwRound(Gear^.dX * Gear^.Radius * 2) + hwRound(Gear^.dY * Gear^.Radius * 2);
    95 
    91         for i:= max(maxDrops div 3, min(32, Random(maxDrops))) downto 0 do 
    96             maxDrops := (Gear^.Radius div 2) + hwRound(Gear^.dX * Gear^.Radius * 2) + hwRound(Gear^.
       
    97                         dY * Gear^.Radius * 2);
       
    98             for i:= max(maxDrops div 3, min(32, Random(maxDrops))) downto 0 do
    92             begin
    99             begin
    93             particle := AddVisualGear(hwRound(Gear^.X) - 3 + Random(6), cWaterLine, vgtDroplet);
   100                 particle := AddVisualGear(hwRound(Gear^.X) - 3 + Random(6), cWaterLine, vgtDroplet);
    94             if particle <> nil then
   101                 if particle <> nil then
    95                 begin
   102                 begin
    96                 particle^.dX := particle^.dX - (Gear^.dX / 10);
   103                     particle^.dX := particle^.dX - (Gear^.dX / 10);
    97                 particle^.dY := particle^.dY - (Gear^.dY / 5)
   104                     particle^.dY := particle^.dY - (Gear^.dY / 5)
    98                 end
   105                 end
    99             end
   106             end
   100         end;
   107         end;
   101     end
   108     end
   102 else
   109     else
   103     CheckGearDrowning:= false
   110         CheckGearDrowning := false
   104 end;
   111 end;
   105 
   112 
   106 procedure CheckCollision(Gear: PGear);
   113 procedure CheckCollision(Gear: PGear);
   107 begin
   114 begin
   108 if TestCollisionXwithGear(Gear, hwSign(Gear^.X)) or TestCollisionYwithGear(Gear, hwSign(Gear^.Y))
   115     if TestCollisionXwithGear(Gear, hwSign(Gear^.X)) or TestCollisionYwithGear(Gear, hwSign(Gear^.Y)
   109     then Gear^.State:= Gear^.State or      gstCollision
   116        )
   110     else Gear^.State:= Gear^.State and not gstCollision
   117         then Gear^.State := Gear^.State or      gstCollision
       
   118     else Gear^.State := Gear^.State and not gstCollision
   111 end;
   119 end;
   112 
   120 
   113 procedure CheckHHDamage(Gear: PGear);
   121 procedure CheckHHDamage(Gear: PGear);
   114 var 
   122 var 
   115     dmg: Longword;
   123     dmg: Longword;
   116     i: LongInt;
   124     i: LongInt;
   117     particle: PVisualGear;
   125     particle: PVisualGear;
   118 begin
   126 begin
   119 if _0_4 < Gear^.dY then
   127     if _0_4 < Gear^.dY then
   120     begin
   128     begin
   121     dmg:= ModifyDamage(1 + hwRound((hwAbs(Gear^.dY) - _0_4) * 70), Gear);
   129         dmg := ModifyDamage(1 + hwRound((hwAbs(Gear^.dY) - _0_4) * 70), Gear);
   122     if dmg < 1 then exit;
   130         if dmg < 1 then exit;
   123 
   131 
   124     for i:= min(12, (3 + dmg div 10)) downto 0 do begin
   132         for i:= min(12, (3 + dmg div 10)) downto 0 do
   125         particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
   133         begin
   126         if particle <> nil then particle^.dX := particle^.dX + (Gear^.dX / 5);
   134             particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12,
   127         end;
   135                         vgtDust);
   128 
   136             if particle <> nil then particle^.dX := particle^.dX + (Gear^.dX / 5);
   129     if(Gear^.Invulnerable) then exit;
   137         end;
   130 
   138 
   131     if _0_6 < Gear^.dY then
   139         if (Gear^.Invulnerable) then exit;
   132         PlaySound(sndOw4, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
   140 
       
   141         if _0_6 < Gear^.dY then
       
   142             PlaySound(sndOw4, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
       
   143         else
       
   144             PlaySound(sndOw1, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
       
   145 
       
   146         ApplyDamage(Gear, dmg);
       
   147     end
       
   148 end;
       
   149 
       
   150 ////////////////////////////////////////////////////////////////////////////////
       
   151 ////////////////////////////////////////////////////////////////////////////////
       
   152 procedure CalcRotationDirAngle(Gear: PGear);
       
   153 var 
       
   154     dAngle: real;
       
   155 begin
       
   156     dAngle := (Gear^.dX.QWordValue + Gear^.dY.QWordValue) / $80000000;
       
   157     if not Gear^.dX.isNegative then
       
   158         Gear^.DirAngle := Gear^.DirAngle + dAngle
   133     else
   159     else
   134         PlaySound(sndOw1, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
   160         Gear^.DirAngle := Gear^.DirAngle - dAngle;
   135 
   161 
   136     ApplyDamage(Gear, dmg);
   162     if Gear^.DirAngle < 0 then Gear^.DirAngle := Gear^.DirAngle + 360
   137     end
   163     else if 360 < Gear^.DirAngle then Gear^.DirAngle := Gear^.DirAngle - 360
   138 end;
       
   139 
       
   140 ////////////////////////////////////////////////////////////////////////////////
       
   141 ////////////////////////////////////////////////////////////////////////////////
       
   142 procedure CalcRotationDirAngle(Gear: PGear);
       
   143 var dAngle: real;
       
   144 begin
       
   145 dAngle:= (Gear^.dX.QWordValue + Gear^.dY.QWordValue) / $80000000;
       
   146 if not Gear^.dX.isNegative then
       
   147     Gear^.DirAngle:= Gear^.DirAngle + dAngle
       
   148 else
       
   149     Gear^.DirAngle:= Gear^.DirAngle - dAngle;
       
   150 
       
   151 if Gear^.DirAngle < 0 then Gear^.DirAngle:= Gear^.DirAngle + 360
       
   152 else if 360 < Gear^.DirAngle then Gear^.DirAngle:= Gear^.DirAngle - 360
       
   153 end;
   164 end;
   154 
   165 
   155 ////////////////////////////////////////////////////////////////////////////////
   166 ////////////////////////////////////////////////////////////////////////////////
   156 procedure doStepDrowningGear(Gear: PGear);
   167 procedure doStepDrowningGear(Gear: PGear);
   157 begin
   168 begin
   158 AllInactive:= false;
   169     AllInactive := false;
   159 Gear^.Y:= Gear^.Y + cDrownSpeed;
   170     Gear^.Y := Gear^.Y + cDrownSpeed;
   160 Gear^.X:= Gear^.X + Gear^.dX * cDrownSpeed;
   171     Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed;
   161 if (cWaterOpacity > $FE) or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then DeleteGear(Gear);
   172     if (cWaterOpacity > $FE) or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then
   162 // Create some bubbles (0.5% might be better but causes too few bubbles sometimes)
   173         DeleteGear(Gear);
   163 if (cWaterOpacity < $FF) and ((GameTicks and $1F) = 0) then
   174     // Create some bubbles (0.5% might be better but causes too few bubbles sometimes)
   164     if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
   175     if (cWaterOpacity < $FF) and ((GameTicks and $1F) = 0) then
   165         AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble)
   176         if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
       
   177             AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius,
       
   178             vgtBubble)
   166     else if Random(12) = 0 then
   179     else if Random(12) = 0 then
   167         AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble)
   180              AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius,
       
   181              vgtBubble)
   168 end;
   182 end;
   169 
   183 
   170 ////////////////////////////////////////////////////////////////////////////////
   184 ////////////////////////////////////////////////////////////////////////////////
   171 procedure doStepFallingGear(Gear: PGear);
   185 procedure doStepFallingGear(Gear: PGear);
   172 var isFalling: boolean;
   186 var 
       
   187     isFalling: boolean;
   173     //tmp: QWord;
   188     //tmp: QWord;
   174     tdX, tdY: hwFloat;
   189     tdX, tdY: hwFloat;
   175     collV, collH: LongInt;
   190     collV, collH: LongInt;
   176 begin
   191 begin
   177 if Gear^.dX > _0_995 then Gear^.dX:= _0_995;
   192     if Gear^.dX > _0_995 then Gear^.dX := _0_995;
   178 if Gear^.dY > _0_995 then Gear^.dY:= _0_995;
   193     if Gear^.dY > _0_995 then Gear^.dY := _0_995;
   179 Gear^.State:= Gear^.State and not gstCollision;
   194     Gear^.State := Gear^.State and not gstCollision;
   180 collV:= 0; 
   195     collV := 0;
   181 collH:= 0;
   196     collH := 0;
   182 tdX:= Gear^.dX;
   197     tdX := Gear^.dX;
   183 tdY:= Gear^.dY;
   198     tdY := Gear^.dY;
       
   199 
   184 
   200 
   185 // might need some testing/adjustments - just to avoid projectiles to fly forever (accelerated by wind/skips)
   201 // might need some testing/adjustments - just to avoid projectiles to fly forever (accelerated by wind/skips)
   186 if (hwRound(Gear^.X) < LAND_WIDTH div -2) or (hwRound(Gear^.X) > LAND_WIDTH * 3 div 2) then
   202     if (hwRound(Gear^.X) < LAND_WIDTH div -2) or (hwRound(Gear^.X) > LAND_WIDTH * 3 div 2) then
   187     begin
   203     begin
   188     Gear^.State:= Gear^.State or gstCollision;
   204         Gear^.State := Gear^.State or gstCollision;
   189     exit
   205         exit
   190     end;
   206     end;
   191 
   207 
   192 if Gear^.dY.isNegative then
   208     if Gear^.dY.isNegative then
   193     begin
   209     begin
   194     isFalling:= true;
   210         isFalling := true;
   195     if TestCollisionYwithGear(Gear, -1) then
   211         if TestCollisionYwithGear(Gear, -1) then
   196         begin
   212         begin
   197         collV:= -1;
   213             collV := -1;
   198         Gear^.dX:=   Gear^.dX * Gear^.Friction;
   214             Gear^.dX :=   Gear^.dX * Gear^.Friction;
   199         Gear^.dY:= - Gear^.dY * Gear^.Elasticity;
   215             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
   200         Gear^.State:= Gear^.State or gstCollision
   216             Gear^.State := Gear^.State or gstCollision
   201         end
   217         end
   202     else if (Gear^.AdvBounce=1) and TestCollisionYwithGear(Gear, 1) then collV:= 1;
   218         else if (Gear^.AdvBounce=1) and TestCollisionYwithGear(Gear, 1) then collV := 1;
   203     end 
   219     end
   204 else if TestCollisionYwithGear(Gear, 1) then
   220     else if TestCollisionYwithGear(Gear, 1) then
   205     begin
   221         begin
   206     collV:= 1;
   222             collV := 1;
   207     isFalling:= false;
   223             isFalling := false;
   208     Gear^.dX:=   Gear^.dX * Gear^.Friction;
   224             Gear^.dX :=   Gear^.dX * Gear^.Friction;
   209     Gear^.dY:= - Gear^.dY * Gear^.Elasticity;
   225             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
   210     Gear^.State:= Gear^.State or gstCollision
   226             Gear^.State := Gear^.State or gstCollision
   211     end
   227         end
   212 else
   228     else
   213     begin
   229     begin
   214     isFalling:= true;
   230         isFalling := true;
   215     if (Gear^.AdvBounce=1) and not Gear^.dY.isNegative and TestCollisionYwithGear(Gear, -1) then collV:= -1;
   231         if (Gear^.AdvBounce=1) and not Gear^.dY.isNegative and TestCollisionYwithGear(Gear, -1) then
   216     end;
   232             collV := -1;
   217 
   233     end;
   218 
   234 
   219 if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
   235 
   220     begin
   236     if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
   221     collH:= hwSign(Gear^.dX);
   237     begin
   222     Gear^.dX:= - Gear^.dX * Gear^.Elasticity;
   238         collH := hwSign(Gear^.dX);
   223     Gear^.dY:=   Gear^.dY * Gear^.Elasticity;
   239         Gear^.dX := - Gear^.dX * Gear^.Elasticity;
   224     Gear^.State:= Gear^.State or gstCollision
   240         Gear^.dY :=   Gear^.dY * Gear^.Elasticity;
   225     end 
   241         Gear^.State := Gear^.State or gstCollision
   226 else if (Gear^.AdvBounce=1) and TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)) then collH:= -hwSign(Gear^.dX);
   242     end
   227 
   243     else if (Gear^.AdvBounce=1) and TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)) then 
   228 //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
   244         collH := -hwSign(Gear^.dX); 
   229 if (Gear^.AdvBounce=1) and (collV <>0) and (collH <> 0) and ((collV=-1) or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)) then
   245     //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
   230     begin
   246     if (Gear^.AdvBounce=1) and (collV <>0) and (collH <> 0) and ((collV=-1) or ((tdX.QWordValue +
   231     Gear^.dX:= tdY*Gear^.Elasticity*Gear^.Friction;
   247        tdY.QWordValue) > _0_2.QWordValue)) then
   232     Gear^.dY:= tdX*Gear^.Elasticity;//*Gear^.Friction;
   248     begin
   233     Gear^.dY.isNegative:= not tdY.isNegative;
   249         Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
   234     isFalling:= false;
   250         Gear^.dY := tdX*Gear^.Elasticity;
   235     Gear^.AdvBounce:= 10;
   251         //*Gear^.Friction;
   236     end;
   252         Gear^.dY.isNegative := not tdY.isNegative;
   237 
   253         isFalling := false;
   238 if Gear^.AdvBounce > 1 then dec(Gear^.AdvBounce);
   254         Gear^.AdvBounce := 10;
   239 
   255     end;
   240 if isFalling then Gear^.dY:= Gear^.dY + cGravity;
   256 
   241 
   257     if Gear^.AdvBounce > 1 then dec(Gear^.AdvBounce);
   242 Gear^.X:= Gear^.X + Gear^.dX;
   258 
   243 Gear^.Y:= Gear^.Y + Gear^.dY;
   259     if isFalling then Gear^.dY := Gear^.dY + cGravity;
   244 CheckGearDrowning(Gear);
   260 
   245 //if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) < _0_0002) and
   261     Gear^.X := Gear^.X + Gear^.dX;
   246 if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_02.QWordValue) and
   262     Gear^.Y := Gear^.Y + Gear^.dY;
   247     (not isFalling) then
   263     CheckGearDrowning(Gear);
   248     Gear^.State:= Gear^.State and not gstMoving
   264     //if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) < _0_0002) and
   249 else
   265     if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_02.QWordValue) and
   250     Gear^.State:= Gear^.State or      gstMoving;
   266        (not isFalling) then
   251 
   267         Gear^.State := Gear^.State and not gstMoving
   252 if (Gear^.nImpactSounds > 0) then
   268     else
   253     if ((Gear^.Damage <> 0) or ((Gear^.State and (gstCollision or gstMoving)) = (gstCollision or gstMoving))) and
   269         Gear^.State := Gear^.State or      gstMoving;
   254        ((Gear^.dX.QWordValue > _0_1.QWordValue) or (Gear^.dY.QWordValue > _0_1.QWordValue)) then
   270 
   255         PlaySound(TSound(ord(Gear^.ImpactSound) + LongInt(GetRandom(Gear^.nImpactSounds))), true);
   271     if (Gear^.nImpactSounds > 0) then
       
   272         if ((Gear^.Damage <> 0) or ((Gear^.State and (gstCollision or gstMoving)) = (gstCollision or
       
   273            gstMoving))) and
       
   274            ((Gear^.dX.QWordValue > _0_1.QWordValue) or (Gear^.dY.QWordValue > _0_1.QWordValue)) then
       
   275             PlaySound(TSound(ord(Gear^.ImpactSound) + LongInt(GetRandom(Gear^.nImpactSounds))), true
       
   276             );
   256 end;
   277 end;
   257 
   278 
   258 ////////////////////////////////////////////////////////////////////////////////
   279 ////////////////////////////////////////////////////////////////////////////////
   259 procedure doStepBomb(Gear: PGear);
   280 procedure doStepBomb(Gear: PGear);
   260 var i, x, y: LongInt;
   281 var 
       
   282     i, x, y: LongInt;
   261     dX, dY: hwFloat;
   283     dX, dY: hwFloat;
   262     Fire: PGear;
   284     Fire: PGear;
   263 begin
   285 begin
   264 AllInactive:= false;
   286     AllInactive := false;
   265 
   287 
   266 doStepFallingGear(Gear);
   288     doStepFallingGear(Gear);
   267 
   289 
   268 dec(Gear^.Timer);
   290     dec(Gear^.Timer);
   269 if Gear^.Timer = 1000 then // might need adjustments
   291     if Gear^.Timer = 1000 then // might need adjustments
   270     case Gear^.Kind of
   292         case Gear^.Kind of 
   271         gtAmmo_Bomb: makeHogsWorry(Gear^.X, Gear^.Y, 50);
   293             gtAmmo_Bomb: makeHogsWorry(Gear^.X, Gear^.Y, 50);
   272         gtClusterBomb: makeHogsWorry(Gear^.X, Gear^.Y, 20);
   294             gtClusterBomb: makeHogsWorry(Gear^.X, Gear^.Y, 20);
   273         gtWatermelon: makeHogsWorry(Gear^.X, Gear^.Y, 75);
   295             gtWatermelon: makeHogsWorry(Gear^.X, Gear^.Y, 75);
   274         gtHellishBomb: makeHogsWorry(Gear^.X, Gear^.Y, 90);
   296             gtHellishBomb: makeHogsWorry(Gear^.X, Gear^.Y, 90);
   275         gtGasBomb: makeHogsWorry(Gear^.X, Gear^.Y, 50);
   297             gtGasBomb: makeHogsWorry(Gear^.X, Gear^.Y, 50);
   276     end;
   298         end;
   277 
   299 
   278 if (Gear^.Kind = gtBall) and ((Gear^.State and gstTmpFlag) <> 0) then
   300     if (Gear^.Kind = gtBall) and ((Gear^.State and gstTmpFlag) <> 0) then
   279     begin
   301     begin
   280     CheckCollision(Gear);
   302         CheckCollision(Gear);
   281     if (Gear^.State and gstCollision) <> 0 then
   303         if (Gear^.State and gstCollision) <> 0 then
   282         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLDontDraw or EXPLNoGfx);
   304             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLDontDraw or EXPLNoGfx);
   283     end;
   305     end;
   284 
   306 
   285 if Gear^.Timer = 0 then
   307     if Gear^.Timer = 0 then
   286     begin
   308     begin
   287     case Gear^.Kind of
   309         case Gear^.Kind of 
   288         gtAmmo_Bomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
   310             gtAmmo_Bomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
   289              gtBall: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 40, EXPLAutoSound);
   311             gtBall: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 40, EXPLAutoSound);
   290         gtClusterBomb: begin
   312             gtClusterBomb: 
   291                 x:= hwRound(Gear^.X);
   313         begin
   292                 y:= hwRound(Gear^.Y);
   314             x := hwRound(Gear^.X);
   293                 doMakeExplosion(x, y, 20, EXPLAutoSound);
   315             y := hwRound(Gear^.Y);
   294                 for i:= 0 to 4 do
   316             doMakeExplosion(x, y, 20, EXPLAutoSound);
   295                     begin
   317             for i:= 0 to 4 do
   296                     dX:= rndSign(GetRandom * _0_1);
   318             begin
   297                     dY:= (GetRandom - _3) * _0_08;
   319                 dX := rndSign(GetRandom * _0_1);
   298                     AddGear(x, y, gtCluster, 0, dX, dY, 25);
   320                 dY := (GetRandom - _3) * _0_08;
   299                     end
   321                 AddGear(x, y, gtCluster, 0, dX, dY, 25);
   300                 end;
   322             end
   301         gtWatermelon: begin
   323         end;
   302                 x:= hwRound(Gear^.X);
   324         gtWatermelon: 
   303                 y:= hwRound(Gear^.Y);
   325     begin
   304                 doMakeExplosion(x, y, 75, EXPLAutoSound);
   326         x := hwRound(Gear^.X);
   305                 for i:= 0 to 5 do
   327         y := hwRound(Gear^.Y);
   306                     begin
   328         doMakeExplosion(x, y, 75, EXPLAutoSound);
   307                     dX:= rndSign(GetRandom * _0_1);
   329         for i:= 0 to 5 do
   308                     dY:= (GetRandom - _1_5) * _0_3;
   330         begin
   309                     AddGear(x, y, gtMelonPiece, 0, dX, dY, 75)^.DirAngle:= i * 60;
   331             dX := rndSign(GetRandom * _0_1);
   310                     end
   332             dY := (GetRandom - _1_5) * _0_3;
   311                 end;
   333             AddGear(x, y, gtMelonPiece, 0, dX, dY, 75)^.DirAngle := i * 60;
   312         gtHellishBomb: begin
   334         end
   313                 x:= hwRound(Gear^.X);
   335     end;
   314                 y:= hwRound(Gear^.Y);
   336     gtHellishBomb: 
   315                 doMakeExplosion(x, y, 90, EXPLAutoSound);
   337 begin
   316                 
   338     x := hwRound(Gear^.X);
   317                 for i:= 0 to 127 do
   339     y := hwRound(Gear^.Y);
   318                     begin
   340     doMakeExplosion(x, y, 90, EXPLAutoSound);
   319                     dX:= AngleCos(i * 16) * _0_5 * (GetRandom + _1);
   341 
   320                     dY:= AngleSin(i * 16) * _0_5 * (GetRandom + _1);
   342     for i:= 0 to 127 do
   321                     Fire:= AddGear(x, y, gtFlame, 0, dX, dY, 0);
   343     begin
   322                     if i mod 2 = 0 then Fire^.State:= Fire^.State or gsttmpFlag;
   344         dX := AngleCos(i * 16) * _0_5 * (GetRandom + _1);
   323                     Fire:= AddGear(x, y, gtFlame, 0, dX, -dY, 0);
   345         dY := AngleSin(i * 16) * _0_5 * (GetRandom + _1);
   324                     if i mod 2 <> 0 then Fire^.State:= Fire^.State or gsttmpFlag;
   346         Fire := AddGear(x, y, gtFlame, 0, dX, dY, 0);
   325                     end
   347         if i mod 2 = 0 then Fire^.State := Fire^.State or gsttmpFlag;
   326                 end;
   348         Fire := AddGear(x, y, gtFlame, 0, dX, -dY, 0);
   327 		gtGasBomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound or EXPLPoisoned);
   349         if i mod 2 <> 0 then Fire^.State := Fire^.State or gsttmpFlag;
   328         end;
   350     end
   329     DeleteGear(Gear);
   351 end;
   330     exit
   352 gtGasBomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound or EXPLPoisoned);
   331     end;
   353 end;
       
   354 DeleteGear(Gear);
       
   355 exit
       
   356 end;
   332 
   357 
   333 CalcRotationDirAngle(Gear);
   358 CalcRotationDirAngle(Gear);
   334 
   359 
   335 if Gear^.Kind = gtHellishBomb then
   360 if Gear^.Kind = gtHellishBomb then
   336     begin
   361 begin
   337 
   362 
   338     if Gear^.Timer = 3000 then
   363     if Gear^.Timer = 3000 then
   339         begin
   364     begin
   340         Gear^.nImpactSounds:= 0;
   365         Gear^.nImpactSounds := 0;
   341         PlaySound(sndHellish);
   366         PlaySound(sndHellish);
   342         end;
   367     end;
   343 
   368 
   344     if (GameTicks and $3F) = 0 then
   369     if (GameTicks and $3F) = 0 then
   345         if (Gear^.State and gstCollision) = 0 then
   370         if (Gear^.State and gstCollision) = 0 then
   346             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace);
   371             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace);
   347     end;
   372 end;
   348 end;
   373 end;
   349 ////////////////////////////////////////////////////////////////////////////////
   374 ////////////////////////////////////////////////////////////////////////////////
   350 procedure doStepMolotov(Gear: PGear);
   375 procedure doStepMolotov(Gear: PGear);
   351 var i, gX, gY: LongInt;
   376 var 
       
   377     i, gX, gY: LongInt;
   352     dX, dY: hwFloat;
   378     dX, dY: hwFloat;
   353     Fire: PGear;
   379     Fire: PGear;
   354 begin
   380 begin
   355     AllInactive:= false;
   381     AllInactive := false;
   356     
   382 
   357     doStepFallingGear(Gear);
   383     doStepFallingGear(Gear);
   358     CalcRotationDirAngle(Gear);
   384     CalcRotationDirAngle(Gear);
   359 
   385 
   360     if (Gear^.State and gstCollision) <> 0 then begin
   386     if (Gear^.State and gstCollision) <> 0 then
       
   387     begin
   361         PlaySound(sndMolotov);
   388         PlaySound(sndMolotov);
   362         gX:= hwRound(Gear^.X);
   389         gX := hwRound(Gear^.X);
   363         gY:= hwRound(Gear^.Y);
   390         gY := hwRound(Gear^.Y);
   364         //doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 5, EXPLAutoSound);
   391         //doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 5, EXPLAutoSound);
   365         for i:= 0 to 20 do begin
   392         for i:= 0 to 20 do
   366                 dX:= AngleCos(i * 2) * ((_0_1*(i div 5))) * (GetRandom + _1);
   393         begin
   367                 dY:= AngleSin(i * 8) * _0_5 * (GetRandom + _1);
   394             dX := AngleCos(i * 2) * ((_0_1*(i div 5))) * (GetRandom + _1);
   368                 Fire:= AddGear(gX, gY, gtFlame, 0, dX, dY, 0);
   395             dY := AngleSin(i * 8) * _0_5 * (GetRandom + _1);
   369                 Fire^.State:= Fire^.State or gsttmpFlag;
   396             Fire := AddGear(gX, gY, gtFlame, 0, dX, dY, 0);
   370                 Fire:= AddGear(gX, gY, gtFlame, 0, dX, -dY, 0);
   397             Fire^.State := Fire^.State or gsttmpFlag;
   371                 Fire^.State:= Fire^.State or gsttmpFlag;
   398             Fire := AddGear(gX, gY, gtFlame, 0, dX, -dY, 0);
   372                 Fire:= AddGear(gX, gY, gtFlame, 0, -dX, dY, 0);
   399             Fire^.State := Fire^.State or gsttmpFlag;
   373                 Fire^.State:= Fire^.State or gsttmpFlag;
   400             Fire := AddGear(gX, gY, gtFlame, 0, -dX, dY, 0);
   374                 Fire:= AddGear(gX, gY, gtFlame, 0, -dX, -dY, 0);
   401             Fire^.State := Fire^.State or gsttmpFlag;
   375                 Fire^.State:= Fire^.State or gsttmpFlag;
   402             Fire := AddGear(gX, gY, gtFlame, 0, -dX, -dY, 0);
       
   403             Fire^.State := Fire^.State or gsttmpFlag;
   376         end;
   404         end;
   377         DeleteGear(Gear);
   405         DeleteGear(Gear);
   378         exit
   406         exit
   379     end;
   407     end;
   380 end;
   408 end;
   381 
   409 
   382 procedure doStepWatermelon(Gear: PGear);
   410 procedure doStepWatermelon(Gear: PGear);
   383 begin
   411 begin
   384 AllInactive:= false;
   412     AllInactive := false;
   385 Gear^.doStep:= @doStepBomb
   413     Gear^.doStep := @doStepBomb
   386 end;
   414 end;
   387 
   415 
   388 procedure doStepCluster(Gear: PGear);
   416 procedure doStepCluster(Gear: PGear);
   389 begin
   417 begin
   390 AllInactive:= false;
   418     AllInactive := false;
   391 doStepFallingGear(Gear);
   419     doStepFallingGear(Gear);
   392 if (Gear^.State and gstCollision) <> 0 then
   420     if (Gear^.State and gstCollision) <> 0 then
   393     begin
   421     begin
   394     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Timer, EXPLAutoSound);
   422         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Timer, EXPLAutoSound);
   395     DeleteGear(Gear);
   423         DeleteGear(Gear);
   396     exit
   424         exit
   397     end;
   425     end;
   398 
   426 
   399 if (Gear^.Kind = gtMelonPiece) or (Gear^.Kind = gtBall) then
   427     if (Gear^.Kind = gtMelonPiece) or (Gear^.Kind = gtBall) then
   400     CalcRotationDirAngle(Gear)
   428         CalcRotationDirAngle(Gear)
   401 else
   429     else if (GameTicks and $1F) = 0 then
   402     if (GameTicks and $1F) = 0 then
       
   403         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
   430         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
   404 end;
   431 end;
   405 
   432 
   406 ////////////////////////////////////////////////////////////////////////////////
   433 ////////////////////////////////////////////////////////////////////////////////
   407 procedure doStepGrenade(Gear: PGear);
   434 procedure doStepGrenade(Gear: PGear);
   408 begin
   435 begin
   409 AllInactive:= false;
   436     AllInactive := false;
   410 Gear^.dX:= Gear^.dX + cWindSpeed;
   437     Gear^.dX := Gear^.dX + cWindSpeed;
   411 doStepFallingGear(Gear);
   438     doStepFallingGear(Gear);
   412 if (Gear^.State and gstCollision) <> 0 then
   439     if (Gear^.State and gstCollision) <> 0 then
   413     begin
   440     begin
   414     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
   441         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
   415     DeleteGear(Gear);
   442         DeleteGear(Gear);
   416     exit
   443         exit
   417     end;
   444     end;
   418 if (GameTicks and $3F) = 0 then
   445     if (GameTicks and $3F) = 0 then
   419     AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
   446         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
   420 end;
   447 end;
   421 
   448 
   422 ////////////////////////////////////////////////////////////////////////////////
   449 ////////////////////////////////////////////////////////////////////////////////
   423 procedure doStepGrave(Gear: PGear);
   450 procedure doStepGrave(Gear: PGear);
   424 begin
   451 begin
   425 AllInactive:= false;
   452     AllInactive := false;
   426 if Gear^.dY.isNegative then
   453     if Gear^.dY.isNegative then
   427    if TestCollisionY(Gear, -1) then Gear^.dY:= _0;
   454         if TestCollisionY(Gear, -1) then Gear^.dY := _0;
   428 
   455 
   429 if not Gear^.dY.isNegative then
   456     if not Gear^.dY.isNegative then
   430    if TestCollisionY(Gear, 1) then
   457         if TestCollisionY(Gear, 1) then
   431       begin
   458         begin
   432       Gear^.dY:= - Gear^.dY * Gear^.Elasticity;
   459             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
   433       if Gear^.dY > - _1div1024 then
   460             if Gear^.dY > - _1div1024 then
   434          begin
   461             begin
   435          Gear^.Active:= false;
   462                 Gear^.Active := false;
   436          exit
   463                 exit
   437          end else if Gear^.dY < - _0_03 then PlaySound(Gear^.ImpactSound)
   464             end
   438       end;
   465             else if Gear^.dY < - _0_03 then PlaySound(Gear^.ImpactSound)
   439 
   466         end;
   440 Gear^.Y:= Gear^.Y + Gear^.dY;
   467 
   441 CheckGearDrowning(Gear);
   468     Gear^.Y := Gear^.Y + Gear^.dY;
   442 Gear^.dY:= Gear^.dY + cGravity
   469     CheckGearDrowning(Gear);
       
   470     Gear^.dY := Gear^.dY + cGravity
   443 end;
   471 end;
   444 
   472 
   445 ////////////////////////////////////////////////////////////////////////////////
   473 ////////////////////////////////////////////////////////////////////////////////
   446 procedure doStepBeeWork(Gear: PGear);
   474 procedure doStepBeeWork(Gear: PGear);
   447 var t: hwFloat;
   475 var 
       
   476     t: hwFloat;
   448     gX,gY: LongInt;
   477     gX,gY: LongInt;
   449     nuw: boolean;
   478     nuw: boolean;
   450 const uw: boolean = false;
   479 
   451 begin
   480 const uw: boolean =   false;
   452 AllInactive:= false;
   481 begin
   453 gX:= hwRound(Gear^.X);
   482     AllInactive := false;
   454 gY:= hwRound(Gear^.Y);
   483     gX := hwRound(Gear^.X);
   455 nuw:= (cWaterLine < hwRound(Gear^.Y) + Gear^.Radius);
   484     gY := hwRound(Gear^.Y);
   456 if nuw and not uw then
   485     nuw := (cWaterLine < hwRound(Gear^.Y) + Gear^.Radius);
   457     begin
   486     if nuw and not uw then
   458     AddVisualGear(gX, cWaterLine, vgtSplash);
   487     begin
   459     AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
   488         AddVisualGear(gX, cWaterLine, vgtSplash);
   460     AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
   489         AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
   461     AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
   490         AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
   462     AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
   491         AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
   463     StopSound(Gear^.SoundChannel);
   492         AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
   464     Gear^.SoundChannel:= LoopSound(sndBeeWater);
   493         StopSound(Gear^.SoundChannel);
   465     uw:= nuw
   494         Gear^.SoundChannel := LoopSound(sndBeeWater);
   466     end
   495         uw := nuw
   467 else if not nuw and uw then
   496     end
   468     begin
   497     else if not nuw and uw then
   469     AddVisualGear(gX, cWaterLine, vgtSplash);
   498         begin
   470     StopSound(Gear^.SoundChannel);
   499             AddVisualGear(gX, cWaterLine, vgtSplash);
   471     Gear^.SoundChannel:= LoopSound(sndBee);
   500             StopSound(Gear^.SoundChannel);
   472     uw:= nuw
   501             Gear^.SoundChannel := LoopSound(sndBee);
   473     end;
   502             uw := nuw
   474 
   503         end;
   475 
   504 
   476 t:= Distance(Gear^.dX, Gear^.dY);
   505 
   477 Gear^.dX:= Gear^.Elasticity * (Gear^.dX + _0_000004 * (TargetPoint.X - gX));
   506     t := Distance(Gear^.dX, Gear^.dY);
   478 Gear^.dY:= Gear^.Elasticity * (Gear^.dY + _0_000004 * (TargetPoint.Y - gY));
   507     Gear^.dX := Gear^.Elasticity * (Gear^.dX + _0_000004 * (TargetPoint.X - gX));
   479 
   508     Gear^.dY := Gear^.Elasticity * (Gear^.dY + _0_000004 * (TargetPoint.Y - gY));
   480 t:= t / Distance(Gear^.dX, Gear^.dY);
   509 
   481 Gear^.dX:= Gear^.dX * t;
   510     t := t / Distance(Gear^.dX, Gear^.dY);
   482 Gear^.dY:= Gear^.dY * t;
   511     Gear^.dX := Gear^.dX * t;
   483 Gear^.X:= Gear^.X + Gear^.dX;
   512     Gear^.dY := Gear^.dY * t;
   484 Gear^.Y:= Gear^.Y + Gear^.dY;
   513     Gear^.X := Gear^.X + Gear^.dX;
   485 
   514     Gear^.Y := Gear^.Y + Gear^.dY;
   486 if (GameTicks and $3F) = 0 then
   515 
   487    begin
   516     if (GameTicks and $3F) = 0 then
   488       AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBeeTrace);
   517     begin
   489    end;
   518         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBeeTrace);
   490 
   519     end;
   491 CheckCollision(Gear);
   520 
   492 dec(Gear^.Timer);
   521     CheckCollision(Gear);
   493 if ((Gear^.State and gstCollision) <> 0) or (Gear^.Timer = 0) then
   522     dec(Gear^.Timer);
   494    begin
   523     if ((Gear^.State and gstCollision) <> 0) or (Gear^.Timer = 0) then
   495    StopSound(Gear^.SoundChannel);
   524     begin
   496    doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
   525         StopSound(Gear^.SoundChannel);
   497    DeleteGear(Gear);
   526         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
   498    end;
   527         DeleteGear(Gear);
       
   528     end;
   499 end;
   529 end;
   500 
   530 
   501 procedure doStepBee(Gear: PGear);
   531 procedure doStepBee(Gear: PGear);
   502 begin
   532 begin
   503 AllInactive:= false;
   533     AllInactive := false;
   504 Gear^.X:= Gear^.X + Gear^.dX;
   534     Gear^.X := Gear^.X + Gear^.dX;
   505 Gear^.Y:= Gear^.Y + Gear^.dY;
   535     Gear^.Y := Gear^.Y + Gear^.dY;
   506 Gear^.dY:= Gear^.dY + cGravity;
   536     Gear^.dY := Gear^.dY + cGravity;
   507 CheckCollision(Gear);
   537     CheckCollision(Gear);
   508 if (Gear^.State and gstCollision) <> 0 then
   538     if (Gear^.State and gstCollision) <> 0 then
   509    begin
   539     begin
   510    doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
   540         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
   511    DeleteGear(Gear);
   541         DeleteGear(Gear);
   512    exit
   542         exit
   513    end;
   543     end;
   514 dec(Gear^.Timer);
       
   515 if Gear^.Timer = 0 then
       
   516    begin
       
   517    Gear^.SoundChannel:= LoopSound(sndBee);
       
   518    Gear^.Timer:= 5000;
       
   519    Gear^.doStep:= @doStepBeeWork
       
   520    end;
       
   521 end;
       
   522 
       
   523 ////////////////////////////////////////////////////////////////////////////////
       
   524 procedure doStepShotIdle(Gear: PGear);
       
   525 begin
       
   526 AllInactive:= false;
       
   527 inc(Gear^.Timer);
       
   528 if Gear^.Timer > 75 then
       
   529     begin
       
   530     DeleteGear(Gear);
       
   531     AfterAttack
       
   532     end
       
   533 end;
       
   534 
       
   535 procedure doStepShotgunShot(Gear: PGear);
       
   536 var i: LongWord;
       
   537     shell: PVisualGear;
       
   538 begin
       
   539 AllInactive:= false;
       
   540 
       
   541 if ((Gear^.State and gstAnimation) = 0) then
       
   542     begin
       
   543     dec(Gear^.Timer);
   544     dec(Gear^.Timer);
   544     if Gear^.Timer = 0 then
   545     if Gear^.Timer = 0 then
   545         begin
   546     begin
   546         PlaySound(sndShotgunFire);
   547         Gear^.SoundChannel := LoopSound(sndBee);
   547         shell:= AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
   548         Gear^.Timer := 5000;
       
   549         Gear^.doStep := @doStepBeeWork
       
   550     end;
       
   551 end;
       
   552 
       
   553 ////////////////////////////////////////////////////////////////////////////////
       
   554 procedure doStepShotIdle(Gear: PGear);
       
   555 begin
       
   556     AllInactive := false;
       
   557     inc(Gear^.Timer);
       
   558     if Gear^.Timer > 75 then
       
   559     begin
       
   560         DeleteGear(Gear);
       
   561         AfterAttack
       
   562     end
       
   563 end;
       
   564 
       
   565 procedure doStepShotgunShot(Gear: PGear);
       
   566 var 
       
   567     i: LongWord;
       
   568     shell: PVisualGear;
       
   569 begin
       
   570     AllInactive := false;
       
   571 
       
   572     if ((Gear^.State and gstAnimation) = 0) then
       
   573     begin
       
   574         dec(Gear^.Timer);
       
   575         if Gear^.Timer = 0 then
       
   576         begin
       
   577             PlaySound(sndShotgunFire);
       
   578             shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
       
   579             if shell <> nil then
       
   580             begin
       
   581                 shell^.dX := gear^.dX / -4;
       
   582                 shell^.dY := gear^.dY / -4;
       
   583                 shell^.Frame := 0
       
   584             end;
       
   585             Gear^.State := Gear^.State or gstAnimation
       
   586         end;
       
   587         exit
       
   588     end
       
   589     else inc(Gear^.Timer);
       
   590 
       
   591     i := 200;
       
   592     repeat
       
   593         Gear^.X := Gear^.X + Gear^.dX;
       
   594         Gear^.Y := Gear^.Y + Gear^.dY;
       
   595         CheckCollision(Gear);
       
   596         if (Gear^.State and gstCollision) <> 0 then
       
   597         begin
       
   598             Gear^.X := Gear^.X + Gear^.dX * 8;
       
   599             Gear^.Y := Gear^.Y + Gear^.dY * 8;
       
   600             ShotgunShot(Gear);
       
   601             Gear^.doStep := @doStepShotIdle;
       
   602             exit
       
   603         end;
       
   604 
       
   605         CheckGearDrowning(Gear);
       
   606         if (Gear^.State and gstDrowning) <> 0 then
       
   607         begin
       
   608             Gear^.doStep := @doStepShotIdle;
       
   609             exit
       
   610         end;
       
   611         dec(i)
       
   612     until i = 0;
       
   613     if (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0)
       
   614         then
       
   615         Gear^.doStep := @doStepShotIdle
       
   616 end;
       
   617 
       
   618 ////////////////////////////////////////////////////////////////////////////////
       
   619 procedure doStepBulletWork(Gear: PGear);
       
   620 var 
       
   621     i, x, y: LongWord;
       
   622     oX, oY: hwFloat;
       
   623 begin
       
   624     AllInactive := false;
       
   625     inc(Gear^.Timer);
       
   626     i := 80;
       
   627     oX := Gear^.X;
       
   628     oY := Gear^.Y;
       
   629     repeat
       
   630         Gear^.X := Gear^.X + Gear^.dX;
       
   631         Gear^.Y := Gear^.Y + Gear^.dY;
       
   632         x := hwRound(Gear^.X);
       
   633         y := hwRound(Gear^.Y);
       
   634         if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0)
       
   635            and (Land[y, x] <> 0) then inc(Gear^.Damage);
       
   636         if Gear^.Damage > 5 then
       
   637             if Gear^.Ammo^.AmmoType = amDEagle then
       
   638                 AmmoShove(Gear, 7, 20)
       
   639         else
       
   640             AmmoShove(Gear, Gear^.Timer, 20);
       
   641         CheckGearDrowning(Gear);
       
   642         dec(i)
       
   643     until (i = 0) or (Gear^.Damage > Gear^.Health) or ((Gear^.State and gstDrowning) <> 0);
       
   644     if Gear^.Damage > 0 then
       
   645     begin
       
   646         DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 82 - i, 1);
       
   647         dec(Gear^.Health, Gear^.Damage);
       
   648         Gear^.Damage := 0
       
   649     end;
       
   650     if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and (cWaterOpacity < $FF) then
       
   651     begin
       
   652         for i:=(Gear^.Health - Gear^.Damage) * 4 downto 0 do
       
   653         begin
       
   654             if Random(6) = 0 then
       
   655                 AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
       
   656             Gear^.X := Gear^.X + Gear^.dX;
       
   657             Gear^.Y := Gear^.Y + Gear^.dY;
       
   658         end;
       
   659     end;
       
   660 
       
   661     if (Gear^.Health <= 0)
       
   662        or (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0)
       
   663        or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
       
   664     begin
       
   665         if (Gear^.Kind = gtSniperRifleShot) and ((GameFlags and gfLaserSight) = 0) then
       
   666             cLaserSighting := false;
       
   667         if (Gear^.Ammo^.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and
       
   668            ((GameFlags and gfArtillery) = 0) then cArtillery := false;
       
   669         Gear^.doStep := @doStepShotIdle
       
   670     end;
       
   671 end;
       
   672 
       
   673 procedure doStepDEagleShot(Gear: PGear);
       
   674 begin
       
   675     PlaySound(sndGun);
       
   676     Gear^.doStep := @doStepBulletWork
       
   677 end;
       
   678 
       
   679 procedure doStepSniperRifleShot(Gear: PGear);
       
   680 var 
       
   681     HHGear: PGear;
       
   682     shell: PVisualGear;
       
   683 begin
       
   684     cArtillery := true;
       
   685     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
   686     HHGear^.State := HHGear^.State or gstNotKickable;
       
   687     HedgehogChAngle(HHGear);
       
   688     if not cLaserSighting then
       
   689         // game does not have default laser sight. turn it on and give them a chance to aim
       
   690     begin
       
   691         cLaserSighting := true;
       
   692         HHGear^.Message := 0;
       
   693         if (HHGear^.Angle - 32 >= 0) then dec(HHGear^.Angle,32)
       
   694     end;
       
   695 
       
   696     if (HHGear^.Message and gm_Attack) <> 0 then
       
   697     begin
       
   698         shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
   548         if shell <> nil then
   699         if shell <> nil then
   549         begin 
   700         begin
   550            shell^.dX:= gear^.dX / -4;
   701             shell^.dX := gear^.dX / -2;
   551            shell^.dY:= gear^.dY / -4;
   702             shell^.dY := gear^.dY / -2;
   552            shell^.Frame:= 0
   703             shell^.Frame := 1
   553         end;
   704         end;
   554         Gear^.State:= Gear^.State or gstAnimation
   705         Gear^.State := Gear^.State or gstAnimation;
   555         end;
   706         Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
   556     exit
   707         Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5;
   557     end
   708         PlaySound(sndGun);
   558     else inc(Gear^.Timer);
   709         Gear^.doStep := @doStepBulletWork;
   559 
   710     end
   560 i:= 200;
   711     else
   561 repeat
   712         if (GameTicks mod 32) = 0 then
   562 Gear^.X:= Gear^.X + Gear^.dX;
   713             if (GameTicks mod 4096) < 2048 then
   563 Gear^.Y:= Gear^.Y + Gear^.dY;
       
   564 CheckCollision(Gear);
       
   565 if (Gear^.State and gstCollision) <> 0 then
       
   566     begin
       
   567     Gear^.X:= Gear^.X + Gear^.dX * 8;
       
   568     Gear^.Y:= Gear^.Y + Gear^.dY * 8;
       
   569     ShotgunShot(Gear);
       
   570     Gear^.doStep:= @doStepShotIdle;
       
   571     exit
       
   572     end;
       
   573 
       
   574 CheckGearDrowning(Gear);
       
   575 if (Gear^.State and gstDrowning) <> 0 then
       
   576     begin
       
   577     Gear^.doStep:= @doStepShotIdle;
       
   578     exit
       
   579     end;
       
   580 dec(i)
       
   581 until i = 0;
       
   582 if (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
       
   583     Gear^.doStep:= @doStepShotIdle
       
   584 end;
       
   585 
       
   586 ////////////////////////////////////////////////////////////////////////////////
       
   587 procedure doStepBulletWork(Gear: PGear);
       
   588 var i, x, y: LongWord;
       
   589     oX, oY: hwFloat;
       
   590 begin
       
   591 AllInactive:= false;
       
   592 inc(Gear^.Timer);
       
   593 i:= 80;
       
   594 oX:= Gear^.X;
       
   595 oY:= Gear^.Y;
       
   596 repeat
       
   597   Gear^.X:= Gear^.X + Gear^.dX;
       
   598   Gear^.Y:= Gear^.Y + Gear^.dY;
       
   599   x:= hwRound(Gear^.X);
       
   600   y:= hwRound(Gear^.Y);
       
   601   if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0)
       
   602      and (Land[y, x] <> 0) then inc(Gear^.Damage);
       
   603   if Gear^.Damage > 5 then
       
   604       if Gear^.Ammo^.AmmoType = amDEagle then
       
   605           AmmoShove(Gear, 7, 20)
       
   606       else
       
   607           AmmoShove(Gear, Gear^.Timer, 20);
       
   608   CheckGearDrowning(Gear);
       
   609   dec(i)
       
   610 until (i = 0) or (Gear^.Damage > Gear^.Health) or ((Gear^.State and gstDrowning) <> 0);
       
   611 if Gear^.Damage > 0 then
       
   612    begin
       
   613    DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 82 - i, 1);
       
   614    dec(Gear^.Health, Gear^.Damage);
       
   615    Gear^.Damage:= 0
       
   616    end;
       
   617 if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and (cWaterOpacity < $FF) then
       
   618     begin
       
   619     for i:=(Gear^.Health - Gear^.Damage) * 4 downto 0 do
       
   620         begin
       
   621         if Random(6) = 0 then
       
   622             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
       
   623         Gear^.X:= Gear^.X + Gear^.dX;
       
   624         Gear^.Y:= Gear^.Y + Gear^.dY;
       
   625         end;
       
   626     end;
       
   627 
       
   628 if (Gear^.Health <= 0)
       
   629     or (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0)
       
   630     or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
       
   631     begin
       
   632     if (Gear^.Kind = gtSniperRifleShot) and ((GameFlags and gfLaserSight) = 0) then cLaserSighting:= false;
       
   633     if (Gear^.Ammo^.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and
       
   634        ((GameFlags and gfArtillery) = 0) then cArtillery:= false;
       
   635     Gear^.doStep:= @doStepShotIdle
       
   636     end;
       
   637 end;
       
   638 
       
   639 procedure doStepDEagleShot(Gear: PGear);
       
   640 begin
       
   641 PlaySound(sndGun);
       
   642 Gear^.doStep:= @doStepBulletWork
       
   643 end;
       
   644 
       
   645 procedure doStepSniperRifleShot(Gear: PGear);
       
   646 var HHGear: PGear;
       
   647     shell: PVisualGear;
       
   648 begin
       
   649 cArtillery:= true;
       
   650 HHGear:=PHedgehog(Gear^.Hedgehog)^.Gear;
       
   651 HHGear^.State:= HHGear^.State or gstNotKickable;
       
   652 HedgehogChAngle(HHGear);
       
   653 if not cLaserSighting then // game does not have default laser sight. turn it on and give them a chance to aim
       
   654     begin
       
   655     cLaserSighting:= true;
       
   656     HHGear^.Message:= 0;
       
   657     if(HHGear^.Angle - 32 >= 0) then dec(HHGear^.Angle,32)
       
   658     end;
       
   659 
       
   660 if (HHGear^.Message and gm_Attack) <> 0 then
       
   661     begin
       
   662     shell:= AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
       
   663     if shell <> nil then
       
   664        begin
       
   665        shell^.dX:= gear^.dX / -2;
       
   666        shell^.dY:= gear^.dY / -2;
       
   667        shell^.Frame:= 1
       
   668        end;
       
   669     Gear^.State:= Gear^.State or gstAnimation;
       
   670     Gear^.dX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
       
   671     Gear^.dY:= -AngleCos(HHGear^.Angle) * _0_5;
       
   672     PlaySound(sndGun);
       
   673     Gear^.doStep:= @doStepBulletWork;
       
   674     end
       
   675 else
       
   676     if (GameTicks mod 32) = 0 then
       
   677         if (GameTicks mod 4096) < 2048 then
       
   678             begin
   714             begin
   679             if(HHGear^.Angle + 1 <= cMaxAngle) then inc(HHGear^.Angle)
   715                 if (HHGear^.Angle + 1 <= cMaxAngle) then inc(HHGear^.Angle)
   680             end
   716             end
   681         else
   717     else
   682             if(HHGear^.Angle - 1 >= 0) then dec(HHGear^.Angle);
   718         if (HHGear^.Angle - 1 >= 0) then dec(HHGear^.Angle);
   683 
   719 
   684 if (TurnTimeLeft > 0) then
   720     if (TurnTimeLeft > 0) then
   685     dec(TurnTimeLeft)
   721         dec(TurnTimeLeft)
   686 else
   722     else
   687     begin
   723     begin
   688     DeleteGear(Gear);
   724         DeleteGear(Gear);
   689     AfterAttack
   725         AfterAttack
   690     end;
   726     end;
   691 end;
   727 end;
   692 
   728 
   693 ////////////////////////////////////////////////////////////////////////////////
   729 ////////////////////////////////////////////////////////////////////////////////
   694 procedure doStepActionTimer(Gear: PGear);
   730 procedure doStepActionTimer(Gear: PGear);
   695 begin
   731 begin
   696 dec(Gear^.Timer);
   732     dec(Gear^.Timer);
   697 case Gear^.Kind of
   733     case Gear^.Kind of 
   698     gtATStartGame: begin
   734         gtATStartGame: 
   699                    AllInactive:= false;
   735     begin
   700                    if Gear^.Timer = 0 then
   736         AllInactive := false;
   701                       begin
   737         if Gear^.Timer = 0 then
   702                       AddCaption(trmsg[sidStartFight], cWhiteColor, capgrpGameState);
   738         begin
   703                       end
   739             AddCaption(trmsg[sidStartFight], cWhiteColor, capgrpGameState);
   704                    end;
   740         end
   705  gtATSmoothWindCh: begin
   741     end;
   706                    if Gear^.Timer = 0 then
   742     gtATSmoothWindCh: 
   707                       begin
   743 begin
   708                       if WindBarWidth < Gear^.Tag then inc(WindBarWidth)
   744     if Gear^.Timer = 0 then
   709                          else if WindBarWidth > Gear^.Tag then dec(WindBarWidth);
   745     begin
   710                       if WindBarWidth <> Gear^.Tag then Gear^.Timer:= 10;
   746         if WindBarWidth < Gear^.Tag then inc(WindBarWidth)
   711                       end
   747         else if WindBarWidth > Gear^.Tag then dec(WindBarWidth);
   712                    end;
   748         if WindBarWidth <> Gear^.Tag then Gear^.Timer := 10;
   713    gtATFinishGame: begin
   749     end
   714                    AllInactive:= false;
   750 end;
   715                    if Gear^.Timer = 1000 then
   751 gtATFinishGame: 
   716                       begin
   752 begin
   717                       ScreenFade:= sfToBlack;
   753     AllInactive := false;
   718                       ScreenFadeValue:= 0;
   754     if Gear^.Timer = 1000 then
   719                       ScreenFadeSpeed:= 1;
   755     begin
   720                       end;
   756         ScreenFade := sfToBlack;
   721                    if Gear^.Timer = 0 then
   757         ScreenFadeValue := 0;
   722                       begin
   758         ScreenFadeSpeed := 1;
   723                       SendIPC('N');
   759     end;
   724                       SendIPC('q');
   760     if Gear^.Timer = 0 then
   725                       GameState:= gsExit
   761     begin
   726                       end
   762         SendIPC('N');
   727                    end;
   763         SendIPC('q');
   728      end;
   764         GameState := gsExit
       
   765     end
       
   766 end;
       
   767 end;
   729 if Gear^.Timer = 0 then DeleteGear(Gear)
   768 if Gear^.Timer = 0 then DeleteGear(Gear)
   730 end;
   769 end;
   731 
   770 
   732 ////////////////////////////////////////////////////////////////////////////////
   771 ////////////////////////////////////////////////////////////////////////////////
   733 procedure doStepPickHammerWork(Gear: PGear);
   772 procedure doStepPickHammerWork(Gear: PGear);
   734 var i, ei: LongInt;
   773 var 
       
   774     i, ei: LongInt;
   735     HHGear: PGear;
   775     HHGear: PGear;
   736 begin
   776 begin
   737 AllInactive:= false;
   777     AllInactive := false;
   738 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
   778     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
   739 dec(Gear^.Timer);
   779     dec(Gear^.Timer);
   740 if (Gear^.Timer = 0)or((Gear^.Message and gm_Destroy) <> 0)or((HHGear^.State and gstHHDriven) = 0) then
   780     if (Gear^.Timer = 0)or((Gear^.Message and gm_Destroy) <> 0)or((HHGear^.State and gstHHDriven) =
   741     begin
   781        0) then
   742     StopSound(Gear^.SoundChannel);
   782     begin
   743     DeleteGear(Gear);
   783         StopSound(Gear^.SoundChannel);
   744     AfterAttack;
   784         DeleteGear(Gear);
   745     exit
   785         AfterAttack;
   746     end;
   786         exit
   747 
   787     end;
   748 if (Gear^.Timer mod 33) = 0 then
   788 
   749     begin
   789     if (Gear^.Timer mod 33) = 0 then
   750     HHGear^.State:= HHGear^.State or gstNoDamage;
   790     begin
   751     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y) + 7, 6, EXPLDontDraw);
   791         HHGear^.State := HHGear^.State or gstNoDamage;
   752     HHGear^.State:= HHGear^.State and not gstNoDamage
   792         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y) + 7, 6, EXPLDontDraw);
   753     end;
   793         HHGear^.State := HHGear^.State and not gstNoDamage
   754 
   794     end;
   755 if (Gear^.Timer mod 47) = 0 then
   795 
   756     begin
   796     if (Gear^.Timer mod 47) = 0 then
   757     i:= hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
   797     begin
   758     ei:= hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
   798         i := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
   759     while i <= ei do
   799         ei := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
   760         begin
   800         while i <= ei do
   761         DrawExplosion(i, hwRound(Gear^.Y) + 3, 3);
   801         begin
   762         inc(i, 1)
   802             DrawExplosion(i, hwRound(Gear^.Y) + 3, 3);
   763         end;
   803             inc(i, 1)
   764 
   804         end;
   765     if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9), COLOR_INDESTRUCTIBLE) then
   805 
   766         begin
   806         if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9)
   767         Gear^.X:= Gear^.X + Gear^.dX;
   807            , COLOR_INDESTRUCTIBLE) then
   768         Gear^.Y:= Gear^.Y + _1_9;
   808         begin
   769         end;
   809             Gear^.X := Gear^.X + Gear^.dX;
   770     SetAllHHToActive;
   810             Gear^.Y := Gear^.Y + _1_9;
   771     end;
   811         end;
   772 if TestCollisionYwithGear(Gear, 1) then
   812         SetAllHHToActive;
   773     begin
   813     end;
   774     Gear^.dY:= _0;
   814     if TestCollisionYwithGear(Gear, 1) then
   775     SetLittle(HHGear^.dX);
   815     begin
   776     HHGear^.dY:= _0;
   816         Gear^.dY := _0;
   777     end else
   817         SetLittle(HHGear^.dX);
   778     begin
   818         HHGear^.dY := _0;
   779     Gear^.dY:= Gear^.dY + cGravity;
   819     end
   780     Gear^.Y:= Gear^.Y + Gear^.dY;
   820     else
   781     if hwRound(Gear^.Y) > cWaterLine then Gear^.Timer:= 1
   821     begin
   782     end;
   822         Gear^.dY := Gear^.dY + cGravity;
   783 
   823         Gear^.Y := Gear^.Y + Gear^.dY;
   784 Gear^.X:= Gear^.X + HHGear^.dX;
   824         if hwRound(Gear^.Y) > cWaterLine then Gear^.Timer := 1
   785 HHGear^.X:= Gear^.X;
   825     end;
   786 HHGear^.Y:= Gear^.Y - int2hwFloat(cHHRadius);
   826 
   787 
   827     Gear^.X := Gear^.X + HHGear^.dX;
   788 if (Gear^.Message and gm_Attack) <> 0 then
   828     HHGear^.X := Gear^.X;
   789    if (Gear^.State and gsttmpFlag) <> 0 then Gear^.Timer:= 1 else else
   829     HHGear^.Y := Gear^.Y - int2hwFloat(cHHRadius);
   790    if (Gear^.State and gsttmpFlag) = 0 then Gear^.State:= Gear^.State or gsttmpFlag;
   830 
   791 if ((Gear^.Message and gm_Left) <> 0) then Gear^.dX:= - _0_3 else
   831     if (Gear^.Message and gm_Attack) <> 0 then
   792    if ((Gear^.Message and gm_Right) <> 0) then Gear^.dX:= _0_3
   832         if (Gear^.State and gsttmpFlag) <> 0 then Gear^.Timer := 1
   793                                           else Gear^.dX:= _0;
   833     else
       
   834     else
       
   835         if (Gear^.State and gsttmpFlag) = 0 then Gear^.State := Gear^.State or gsttmpFlag;
       
   836     if ((Gear^.Message and gm_Left) <> 0) then Gear^.dX := - _0_3
       
   837     else
       
   838         if ((Gear^.Message and gm_Right) <> 0) then Gear^.dX := _0_3
       
   839     else Gear^.dX := _0;
   794 end;
   840 end;
   795 
   841 
   796 procedure doStepPickHammer(Gear: PGear);
   842 procedure doStepPickHammer(Gear: PGear);
   797 var i, y: LongInt;
   843 var 
       
   844     i, y: LongInt;
   798     ar: TRangeArray;
   845     ar: TRangeArray;
   799     HHGear: PGear;
   846     HHGear: PGear;
   800 begin
   847 begin
   801 i:= 0;
   848     i := 0;
   802 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
   849     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
   803 
   850 
   804 y:= hwRound(Gear^.Y) - cHHRadius * 2;
   851     y := hwRound(Gear^.Y) - cHHRadius * 2;
   805 while y < hwRound(Gear^.Y) do
   852     while y < hwRound(Gear^.Y) do
   806    begin
   853     begin
   807    ar[i].Left := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
   854         ar[i].Left := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
   808    ar[i].Right:= hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
   855         ar[i].Right := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
   809    inc(y, 2);
   856         inc(y, 2);
   810    inc(i)
   857         inc(i)
   811    end;
   858     end;
   812 
   859 
   813 DrawHLinesExplosions(@ar, 3, hwRound(Gear^.Y) - cHHRadius * 2, 2, Pred(i));
   860     DrawHLinesExplosions(@ar, 3, hwRound(Gear^.Y) - cHHRadius * 2, 2, Pred(i));
   814 Gear^.dY:= HHGear^.dY;
   861     Gear^.dY := HHGear^.dY;
   815 DeleteCI(HHGear);
   862     DeleteCI(HHGear);
   816 
   863 
   817 Gear^.SoundChannel:= LoopSound(sndPickhammer);
   864     Gear^.SoundChannel := LoopSound(sndPickhammer);
   818 doStepPickHammerWork(Gear);
   865     doStepPickHammerWork(Gear);
   819 Gear^.doStep:= @doStepPickHammerWork
   866     Gear^.doStep := @doStepPickHammerWork
   820 end;
   867 end;
   821 
   868 
   822 ////////////////////////////////////////////////////////////////////////////////
   869 ////////////////////////////////////////////////////////////////////////////////
   823 var BTPrevAngle, BTSteps: LongInt;
   870 var 
       
   871     BTPrevAngle, BTSteps: LongInt;
   824 
   872 
   825 procedure doStepBlowTorchWork(Gear: PGear);
   873 procedure doStepBlowTorchWork(Gear: PGear);
   826 var HHGear: PGear;
   874 var 
       
   875     HHGear: PGear;
   827     b: boolean;
   876     b: boolean;
   828     prevX: LongInt;
   877     prevX: LongInt;
   829 begin
   878 begin
   830 AllInactive:= false;
   879     AllInactive := false;
   831 dec(Gear^.Timer);
   880     dec(Gear^.Timer);
   832 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
   881     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
   833 
   882 
   834 HedgehogChAngle(HHGear);
   883     HedgehogChAngle(HHGear);
   835 
   884 
   836 b:= false;
   885     b := false;
   837 
   886 
   838 if abs(LongInt(HHGear^.Angle) - BTPrevAngle) > 7  then
   887     if abs(LongInt(HHGear^.Angle) - BTPrevAngle) > 7  then
   839     begin
   888     begin
   840     Gear^.dX:= SignAs(AngleSin(HHGear^.Angle) * _0_5, HHGear^.dX);
   889         Gear^.dX := SignAs(AngleSin(HHGear^.Angle) * _0_5, HHGear^.dX);
   841     Gear^.dY:= AngleCos(HHGear^.Angle) * ( - _0_5);
   890         Gear^.dY := AngleCos(HHGear^.Angle) * ( - _0_5);
   842     BTPrevAngle:= HHGear^.Angle;
   891         BTPrevAngle := HHGear^.Angle;
   843     b:= true
   892         b := true
   844     end;
   893     end;
   845 
   894 
   846 if ((HHGear^.State and gstMoving) <> 0) then
   895     if ((HHGear^.State and gstMoving) <> 0) then
   847     begin
   896     begin
   848     doStepHedgehogMoving(HHGear);
   897         doStepHedgehogMoving(HHGear);
   849     if (HHGear^.State and gstHHDriven) = 0 then Gear^.Timer:= 0
   898         if (HHGear^.State and gstHHDriven) = 0 then Gear^.Timer := 0
   850     end;
   899     end;
   851 
   900 
   852 if Gear^.Timer mod cHHStepTicks = 0 then
   901     if Gear^.Timer mod cHHStepTicks = 0 then
   853     begin
   902     begin
   854     b:= true;
   903         b := true;
   855     if Gear^.dX.isNegative then
   904         if Gear^.dX.isNegative then
   856         HHGear^.Message:= (HHGear^.Message and (gm_Attack or gm_Up or gm_Down)) or gm_Left
   905             HHGear^.Message := (HHGear^.Message and (gm_Attack or gm_Up or gm_Down)) or gm_Left
   857     else
   906         else
   858         HHGear^.Message:= (HHGear^.Message and (gm_Attack or gm_Up or gm_Down)) or gm_Right;
   907             HHGear^.Message := (HHGear^.Message and (gm_Attack or gm_Up or gm_Down)) or gm_Right;
   859 
   908 
   860     if ((HHGear^.State and gstMoving) = 0) then
   909         if ((HHGear^.State and gstMoving) = 0) then
   861         begin
   910         begin
   862         HHGear^.State:= HHGear^.State and not gstAttacking;
   911             HHGear^.State := HHGear^.State and not gstAttacking;
   863         prevX:= hwRound(HHGear^.X);
   912             prevX := hwRound(HHGear^.X);
   864 
   913 
   865 // why the call to HedgehogStep then a further increment of X?
   914             // why the call to HedgehogStep then a further increment of X?
   866         if (prevX = hwRound(HHGear^.X)) and
   915             if (prevX = hwRound(HHGear^.X)) and
   867            CheckLandValue(hwRound(HHGear^.X + SignAs(_6, HHGear^.dX)), hwRound(HHGear^.Y), COLOR_INDESTRUCTIBLE) then HedgehogStep(HHGear);
   916                CheckLandValue(hwRound(HHGear^.X + SignAs(_6, HHGear^.dX)), hwRound(HHGear^.Y),
   868 
   917                COLOR_INDESTRUCTIBLE) then HedgehogStep(HHGear);
   869         if (prevX = hwRound(HHGear^.X)) and
   918 
   870            CheckLandValue(hwRound(HHGear^.X + SignAs(_6, HHGear^.dX)), hwRound(HHGear^.Y), COLOR_INDESTRUCTIBLE) then HHGear^.X:= HHGear^.X + SignAs(_1, HHGear^.dX);
   919             if (prevX = hwRound(HHGear^.X)) and
   871         HHGear^.State:= HHGear^.State or gstAttacking
   920                CheckLandValue(hwRound(HHGear^.X + SignAs(_6, HHGear^.dX)), hwRound(HHGear^.Y),
   872         end;
   921                COLOR_INDESTRUCTIBLE) then HHGear^.X := HHGear^.X + SignAs(_1, HHGear^.dX);
   873 
   922             HHGear^.State := HHGear^.State or gstAttacking
   874     inc(BTSteps);
   923         end;
   875     if BTSteps = 7 then
   924 
   876         begin
   925         inc(BTSteps);
   877         BTSteps:= 0;
   926         if BTSteps = 7 then
   878         if CheckLandValue(hwRound(HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC) + SignAs(_6,Gear^.dX)), hwRound(HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC)), COLOR_INDESTRUCTIBLE) then
   927         begin
       
   928             BTSteps := 0;
       
   929             if CheckLandValue(hwRound(HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC) + SignAs(_6,
       
   930                Gear^.dX)), hwRound(HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC)),
       
   931                COLOR_INDESTRUCTIBLE) then
   879             begin
   932             begin
   880             Gear^.X:= HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC);
   933                 Gear^.X := HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC);
   881             Gear^.Y:= HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC);
   934                 Gear^.Y := HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC);
   882             end;
   935             end;
   883         HHGear^.State:= HHGear^.State or gstNoDamage;
   936             HHGear^.State := HHGear^.State or gstNoDamage;
   884         AmmoShove(Gear, 2, 15);
   937             AmmoShove(Gear, 2, 15);
   885         HHGear^.State:= HHGear^.State and not gstNoDamage
   938             HHGear^.State := HHGear^.State and not gstNoDamage
   886         end;
   939         end;
   887     end;
   940     end;
   888 
   941 
   889 if b then
   942     if b then
   890    DrawTunnel(HHGear^.X - Gear^.dX * cHHRadius, HHGear^.Y - _4 - Gear^.dY * cHHRadius + hwAbs(Gear^.dY) * 7,
   943         DrawTunnel(HHGear^.X - Gear^.dX * cHHRadius, HHGear^.Y - _4 - Gear^.dY * cHHRadius + hwAbs(
   891               Gear^.dX, Gear^.dY,
   944                    Gear^.dY) * 7,
   892               cHHRadius * 5, cHHRadius * 2 + 7);
   945         Gear^.dX, Gear^.dY,
   893 
   946         cHHRadius * 5, cHHRadius * 2 + 7);
   894 if (Gear^.Timer = 0) or ((HHGear^.Message and gm_Attack) <> 0) then
   947 
   895     begin
   948     if (Gear^.Timer = 0) or ((HHGear^.Message and gm_Attack) <> 0) then
   896     HHGear^.Message:= 0;
   949     begin
   897     HHGear^.State:= HHGear^.State and (not gstNotKickable);
   950         HHGear^.Message := 0;
   898     DeleteGear(Gear);
   951         HHGear^.State := HHGear^.State and (not gstNotKickable);
   899     AfterAttack
   952         DeleteGear(Gear);
       
   953         AfterAttack
   900     end
   954     end
   901 end;
   955 end;
   902 
   956 
   903 procedure doStepBlowTorch(Gear: PGear);
   957 procedure doStepBlowTorch(Gear: PGear);
   904 var HHGear: PGear;
   958 var 
   905 begin
   959     HHGear: PGear;
   906 BTPrevAngle:= High(LongInt);
   960 begin
   907 BTSteps:= 0;
   961     BTPrevAngle := High(LongInt);
   908 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
   962     BTSteps := 0;
   909 HHGear^.Message:= 0;
   963     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
   910 HHGear^.State:= HHGear^.State or gstNotKickable;
   964     HHGear^.Message := 0;
   911 Gear^.doStep:= @doStepBlowTorchWork
   965     HHGear^.State := HHGear^.State or gstNotKickable;
   912 end;
   966     Gear^.doStep := @doStepBlowTorchWork
   913 
   967 end;
   914 ////////////////////////////////////////////////////////////////////////////////
   968 
   915 
   969 ////////////////////////////////////////////////////////////////////////////////
   916 procedure doStepRope(Gear: PGear); forward;
   970 
       
   971 procedure doStepRope(Gear: PGear);
       
   972 forward;
   917 
   973 
   918 procedure doStepRopeAfterAttack(Gear: PGear);
   974 procedure doStepRopeAfterAttack(Gear: PGear);
   919 var HHGear: PGear;
   975 var 
   920 begin
   976     HHGear: PGear;
   921 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
   977 begin
   922 if ((HHGear^.State and gstHHDriven) = 0)
   978     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
   923     or (CheckGearDrowning(HHGear))
   979     if ((HHGear^.State and gstHHDriven) = 0)
   924     or TestCollisionYwithGear(HHGear, 1) then
   980        or (CheckGearDrowning(HHGear))
   925     begin
   981        or TestCollisionYwithGear(HHGear, 1) then
   926     DeleteGear(Gear);
   982     begin
   927     isCursorVisible:= false;
   983         DeleteGear(Gear);
   928     ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
   984         isCursorVisible := false;
   929     exit
   985         ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
   930     end;
   986         exit
   931 
   987     end;
   932 HedgehogChAngle(HHGear);
   988 
   933 
   989     HedgehogChAngle(HHGear);
   934 if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
   990 
   935 
   991     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
   936 if HHGear^.dY.isNegative and TestCollisionYwithGear(HHGear, -1) then HHGear^.dY:= _0;
   992 
   937 HHGear^.X:= HHGear^.X + HHGear^.dX;
   993     if HHGear^.dY.isNegative and TestCollisionYwithGear(HHGear, -1) then HHGear^.dY := _0;
   938 HHGear^.Y:= HHGear^.Y + HHGear^.dY;
   994     HHGear^.X := HHGear^.X + HHGear^.dX;
   939 HHGear^.dY:= HHGear^.dY + cGravity;
   995     HHGear^.Y := HHGear^.Y + HHGear^.dY;
   940 
   996     HHGear^.dY := HHGear^.dY + cGravity;
   941 if (Gear^.Message and gm_Attack) <> 0 then
   997 
   942     begin
   998     if (Gear^.Message and gm_Attack) <> 0 then
   943     Gear^.X:= HHGear^.X;
   999     begin
   944     Gear^.Y:= HHGear^.Y;
  1000         Gear^.X := HHGear^.X;
   945 
  1001         Gear^.Y := HHGear^.Y;
   946     ApplyAngleBounds(PHedgehog(Gear^.Hedgehog)^, amRope);
  1002 
   947 
  1003         ApplyAngleBounds(PHedgehog(Gear^.Hedgehog)^, amRope);
   948     Gear^.dX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX);
  1004 
   949     Gear^.dY:= -AngleCos(HHGear^.Angle);
  1005         Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX);
   950     Gear^.Friction:= _450;
  1006         Gear^.dY := -AngleCos(HHGear^.Angle);
   951     Gear^.Elasticity:= _0;
  1007         Gear^.Friction := _450;
   952     Gear^.State:= Gear^.State and not gsttmpflag;
  1008         Gear^.Elasticity := _0;
   953     Gear^.doStep:= @doStepRope;
  1009         Gear^.State := Gear^.State and not gsttmpflag;
       
  1010         Gear^.doStep := @doStepRope;
   954     end
  1011     end
   955 end;
  1012 end;
   956 
  1013 
   957 procedure doStepRopeWork(Gear: PGear);
  1014 procedure doStepRopeWork(Gear: PGear);
   958 var HHGear: PGear;
  1015 var 
       
  1016     HHGear: PGear;
   959     len, tx, ty, nx, ny, ropeDx, ropeDy, mdX, mdY: hwFloat;
  1017     len, tx, ty, nx, ny, ropeDx, ropeDy, mdX, mdY: hwFloat;
   960     lx, ly: LongInt;
  1018     lx, ly: LongInt;
   961     haveCollision,
  1019     haveCollision,
   962     haveDivided: boolean;
  1020     haveDivided: boolean;
   963 
  1021 
   964     procedure DeleteMe;
  1022 procedure DeleteMe;
   965     begin
  1023 begin
   966     with HHGear^ do
  1024     with HHGear^ do
   967         begin
  1025     begin
   968         Message:= Message and not gm_Attack;
  1026         Message := Message and not gm_Attack;
   969         State:= (State or gstMoving) and not gstWinner;
  1027         State := (State or gstMoving) and not gstWinner;
   970         end;
  1028     end;
   971     DeleteGear(Gear)
  1029     DeleteGear(Gear)
   972     end;
  1030 end;
   973 
  1031 
   974     procedure WaitCollision;
  1032 procedure WaitCollision;
   975     begin
  1033 begin
   976     with HHGear^ do
  1034     with HHGear^ do
   977         begin
  1035     begin
   978         Message:= Message and not gm_Attack;
  1036         Message := Message and not gm_Attack;
   979         State:= State or gstMoving;
  1037         State := State or gstMoving;
   980         end;
  1038     end;
   981     RopePoints.Count:= 0;
  1039     RopePoints.Count := 0;
   982     Gear^.Elasticity:= _0;
  1040     Gear^.Elasticity := _0;
   983     Gear^.doStep:= @doStepRopeAfterAttack
  1041     Gear^.doStep := @doStepRopeAfterAttack
   984     end;
  1042 end;
   985 
  1043 
   986 begin
  1044 begin
   987 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
  1045     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
   988 
  1046 
   989 if ((HHGear^.State and gstHHDriven) = 0)
  1047     if ((HHGear^.State and gstHHDriven) = 0)
   990     or (CheckGearDrowning(HHGear)) then
  1048        or (CheckGearDrowning(HHGear)) then
   991     begin
  1049     begin
   992     PlaySound(sndRopeRelease);
  1050         PlaySound(sndRopeRelease);
   993     DeleteMe;
  1051         DeleteMe;
   994     exit
  1052         exit
   995     end;
  1053     end;
   996 
  1054 
   997 if (Gear^.Message and gm_Left  <> 0) then HHGear^.dX:= HHGear^.dX - _0_0002 else
  1055     if (Gear^.Message and gm_Left  <> 0) then HHGear^.dX := HHGear^.dX - _0_0002
   998 if (Gear^.Message and gm_Right <> 0) then HHGear^.dX:= HHGear^.dX + _0_0002;
  1056     else
   999 
  1057         if (Gear^.Message and gm_Right <> 0) then HHGear^.dX := HHGear^.dX + _0_0002;
  1000 if not TestCollisionYwithGear(HHGear, 1) then HHGear^.dY:= HHGear^.dY + cGravity;
  1058 
  1001 
  1059     if not TestCollisionYwithGear(HHGear, 1) then HHGear^.dY := HHGear^.dY + cGravity;
  1002 ropeDx:= HHGear^.X - Gear^.X; // vector between hedgehog and rope attaching point
  1060 
  1003 ropeDy:= HHGear^.Y - Gear^.Y;
  1061     ropeDx := HHGear^.X - Gear^.X;
  1004 
  1062     // vector between hedgehog and rope attaching point
  1005 mdX:= ropeDx + HHGear^.dX;
  1063     ropeDy := HHGear^.Y - Gear^.Y;
  1006 mdY:= ropeDy + HHGear^.dY;
  1064 
  1007 len:= _1 / Distance(mdX, mdY);
  1065     mdX := ropeDx + HHGear^.dX;
  1008 mdX:= mdX * len; // rope vector plus hedgehog direction vector normalized
  1066     mdY := ropeDy + HHGear^.dY;
  1009 mdY:= mdY * len;
  1067     len := _1 / Distance(mdX, mdY);
  1010 
  1068     mdX := mdX * len;
  1011 Gear^.dX:= mdX; // for visual purposes only
  1069     // rope vector plus hedgehog direction vector normalized
  1012 Gear^.dY:= mdY;
  1070     mdY := mdY * len;
  1013 
  1071 
  1014 /////
  1072     Gear^.dX := mdX;
  1015     tx:= HHGear^.X;
  1073     // for visual purposes only
  1016     ty:= HHGear^.Y;
  1074     Gear^.dY := mdY;
       
  1075 
       
  1076     /////
       
  1077     tx := HHGear^.X;
       
  1078     ty := HHGear^.Y;
  1017 
  1079 
  1018     if ((Gear^.Message and gm_Down) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
  1080     if ((Gear^.Message and gm_Down) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
  1019         if not (TestCollisionXwithGear(HHGear, hwSign(ropeDx))
  1081         if not (TestCollisionXwithGear(HHGear, hwSign(ropeDx))
  1020                 or TestCollisionYwithGear(HHGear, hwSign(ropeDy))) then
  1082            or TestCollisionYwithGear(HHGear, hwSign(ropeDy))) then
  1021                     Gear^.Elasticity:= Gear^.Elasticity + _0_3;
  1083             Gear^.Elasticity := Gear^.Elasticity + _0_3;
  1022 
  1084 
  1023     if ((Gear^.Message and gm_Up) <> 0) and (Gear^.Elasticity > _30) then
  1085     if ((Gear^.Message and gm_Up) <> 0) and (Gear^.Elasticity > _30) then
  1024         if not (TestCollisionXwithGear(HHGear, -hwSign(ropeDx))
  1086         if not (TestCollisionXwithGear(HHGear, -hwSign(ropeDx))
  1025                 or TestCollisionYwithGear(HHGear, -hwSign(ropeDy))) then
  1087            or TestCollisionYwithGear(HHGear, -hwSign(ropeDy))) then
  1026                     Gear^.Elasticity:= Gear^.Elasticity - _0_3;
  1088             Gear^.Elasticity := Gear^.Elasticity - _0_3;
  1027 
  1089 
  1028     HHGear^.X:= Gear^.X + mdX * Gear^.Elasticity;
  1090     HHGear^.X := Gear^.X + mdX * Gear^.Elasticity;
  1029     HHGear^.Y:= Gear^.Y + mdY * Gear^.Elasticity;
  1091     HHGear^.Y := Gear^.Y + mdY * Gear^.Elasticity;
  1030 
  1092 
  1031     HHGear^.dX:= HHGear^.X - tx;
  1093     HHGear^.dX := HHGear^.X - tx;
  1032     HHGear^.dY:= HHGear^.Y - ty;
  1094     HHGear^.dY := HHGear^.Y - ty;
  1033 ////
  1095     ////
  1034 
  1096 
  1035 
  1097 
  1036     haveDivided:= false;
  1098     haveDivided := false;
  1037     // check whether rope needs dividing
  1099     // check whether rope needs dividing
  1038     len:= _1 / Distance(ropeDx, ropeDy); // old rope pos
  1100     len := _1 / Distance(ropeDx, ropeDy);
  1039     nx:= ropeDx * len;
  1101     // old rope pos
  1040     ny:= ropeDy * len;
  1102     nx := ropeDx * len;
  1041 
  1103     ny := ropeDy * len;
  1042     len:= Gear^.Elasticity - _5;
  1104 
       
  1105     len := Gear^.Elasticity - _5;
  1043     while len > _3 do
  1106     while len > _3 do
       
  1107     begin
       
  1108         lx := hwRound(Gear^.X + mdX * len);
       
  1109         ly := hwRound(Gear^.Y + mdY * len);
       
  1110         if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (Land[ly, lx] <> 0
       
  1111            ) then
       
  1112         begin
       
  1113             with RopePoints.ar[RopePoints.Count] do
  1044             begin
  1114             begin
  1045             lx:= hwRound(Gear^.X + mdX * len);
  1115                 X := Gear^.X;
  1046             ly:= hwRound(Gear^.Y + mdY * len);
  1116                 Y := Gear^.Y;
  1047             if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (Land[ly, lx] <> 0) then
  1117                 if RopePoints.Count = 0 then RopePoints.HookAngle := DxDy2Angle(Gear^.dY, Gear^.dX);
  1048                 begin
  1118                 b := (nx * HHGear^.dY) > (ny * HHGear^.dX);
  1049                 with RopePoints.ar[RopePoints.Count] do
  1119                 dLen := len
  1050                     begin
       
  1051                     X:= Gear^.X;
       
  1052                     Y:= Gear^.Y;
       
  1053                     if RopePoints.Count = 0 then RopePoints.HookAngle:= DxDy2Angle(Gear^.dY, Gear^.dX);
       
  1054                     b:= (nx * HHGear^.dY) > (ny * HHGear^.dX);
       
  1055                     dLen:= len
       
  1056                     end;
       
  1057                 with RopePoints.rounded[RopePoints.Count] do
       
  1058                     begin
       
  1059                     X:= hwRound(Gear^.X);
       
  1060                     Y:= hwRound(Gear^.Y);
       
  1061                     end;
       
  1062 
       
  1063                 Gear^.X:= Gear^.X + nx * len;
       
  1064                 Gear^.Y:= Gear^.Y + ny * len;
       
  1065                 inc(RopePoints.Count);
       
  1066                 TryDo(RopePoints.Count <= MAXROPEPOINTS, 'Rope points overflow', true);
       
  1067                 Gear^.Elasticity:= Gear^.Elasticity - len;
       
  1068                 Gear^.Friction:= Gear^.Friction - len;
       
  1069                 haveDivided:= true;
       
  1070                 break
       
  1071                 end;
       
  1072             len:= len - _0_3 // should be the same as increase step
       
  1073             end;
  1120             end;
  1074 
  1121             with RopePoints.rounded[RopePoints.Count] do
  1075 if not haveDivided then
       
  1076     if RopePoints.Count > 0 then // check whether the last dividing point could be removed
       
  1077         begin
       
  1078         tx:= RopePoints.ar[Pred(RopePoints.Count)].X;
       
  1079         ty:= RopePoints.ar[Pred(RopePoints.Count)].Y;
       
  1080         mdX:= tx - Gear^.X;
       
  1081         mdY:= ty - Gear^.Y;
       
  1082         if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * (ty - HHGear^.Y) > (tx - HHGear^.X) * mdY) then
       
  1083             begin
  1122             begin
  1084             dec(RopePoints.Count);
  1123                 X := hwRound(Gear^.X);
  1085             Gear^.X:= RopePoints.ar[RopePoints.Count].X;
  1124                 Y := hwRound(Gear^.Y);
  1086             Gear^.Y:= RopePoints.ar[RopePoints.Count].Y;
  1125             end;
  1087             Gear^.Elasticity:= Gear^.Elasticity + RopePoints.ar[RopePoints.Count].dLen;
  1126 
  1088             Gear^.Friction:= Gear^.Friction + RopePoints.ar[RopePoints.Count].dLen;
  1127             Gear^.X := Gear^.X + nx * len;
  1089 
  1128             Gear^.Y := Gear^.Y + ny * len;
  1090             // restore hog position
  1129             inc(RopePoints.Count);
  1091             len:= _1 / Distance(mdX, mdY);
  1130             TryDo(RopePoints.Count <= MAXROPEPOINTS, 'Rope points overflow', true);
  1092             mdX:= mdX * len; 
  1131             Gear^.Elasticity := Gear^.Elasticity - len;
  1093             mdY:= mdY * len;
  1132             Gear^.Friction := Gear^.Friction - len;
  1094 
  1133             haveDivided := true;
  1095             HHGear^.X:= Gear^.X - mdX * Gear^.Elasticity;
  1134             break
  1096             HHGear^.Y:= Gear^.Y - mdY * Gear^.Elasticity;
  1135         end;
       
  1136         len := len - _0_3 // should be the same as increase step
       
  1137     end;
       
  1138 
       
  1139     if not haveDivided then
       
  1140         if RopePoints.Count > 0 then // check whether the last dividing point could be removed
       
  1141         begin
       
  1142             tx := RopePoints.ar[Pred(RopePoints.Count)].X;
       
  1143             ty := RopePoints.ar[Pred(RopePoints.Count)].Y;
       
  1144             mdX := tx - Gear^.X;
       
  1145             mdY := ty - Gear^.Y;
       
  1146             if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * (ty - HHGear^.Y) > (tx - HHGear^.X
       
  1147                ) * mdY) then
       
  1148             begin
       
  1149                 dec(RopePoints.Count);
       
  1150                 Gear^.X := RopePoints.ar[RopePoints.Count].X;
       
  1151                 Gear^.Y := RopePoints.ar[RopePoints.Count].Y;
       
  1152                 Gear^.Elasticity := Gear^.Elasticity + RopePoints.ar[RopePoints.Count].dLen;
       
  1153                 Gear^.Friction := Gear^.Friction + RopePoints.ar[RopePoints.Count].dLen;
       
  1154 
       
  1155                 // restore hog position
       
  1156                 len := _1 / Distance(mdX, mdY);
       
  1157                 mdX := mdX * len;
       
  1158                 mdY := mdY * len;
       
  1159 
       
  1160                 HHGear^.X := Gear^.X - mdX * Gear^.Elasticity;
       
  1161                 HHGear^.Y := Gear^.Y - mdY * Gear^.Elasticity;
  1097             end
  1162             end
  1098         end;
  1163         end;
  1099 
  1164 
  1100 haveCollision:= false;
  1165     haveCollision := false;
  1101 if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
  1166     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
  1102     begin
  1167     begin
  1103     HHGear^.dX:= -_0_6 * HHGear^.dX;
  1168         HHGear^.dX := -_0_6 * HHGear^.dX;
  1104     haveCollision:= true
  1169         haveCollision := true
  1105     end;
  1170     end;
  1106 if TestCollisionYwithGear(HHGear, hwSign(HHGear^.dY)) then
  1171     if TestCollisionYwithGear(HHGear, hwSign(HHGear^.dY)) then
  1107     begin
  1172     begin
  1108     HHGear^.dY:= -_0_6 * HHGear^.dY;
  1173         HHGear^.dY := -_0_6 * HHGear^.dY;
  1109     haveCollision:= true
  1174         haveCollision := true
  1110     end;
  1175     end;
  1111 
  1176 
  1112 if haveCollision
  1177     if haveCollision
  1113     and (Gear^.Message and (gm_Left or gm_Right) <> 0)
  1178        and (Gear^.Message and (gm_Left or gm_Right) <> 0)
  1114     and (Gear^.Message and (gm_Up or gm_Down) <> 0) then
  1179        and (Gear^.Message and (gm_Up or gm_Down) <> 0) then
  1115     begin
  1180     begin
  1116     HHGear^.dX:= SignAs(hwAbs(HHGear^.dX) + _0_2, HHGear^.dX);
  1181         HHGear^.dX := SignAs(hwAbs(HHGear^.dX) + _0_2, HHGear^.dX);
  1117     HHGear^.dY:= SignAs(hwAbs(HHGear^.dY) + _0_2, HHGear^.dY)
  1182         HHGear^.dY := SignAs(hwAbs(HHGear^.dY) + _0_2, HHGear^.dY)
  1118     end;
  1183     end;
  1119 
  1184 
  1120 len:= Distance(HHGear^.dX, HHGear^.dY);
  1185     len := Distance(HHGear^.dX, HHGear^.dY);
  1121 if len > _0_8 then
  1186     if len > _0_8 then
  1122     begin
  1187     begin
  1123     len:= _0_8 / len;
  1188         len := _0_8 / len;
  1124     HHGear^.dX:= HHGear^.dX * len;
  1189         HHGear^.dX := HHGear^.dX * len;
  1125     HHGear^.dY:= HHGear^.dY * len;
  1190         HHGear^.dY := HHGear^.dY * len;
  1126     end;
  1191     end;
  1127 
  1192 
  1128 if (Gear^.Message and gm_Attack) <> 0 then
  1193     if (Gear^.Message and gm_Attack) <> 0 then
  1129     if (Gear^.State and gsttmpFlag) <> 0 then
  1194         if (Gear^.State and gsttmpFlag) <> 0 then
  1130         with PHedgehog(Gear^.Hedgehog)^ do
  1195             with PHedgehog(Gear^.Hedgehog)^ do
  1131             begin
  1196             begin
  1132             PlaySound(sndRopeRelease);
  1197                 PlaySound(sndRopeRelease);
  1133             if Ammo^[CurSlot, CurAmmo].AmmoType <> amParachute then
  1198                 if Ammo^[CurSlot, CurAmmo].AmmoType <> amParachute then
  1134                 WaitCollision
  1199                     WaitCollision
  1135             else
  1200                 else
  1136                 DeleteMe
  1201                     DeleteMe
  1137             end
  1202             end
  1138     else
  1203     else
  1139 else
  1204     else
  1140     if (Gear^.State and gsttmpFlag) = 0 then
  1205         if (Gear^.State and gsttmpFlag) = 0 then
  1141         Gear^.State:= Gear^.State or gsttmpFlag;
  1206             Gear^.State := Gear^.State or gsttmpFlag;
  1142 end;
  1207 end;
  1143 
  1208 
  1144 procedure doStepRopeAttach(Gear: PGear);
  1209 procedure doStepRopeAttach(Gear: PGear);
  1145 var HHGear: PGear;
  1210 var 
       
  1211     HHGear: PGear;
  1146     tx, ty, tt: hwFloat;
  1212     tx, ty, tt: hwFloat;
  1147 
  1213 
  1148     procedure RemoveFromAmmo;
  1214 procedure RemoveFromAmmo;
  1149     begin
  1215 begin
  1150     if (Gear^.State and gstAttacked) = 0 then
  1216     if (Gear^.State and gstAttacked) = 0 then
  1151         begin
  1217     begin
  1152         OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^);
  1218         OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^);
  1153         Gear^.State:= Gear^.State or gstAttacked
  1219         Gear^.State := Gear^.State or gstAttacked
  1154         end;
  1220     end;
  1155     ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^)
  1221     ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^)
  1156     end;
  1222 end;
  1157 
  1223 
  1158 begin
  1224 begin
  1159 Gear^.X:= Gear^.X - Gear^.dX;
  1225     Gear^.X := Gear^.X - Gear^.dX;
  1160 Gear^.Y:= Gear^.Y - Gear^.dY;
  1226     Gear^.Y := Gear^.Y - Gear^.dY;
  1161 Gear^.Elasticity:= Gear^.Elasticity + _1;
  1227     Gear^.Elasticity := Gear^.Elasticity + _1;
  1162 
  1228 
  1163 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
  1229     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
  1164 DeleteCI(HHGear);
  1230     DeleteCI(HHGear);
  1165 
  1231 
  1166 if (HHGear^.State and gstMoving) <> 0 then
  1232     if (HHGear^.State and gstMoving) <> 0 then
  1167     begin
  1233     begin
  1168     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
  1234         if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
  1169     if HHGear^.dY.isNegative and TestCollisionYwithGear(HHGear, -1) then HHGear^.dY:= _0;
  1235         if HHGear^.dY.isNegative and TestCollisionYwithGear(HHGear, -1) then HHGear^.dY := _0;
  1170 
  1236 
  1171     HHGear^.X:= HHGear^.X + HHGear^.dX;
  1237         HHGear^.X := HHGear^.X + HHGear^.dX;
  1172     Gear^.X:= Gear^.X + HHGear^.dX;
  1238         Gear^.X := Gear^.X + HHGear^.dX;
  1173 
  1239 
  1174     if TestCollisionYwithGear(HHGear, 1) then
  1240         if TestCollisionYwithGear(HHGear, 1) then
  1175         begin
  1241         begin
  1176         CheckHHDamage(HHGear);
  1242             CheckHHDamage(HHGear);
  1177         HHGear^.dY:= _0;
  1243             HHGear^.dY := _0;
  1178         //HHGear^.State:= HHGear^.State and not (gstHHJumping or gstHHHJump);
  1244             //HHGear^.State:= HHGear^.State and not (gstHHJumping or gstHHHJump);
  1179         end else
  1245         end
  1180         begin
  1246         else
  1181         HHGear^.Y:= HHGear^.Y + HHGear^.dY;
  1247         begin
  1182         Gear^.Y:= Gear^.Y + HHGear^.dY;
  1248             HHGear^.Y := HHGear^.Y + HHGear^.dY;
  1183         HHGear^.dY:= HHGear^.dY + cGravity;
  1249             Gear^.Y := Gear^.Y + HHGear^.dY;
  1184         end;
  1250             HHGear^.dY := HHGear^.dY + cGravity;
  1185         
  1251         end;
  1186     tt:= Gear^.Elasticity;
  1252 
  1187     tx:= _0;
  1253         tt := Gear^.Elasticity;
  1188     ty:= _0;
  1254         tx := _0;
  1189     while tt > _20 do
  1255         ty := _0;
  1190         begin
  1256         while tt > _20 do
  1191         if  TestCollisionXwithXYShift(Gear, tx, hwRound(ty), -hwSign(Gear^.dX))
  1257         begin
  1192         or TestCollisionYwithXYShift(Gear, hwRound(tx), hwRound(ty), -hwSign(Gear^.dY)) then
  1258             if  TestCollisionXwithXYShift(Gear, tx, hwRound(ty), -hwSign(Gear^.dX))
       
  1259                or TestCollisionYwithXYShift(Gear, hwRound(tx), hwRound(ty), -hwSign(Gear^.dY)) then
  1193             begin
  1260             begin
  1194             Gear^.X:= Gear^.X + tx;
  1261                 Gear^.X := Gear^.X + tx;
  1195             Gear^.Y:= Gear^.Y + ty;
  1262                 Gear^.Y := Gear^.Y + ty;
  1196             Gear^.Elasticity:= tt;
  1263                 Gear^.Elasticity := tt;
  1197             Gear^.doStep:= @doStepRopeWork;
  1264                 Gear^.doStep := @doStepRopeWork;
  1198             PlaySound(sndRopeAttach);
  1265                 PlaySound(sndRopeAttach);
  1199             with HHGear^ do State:= State and not (gstAttacking or gstHHJumping or gstHHHJump);
  1266                 with HHGear^ do
  1200 
  1267                     State := State and not (gstAttacking or gstHHJumping or gstHHHJump);
  1201             RemoveFromAmmo;
  1268 
  1202 
  1269                 RemoveFromAmmo;
  1203             tt:= _0;
  1270 
  1204             exit
  1271                 tt := _0;
       
  1272                 exit
  1205             end;
  1273             end;
  1206         tx:= tx + Gear^.dX + Gear^.dX;
  1274             tx := tx + Gear^.dX + Gear^.dX;
  1207         ty:= ty + Gear^.dY + Gear^.dY;
  1275             ty := ty + Gear^.dY + Gear^.dY;
  1208         tt:= tt - _2;
  1276             tt := tt - _2;
  1209         end;
  1277         end;
  1210     end;
  1278     end;
  1211 
  1279 
  1212 CheckCollision(Gear);
  1280     CheckCollision(Gear);
  1213 
  1281 
  1214 if (Gear^.State and gstCollision) <> 0 then
  1282     if (Gear^.State and gstCollision) <> 0 then
  1215     if Gear^.Elasticity < _10 then
  1283         if Gear^.Elasticity < _10 then
  1216         Gear^.Elasticity:= _10000
  1284             Gear^.Elasticity := _10000
  1217     else
  1285     else
  1218         begin
  1286     begin
  1219         Gear^.doStep:= @doStepRopeWork;
  1287         Gear^.doStep := @doStepRopeWork;
  1220         PlaySound(sndRopeAttach);
  1288         PlaySound(sndRopeAttach);
  1221         with HHGear^ do State:= State and not (gstAttacking or gstHHJumping or gstHHHJump);
  1289         with HHGear^ do
       
  1290             State := State and not (gstAttacking or gstHHJumping or gstHHHJump);
  1222 
  1291 
  1223         RemoveFromAmmo;
  1292         RemoveFromAmmo;
  1224 
  1293 
  1225         exit
  1294         exit
  1226         end;
  1295     end;
  1227 
  1296 
  1228 if (Gear^.Elasticity > Gear^.Friction)
  1297     if (Gear^.Elasticity > Gear^.Friction)
  1229 or ((Gear^.Message and gm_Attack) = 0)
  1298        or ((Gear^.Message and gm_Attack) = 0)
  1230 or ((HHGear^.State and gstHHDriven) = 0)
  1299        or ((HHGear^.State and gstHHDriven) = 0)
  1231 or (HHGear^.Damage > 0) then
  1300        or (HHGear^.Damage > 0) then
  1232     begin
  1301     begin
  1233     with PHedgehog(Gear^.Hedgehog)^.Gear^ do
  1302         with PHedgehog(Gear^.Hedgehog)^.Gear^ do
  1234         begin
  1303         begin
  1235         State:= State and not gstAttacking;
  1304             State := State and not gstAttacking;
  1236         Message:= Message and not gm_Attack
  1305             Message := Message and not gm_Attack
  1237         end;
  1306         end;
  1238     DeleteGear(Gear)
  1307         DeleteGear(Gear)
  1239     end
  1308     end
  1240 end;
  1309 end;
  1241 
  1310 
  1242 procedure doStepRope(Gear: PGear);
  1311 procedure doStepRope(Gear: PGear);
  1243 begin
  1312 begin
  1244 Gear^.dX:= - Gear^.dX;
  1313     Gear^.dX := - Gear^.dX;
  1245 Gear^.dY:= - Gear^.dY;
  1314     Gear^.dY := - Gear^.dY;
  1246 Gear^.doStep:= @doStepRopeAttach;
  1315     Gear^.doStep := @doStepRopeAttach;
  1247 PlaySound(sndRopeShot)
  1316     PlaySound(sndRopeShot)
  1248 end;
  1317 end;
  1249 
  1318 
  1250 ////////////////////////////////////////////////////////////////////////////////
  1319 ////////////////////////////////////////////////////////////////////////////////
  1251 procedure doStepMine(Gear: PGear);
  1320 procedure doStepMine(Gear: PGear);
  1252 begin
  1321 begin
  1253 if (Gear^.State and gstMoving) <> 0 then
  1322     if (Gear^.State and gstMoving) <> 0 then
  1254     begin
  1323     begin
  1255     DeleteCI(Gear);
  1324         DeleteCI(Gear);
  1256     doStepFallingGear(Gear);
       
  1257     if (Gear^.State and gstMoving) = 0 then
       
  1258         begin
       
  1259         AddGearCI(Gear);
       
  1260         Gear^.dX:= _0;
       
  1261         Gear^.dY:= _0
       
  1262         end;
       
  1263     CalcRotationDirAngle(Gear);
       
  1264     AllInactive:= false
       
  1265     end else
       
  1266     if ((GameTicks and $3F) = 25) then
       
  1267         doStepFallingGear(Gear);
  1325         doStepFallingGear(Gear);
  1268 
  1326         if (Gear^.State and gstMoving) = 0 then
  1269 if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
  1327         begin
  1270     if ((Gear^.State and gstAttacking) = 0) then
  1328             AddGearCI(Gear);
  1271         begin
  1329             Gear^.dX := _0;
  1272         if ((GameTicks and $1F) = 0) then
  1330             Gear^.dY := _0
  1273             if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then Gear^.State:= Gear^.State or gstAttacking
  1331         end;
  1274         end else // gstAttacking <> 0
  1332         CalcRotationDirAngle(Gear);
  1275         begin
  1333         AllInactive := false
  1276         AllInactive:= false;
  1334     end
       
  1335     else
       
  1336         if ((GameTicks and $3F) = 25) then
       
  1337             doStepFallingGear(Gear);
       
  1338 
       
  1339     if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
       
  1340         if ((Gear^.State and gstAttacking) = 0) then
       
  1341         begin
       
  1342             if ((GameTicks and $1F) = 0) then
       
  1343                 if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then Gear^.State := Gear^.State or
       
  1344                                                                                       gstAttacking
       
  1345         end
       
  1346     else // gstAttacking <> 0
       
  1347     begin
       
  1348         AllInactive := false;
  1277         if (Gear^.Timer and $FF) = 0 then PlaySound(sndMineTick);
  1349         if (Gear^.Timer and $FF) = 0 then PlaySound(sndMineTick);
  1278         if Gear^.Timer = 0 then
  1350         if Gear^.Timer = 0 then
  1279             begin
  1351         begin
  1280             if ((Gear^.State and gstWait) <> 0) or 
  1352             if ((Gear^.State and gstWait) <> 0) or
  1281                (cMineDudPercent = 0) or
  1353                (cMineDudPercent = 0) or
  1282                (getRandom(100) > cMineDudPercent) then
  1354                (getRandom(100) > cMineDudPercent) then
  1283                begin
  1355             begin
  1284                doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
  1356                 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
  1285                DeleteGear(Gear)
  1357                 DeleteGear(Gear)
  1286                end
  1358             end
  1287             else
  1359             else
  1288                begin
  1360             begin
  1289                AddVisualGear(hwRound(Gear^.X) - 4  + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
  1361                 AddVisualGear(hwRound(Gear^.X) - 4  + Random(8), hwRound(Gear^.Y) - 4 - Random(4),
  1290                PlaySound(sndVaporize);
  1362                 vgtSmoke);
  1291                Gear^.Health:= 0;
  1363                 PlaySound(sndVaporize);
  1292                end;
  1364                 Gear^.Health := 0;
       
  1365             end;
  1293             exit
  1366             exit
  1294             end;
  1367         end;
  1295         dec(Gear^.Timer);
  1368         dec(Gear^.Timer);
  1296         end else // gsttmpFlag = 0
  1369     end
  1297     if TurnTimeLeft = 0 then Gear^.State:= Gear^.State or gsttmpFlag;
  1370     else // gsttmpFlag = 0
       
  1371         if TurnTimeLeft = 0 then Gear^.State := Gear^.State or gsttmpFlag;
  1298 end;
  1372 end;
  1299 
  1373 
  1300 ////////////////////////////////////////////////////////////////////////////////
  1374 ////////////////////////////////////////////////////////////////////////////////
  1301 procedure doStepDynamite(Gear: PGear);
  1375 procedure doStepDynamite(Gear: PGear);
  1302 begin
  1376 begin
  1303 doStepFallingGear(Gear);
  1377     doStepFallingGear(Gear);
  1304 AllInactive:= false;
  1378     AllInactive := false;
  1305 if Gear^.Timer mod 166 = 0 then inc(Gear^.Tag);
  1379     if Gear^.Timer mod 166 = 0 then inc(Gear^.Tag);
  1306 if Gear^.Timer = 1000 then // might need better timing
  1380     if Gear^.Timer = 1000 then // might need better timing
  1307     makeHogsWorry(Gear^.X, Gear^.Y, 75);
  1381         makeHogsWorry(Gear^.X, Gear^.Y, 75);
  1308 if Gear^.Timer = 0 then
  1382     if Gear^.Timer = 0 then
  1309     begin
  1383     begin
  1310     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 75, EXPLAutoSound);
  1384         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 75, EXPLAutoSound);
  1311     DeleteGear(Gear);
  1385         DeleteGear(Gear);
  1312     exit
  1386         exit
  1313     end;
  1387     end;
  1314 dec(Gear^.Timer);
  1388     dec(Gear^.Timer);
  1315 end;
  1389 end;
  1316 
  1390 
  1317 ///////////////////////////////////////////////////////////////////////////////
  1391 ///////////////////////////////////////////////////////////////////////////////
  1318 
  1392 
  1319 (*
  1393 (*
  1320 TODO
  1394 TODO
  1321 Increase damage as barrel smokes?
  1395 Increase damage as barrel smokes?
  1322 Try tweaking friction some more
  1396 Try tweaking friction some more
  1323 *)
  1397 *)
  1324 procedure doStepRollingBarrel(Gear: PGear);
  1398 procedure doStepRollingBarrel(Gear: PGear);
  1325 var i: LongInt;
  1399 var 
       
  1400     i: LongInt;
  1326     particle: PVisualGear;
  1401     particle: PVisualGear;
  1327 begin
  1402 begin
  1328 Gear^.State:= Gear^.State or gstAnimation;
  1403     Gear^.State := Gear^.State or gstAnimation;
  1329 if ((Gear^.dX.QWordValue <> 0) or (Gear^.dY.QWordValue <> 0))  then
  1404     if ((Gear^.dX.QWordValue <> 0) or (Gear^.dY.QWordValue <> 0))  then
  1330     begin
  1405     begin
  1331     DeleteCI(Gear);
  1406         DeleteCI(Gear);
  1332     AllInactive:= false;
  1407         AllInactive := false;
  1333     if not Gear^.dY.isNegative and (Gear^.dY > _0_03) and TestCollisionYwithGear(Gear, 1) then
  1408         if not Gear^.dY.isNegative and (Gear^.dY > _0_03) and TestCollisionYwithGear(Gear, 1) then
  1334         begin
  1409         begin
  1335         Gear^.State:= Gear^.State or gsttmpFlag;
  1410             Gear^.State := Gear^.State or gsttmpFlag;
  1336         inc(Gear^.Damage, hwRound(Gear^.dY * _50));
  1411             inc(Gear^.Damage, hwRound(Gear^.dY * _50));
  1337         for i:= min(12, hwRound(Gear^.dY*_10)) downto 0 do 
  1412             for i:= min(12, hwRound(Gear^.dY*_10)) downto 0 do
  1338             begin
  1413             begin
  1339             particle:= AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
  1414                 particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12,
  1340             if particle <> nil then particle^.dX := particle^.dX + (Gear^.dX / 5)
  1415                             vgtDust);
       
  1416                 if particle <> nil then particle^.dX := particle^.dX + (Gear^.dX / 5)
  1341             end
  1417             end
  1342         end
  1418         end
  1343     else if not Gear^.dX.isNegative and (Gear^.dX > _0_03) and TestCollisionXwithGear(Gear, 1) then
  1419         else if not Gear^.dX.isNegative and (Gear^.dX > _0_03) and TestCollisionXwithGear(Gear, 1)
  1344         inc(Gear^.Damage, hwRound(Gear^.dX * _50))
  1420                  then
  1345     else if Gear^.dY.isNegative and (Gear^.dY < -_0_03) and TestCollisionYwithGear(Gear, -1) then
  1421                  inc(Gear^.Damage, hwRound(Gear^.dX * _50))
  1346         inc(Gear^.Damage, hwRound(Gear^.dY * -_50))
  1422         else if Gear^.dY.isNegative and (Gear^.dY < -_0_03) and TestCollisionYwithGear(Gear, -1)
  1347     else if Gear^.dX.isNegative and (Gear^.dX < -_0_03) and TestCollisionXwithGear(Gear, -1) then
  1423                  then
  1348         inc(Gear^.Damage, hwRound(Gear^.dX * -_50));
  1424                  inc(Gear^.Damage, hwRound(Gear^.dY * -_50))
  1349     
  1425         else if Gear^.dX.isNegative and (Gear^.dX < -_0_03) and TestCollisionXwithGear(Gear, -1)
  1350     doStepFallingGear(Gear);
  1426                  then
  1351     CalcRotationDirAngle(Gear);
  1427                  inc(Gear^.Damage, hwRound(Gear^.dX * -_50));
  1352     //CheckGearDrowning(Gear)
  1428 
  1353     end
  1429         doStepFallingGear(Gear);
  1354 else 
  1430         CalcRotationDirAngle(Gear);
  1355     begin
  1431         //CheckGearDrowning(Gear)
  1356     Gear^.State:= Gear^.State or gsttmpFlag;
  1432     end
  1357     AddGearCI(Gear)
  1433     else
  1358     end;
  1434     begin
       
  1435         Gear^.State := Gear^.State or gsttmpFlag;
       
  1436         AddGearCI(Gear)
       
  1437     end;
       
  1438 
  1359 (*
  1439 (*
  1360 Attempt to make a barrel knock itself over an edge.  Would need more checks to avoid issues like burn damage
  1440 Attempt to make a barrel knock itself over an edge.  Would need more checks to avoid issues like burn damage
  1361     begin
  1441     begin
  1362     x:= hwRound(Gear^.X);
  1442     x:= hwRound(Gear^.X);
  1363     y:= hwRound(Gear^.Y);
  1443     y:= hwRound(Gear^.Y);
  1370                 Gear^.dX:= _0_08;
  1450                 Gear^.dX:= _0_08;
  1371             end;
  1451             end;
  1372     if Gear^.dX.QWordValue = 0 then AddGearCI(Gear)
  1452     if Gear^.dX.QWordValue = 0 then AddGearCI(Gear)
  1373     end; *)
  1453     end; *)
  1374 
  1454 
  1375 if not Gear^.dY.isNegative and (Gear^.dY < _0_001) and TestCollisionYwithGear(Gear, 1) then Gear^.dY:= _0;
  1455     if not Gear^.dY.isNegative and (Gear^.dY < _0_001) and TestCollisionYwithGear(Gear, 1) then Gear
  1376 if hwAbs(Gear^.dX) < _0_001 then Gear^.dX:= _0;
  1456         ^.dY := _0;
  1377     
  1457     if hwAbs(Gear^.dX) < _0_001 then Gear^.dX := _0;
  1378 if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
  1458 
  1379     if (cBarrelHealth div Gear^.Health) > 2 then 
  1459     if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
  1380         AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
  1460         if (cBarrelHealth div Gear^.Health) > 2 then
       
  1461             AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
  1381     else
  1462     else
  1382         AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
  1463         AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
  1383 dec(Gear^.Health, Gear^.Damage);
  1464     dec(Gear^.Health, Gear^.Damage);
  1384 Gear^.Damage:= 0;
  1465     Gear^.Damage := 0;
  1385 if Gear^.Health <= 0 then Gear^.doStep:= @doStepCase; // Hand off to doStepCase for the explosion
  1466     if Gear^.Health <= 0 then Gear^.doStep := @doStepCase;
       
  1467     // Hand off to doStepCase for the explosion
  1386 
  1468 
  1387 end;
  1469 end;
  1388 
  1470 
  1389 procedure doStepCase(Gear: PGear);
  1471 procedure doStepCase(Gear: PGear);
  1390 var i, x, y: LongInt;
  1472 var 
       
  1473     i, x, y: LongInt;
  1391     k: TGearType;
  1474     k: TGearType;
  1392     exBoom: boolean;
  1475     exBoom: boolean;
  1393     dX, dY: HWFloat;
  1476     dX, dY: HWFloat;
  1394 begin
  1477 begin
  1395 k:= Gear^.Kind;
  1478     k := Gear^.Kind;
  1396 exBoom:= false;
  1479     exBoom := false;
  1397 
  1480 
  1398 if (Gear^.Message and gm_Destroy) > 0 then
  1481     if (Gear^.Message and gm_Destroy) > 0 then
  1399     begin
  1482     begin
  1400     DeleteGear(Gear);
  1483         DeleteGear(Gear);
  1401     FreeActionsList;
  1484         FreeActionsList;
  1402     SetAllToActive; // something (hh, mine, etc...) could be on top of the case
  1485         SetAllToActive;
  1403     with CurrentHedgehog^ do
  1486         // something (hh, mine, etc...) could be on top of the case
  1404         if Gear <> nil then Gear^.Message:= Gear^.Message and not (gm_LJump or gm_HJump);
  1487         with CurrentHedgehog^ do
  1405     exit
  1488             if Gear <> nil then Gear^.Message := Gear^.Message and not (gm_LJump or gm_HJump);
  1406     end;
  1489         exit
  1407 
  1490     end;
  1408 if k = gtExplosives then
  1491 
  1409     begin
  1492     if k = gtExplosives then
  1410     //if V > _0_03 then Gear^.State:= Gear^.State or gstAnimation;
  1493     begin
  1411     if (hwAbs(Gear^.dX) > _0_15) or ((hwAbs(Gear^.dY) > _0_15) and (hwAbs(Gear^.dX) > _0_02)) then Gear^.doStep:= @doStepRollingBarrel;
  1494         //if V > _0_03 then Gear^.State:= Gear^.State or gstAnimation;
  1412     
  1495         if (hwAbs(Gear^.dX) > _0_15) or ((hwAbs(Gear^.dY) > _0_15) and (hwAbs(Gear^.dX) > _0_02))
  1413     if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
  1496             then Gear^.doStep := @doStepRollingBarrel;
  1414         if (cBarrelHealth div Gear^.Health) > 2 then 
  1497 
  1415             AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
  1498         if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
       
  1499             if (cBarrelHealth div Gear^.Health) > 2 then
       
  1500                 AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
  1416         else
  1501         else
  1417             AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
  1502             AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
  1418     dec(Gear^.Health, Gear^.Damage);
  1503         dec(Gear^.Health, Gear^.Damage);
  1419     Gear^.Damage:= 0;
  1504         Gear^.Damage := 0;
  1420     if Gear^.Health <= 0 then
  1505         if Gear^.Health <= 0 then
  1421         exBoom:= true;
  1506             exBoom := true;
  1422     end;
  1507     end;
  1423 
  1508 
  1424 if (Gear^.Damage > 0) or exBoom then
  1509     if (Gear^.Damage > 0) or exBoom then
  1425     begin
  1510     begin
  1426     x:= hwRound(Gear^.X);
  1511         x := hwRound(Gear^.X);
  1427     y:= hwRound(Gear^.Y);
  1512         y := hwRound(Gear^.Y);
  1428     DeleteGear(Gear); // <-- delete gear!
  1513         DeleteGear(Gear);
  1429 
  1514         // <-- delete gear!
  1430     if k = gtCase then
  1515 
  1431         begin
  1516         if k = gtCase then
  1432         doMakeExplosion(x, y, 25, EXPLAutoSound);
  1517         begin
  1433         for i:= 0 to 63 do
  1518             doMakeExplosion(x, y, 25, EXPLAutoSound);
  1434             AddGear(x, y, gtFlame, 0, _0, _0, 0);
  1519             for i:= 0 to 63 do
       
  1520                 AddGear(x, y, gtFlame, 0, _0, _0, 0);
  1435         end
  1521         end
  1436     else if k = gtExplosives then
  1522         else if k = gtExplosives then
  1437         begin
       
  1438         doMakeExplosion(x, y, 75, EXPLAutoSound);
       
  1439         for i:= 0 to 31 do
       
  1440             begin
  1523             begin
  1441             dX:= AngleCos(i * 64) * _0_5 * (getrandom + _1);
  1524                 doMakeExplosion(x, y, 75, EXPLAutoSound);
  1442             dY:= AngleSin(i * 64) * _0_5 * (getrandom + _1);
  1525                 for i:= 0 to 31 do
  1443             AddGear(x, y, gtFlame, 0, dX, dY, 0);
  1526                 begin
  1444             AddGear(x, y, gtFlame, 0, -dX, -dY, 0)^.State:= gsttmpFlag;
  1527                     dX := AngleCos(i * 64) * _0_5 * (getrandom + _1);
       
  1528                     dY := AngleSin(i * 64) * _0_5 * (getrandom + _1);
       
  1529                     AddGear(x, y, gtFlame, 0, dX, dY, 0);
       
  1530                     AddGear(x, y, gtFlame, 0, -dX, -dY, 0)^.State := gsttmpFlag;
       
  1531                 end
       
  1532             end;
       
  1533         exit
       
  1534     end;
       
  1535 
       
  1536     if (Gear^.dY.QWordValue <> 0) or (not TestCollisionYwithGear(Gear, 1)) then
       
  1537     begin
       
  1538         AllInactive := false;
       
  1539         Gear^.dY := Gear^.dY + cGravity;
       
  1540         Gear^.Y := Gear^.Y + Gear^.dY;
       
  1541         if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then SetAllHHToActive;
       
  1542         if (Gear^.dY.isNegative) and TestCollisionYwithGear(Gear, -1) then Gear^.dY := _0;
       
  1543         if (not Gear^.dY.isNegative) and TestCollisionYwithGear(Gear, 1) then
       
  1544         begin
       
  1545             if (Gear^.dY > _0_02) and (k = gtExplosives) then
       
  1546                 inc(Gear^.Damage, hwRound(Gear^.dY * _40));
       
  1547 
       
  1548             if Gear^.dY > _0_2 then
       
  1549                 for i:= min(12, hwRound(Gear^.dY*_10)) downto 0 do
       
  1550                     AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust)
       
  1551             ;
       
  1552             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
       
  1553             if Gear^.dY > - _0_001 then Gear^.dY := _0
       
  1554             else if Gear^.dY < - _0_03 then
       
  1555                      PlaySound(Gear^.ImpactSound);
       
  1556         end;
       
  1557         //if Gear^.dY > - _0_001 then Gear^.dY:= _0
       
  1558         CheckGearDrowning(Gear);
       
  1559     end;
       
  1560 
       
  1561     if (Gear^.dY.QWordValue = 0) then AddGearCI(Gear)
       
  1562     else if (Gear^.dY.QWordValue <> 0) then DeleteCI(Gear)
       
  1563 end;
       
  1564 
       
  1565 ////////////////////////////////////////////////////////////////////////////////
       
  1566 
       
  1567 procedure doStepTarget(Gear: PGear);
       
  1568 begin
       
  1569     if (Gear^.Timer = 0) and (Gear^.Tag = 0) then
       
  1570         PlaySound(sndWarp);
       
  1571 
       
  1572     if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then
       
  1573         inc(Gear^.Timer)
       
  1574     else if Gear^.Tag = 1 then
       
  1575         begin
       
  1576             Gear^.Tag := 2;
       
  1577             if (TrainingFlags and tfTimeTrial) <> 0 then
       
  1578             begin
       
  1579                 inc(TurnTimeLeft, TrainingTimeInc);
       
  1580 
       
  1581                 if TrainingTimeInc > TrainingTimeInM then
       
  1582                     dec(TrainingTimeInc, TrainingTimeInD);
       
  1583                 if TurnTimeLeft > TrainingTimeMax then
       
  1584                     TurnTimeLeft := TrainingTimeMax;
       
  1585             end;
       
  1586         end
       
  1587     else if Gear^.Tag = 2 then
       
  1588              if Gear^.Timer > 0 then
       
  1589                  dec(Gear^.Timer)
       
  1590     else
       
  1591     begin
       
  1592         if (TrainingFlags and tfTargetRespawn) <> 0 then
       
  1593         begin
       
  1594             TrainingTargetGear := AddGear(0, 0, gtTarget, 0, _0, _0, 0);
       
  1595             FindPlace(TrainingTargetGear, false, 0, LAND_WIDTH);
       
  1596         end;
       
  1597         DeleteGear(Gear);
       
  1598         exit;
       
  1599     end;
       
  1600 
       
  1601     doStepCase(Gear)
       
  1602 end;
       
  1603 
       
  1604 ////////////////////////////////////////////////////////////////////////////////
       
  1605 procedure doStepIdle(Gear: PGear);
       
  1606 begin
       
  1607     AllInactive := false;
       
  1608     dec(Gear^.Timer);
       
  1609     if Gear^.Timer = 0 then
       
  1610     begin
       
  1611         DeleteGear(Gear);
       
  1612         AfterAttack
       
  1613     end
       
  1614 end;
       
  1615 
       
  1616 procedure doStepShover(Gear: PGear);
       
  1617 var 
       
  1618     HHGear: PGear;
       
  1619 begin
       
  1620     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1621     HHGear^.State := HHGear^.State or gstNoDamage;
       
  1622     DeleteCI(HHGear);
       
  1623 
       
  1624     AmmoShove(Gear, 30, 115);
       
  1625 
       
  1626     HHGear^.State := HHGear^.State and not gstNoDamage;
       
  1627     Gear^.Timer := 250;
       
  1628     Gear^.doStep := @doStepIdle
       
  1629 end;
       
  1630 
       
  1631 ////////////////////////////////////////////////////////////////////////////////
       
  1632 procedure doStepWhip(Gear: PGear);
       
  1633 var 
       
  1634     HHGear: PGear;
       
  1635     i: LongInt;
       
  1636 begin
       
  1637     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1638     HHGear^.State := HHGear^.State or gstNoDamage;
       
  1639     DeleteCI(HHGear);
       
  1640 
       
  1641     for i:= 0 to 3 do
       
  1642     begin
       
  1643         AmmoShove(Gear, 30, 25);
       
  1644         Gear^.X := Gear^.X + Gear^.dX * 5
       
  1645     end;
       
  1646 
       
  1647     HHGear^.State := HHGear^.State and not gstNoDamage;
       
  1648     Gear^.Timer := 250;
       
  1649     Gear^.doStep := @doStepIdle
       
  1650 end;
       
  1651 
       
  1652 ////////////////////////////////////////////////////////////////////////////////
       
  1653 procedure doStepFlame(Gear: PGear);
       
  1654 var 
       
  1655     gX,gY,i: LongInt;
       
  1656 begin
       
  1657     if (Gear^.State and gsttmpFlag) = 0 then AllInactive := false;
       
  1658 
       
  1659     if not TestCollisionYwithGear(Gear, 1) then
       
  1660     begin
       
  1661         AllInactive := false;
       
  1662         if Gear^.dX.QWordValue > _0_01.QWordValue then
       
  1663             Gear^.dX := Gear^.dX * _0_995;
       
  1664         Gear^.dY := Gear^.dY + cGravity;
       
  1665         if (Gear^.State and gsttmpFlag) <> 0 then Gear^.dY := Gear^.dY + cGravity;
       
  1666         if Gear^.dY.QWordValue > _0_2.QWordValue then Gear^.dY := Gear^.dY * _0_995;
       
  1667 
       
  1668         if (Gear^.State and gsttmpFlag) <> 0 then Gear^.X := Gear^.X + Gear^.dX
       
  1669         else
       
  1670             Gear^.X := Gear^.X + Gear^.dX + cWindSpeed * 640;
       
  1671         Gear^.Y := Gear^.Y + Gear^.dY;
       
  1672 
       
  1673         if (hwRound(Gear^.Y) > cWaterLine) then
       
  1674         begin
       
  1675             gX := hwRound(Gear^.X);
       
  1676             for i:= 0 to 3 do
       
  1677                 AddVisualGear(gX - 16 + Random(32), cWaterLine - 16 + Random(16), vgtSteam);
       
  1678             PlaySound(sndVaporize);
       
  1679             DeleteGear(Gear);
       
  1680             exit
       
  1681         end
       
  1682     end
       
  1683     else
       
  1684     begin
       
  1685         if (Gear^.State and gsttmpFlag) <> 0 then
       
  1686         begin
       
  1687             Gear^.Radius := 9;
       
  1688             AmmoShove(Gear, 2, 30);
       
  1689             Gear^.Radius := 1
       
  1690         end;
       
  1691         if Gear^.Timer > 0 then
       
  1692         begin
       
  1693             dec(Gear^.Timer);
       
  1694             inc(Gear^.Damage)
       
  1695         end
       
  1696         else
       
  1697         begin
       
  1698             // Standard fire
       
  1699             if (Gear^.State and gsttmpFlag) = 0 then
       
  1700             begin
       
  1701                 Gear^.Radius := 9;
       
  1702                 AmmoShove(Gear, 4, 100);
       
  1703                 gX := hwRound(Gear^.X);
       
  1704                 gY := hwRound(Gear^.Y);
       
  1705                 Gear^.Radius := 1;
       
  1706                 doMakeExplosion(gX, gY, 4, EXPLNoDamage);
       
  1707                 if ((GameTicks and $7) = 0) and (Random(2) = 0) then
       
  1708                     for i:= 1 to Random(2)+1 do
       
  1709                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
       
  1710                 if Gear^.Health > 0 then dec(Gear^.Health);
       
  1711                 Gear^.Timer := 450 - Gear^.Tag * 8
  1445             end
  1712             end
  1446         end;
  1713             else
  1447     exit
       
  1448     end;
       
  1449 
       
  1450 if (Gear^.dY.QWordValue <> 0) or (not TestCollisionYwithGear(Gear, 1)) then
       
  1451     begin
       
  1452     AllInactive:= false;
       
  1453     Gear^.dY:= Gear^.dY + cGravity;
       
  1454     Gear^.Y:= Gear^.Y + Gear^.dY;
       
  1455     if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then SetAllHHToActive;
       
  1456     if (Gear^.dY.isNegative) and TestCollisionYwithGear(Gear, -1) then Gear^.dY:= _0;
       
  1457     if (not Gear^.dY.isNegative) and TestCollisionYwithGear(Gear, 1) then
       
  1458         begin
       
  1459         if (Gear^.dY > _0_02) and (k = gtExplosives) then
       
  1460             inc(Gear^.Damage, hwRound(Gear^.dY * _40));
       
  1461 
       
  1462         if Gear^.dY > _0_2 then
       
  1463             for i:= min(12, hwRound(Gear^.dY*_10)) downto 0 do 
       
  1464                 AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
       
  1465         Gear^.dY:= - Gear^.dY * Gear^.Elasticity;
       
  1466         if Gear^.dY > - _0_001 then Gear^.dY:= _0
       
  1467             else if Gear^.dY < - _0_03 then
       
  1468                 PlaySound(Gear^.ImpactSound);
       
  1469         end;
       
  1470     //if Gear^.dY > - _0_001 then Gear^.dY:= _0
       
  1471     CheckGearDrowning(Gear);
       
  1472     end;
       
  1473 
       
  1474 if (Gear^.dY.QWordValue = 0) then AddGearCI(Gear)
       
  1475        else if (Gear^.dY.QWordValue <> 0) then DeleteCI(Gear)
       
  1476 end;
       
  1477 
       
  1478 ////////////////////////////////////////////////////////////////////////////////
       
  1479 
       
  1480 procedure doStepTarget(Gear: PGear);
       
  1481 begin
       
  1482 if (Gear^.Timer = 0) and (Gear^.Tag = 0) then
       
  1483     PlaySound(sndWarp);
       
  1484 
       
  1485 if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then
       
  1486     inc(Gear^.Timer)
       
  1487 else if Gear^.Tag = 1 then
       
  1488     begin
       
  1489         Gear^.Tag:= 2;
       
  1490         if (TrainingFlags and tfTimeTrial) <> 0 then
       
  1491             begin
  1714             begin
  1492             inc(TurnTimeLeft, TrainingTimeInc);
  1715                 // Modified fire
  1493             
  1716                 if ((GameTicks and $7FF) = 0) and ((GameFlags and gfSolidLand) = 0) then
  1494             if TrainingTimeInc > TrainingTimeInM then
  1717                 begin
  1495                 dec(TrainingTimeInc, TrainingTimeInD);
  1718                     DrawExplosion(gX, gY, 4);
  1496             if TurnTimeLeft > TrainingTimeMax then
  1719 
  1497                 TurnTimeLeft:= TrainingTimeMax;
  1720                     for i:= 0 to Random(3) do
       
  1721                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
       
  1722                 end;
       
  1723 
       
  1724 // 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.
       
  1725                 Gear^.Timer := 100 - Gear^.Tag * 3;
       
  1726                 if (Gear^.Damage > 3000+Gear^.Tag*1500) then Gear^.Health := 0
       
  1727             end
       
  1728         end
       
  1729     end;
       
  1730     if Gear^.Health = 0 then
       
  1731     begin
       
  1732         gX := hwRound(Gear^.X);
       
  1733         gY := hwRound(Gear^.Y);
       
  1734         if (Gear^.State and gsttmpFlag) = 0 then
       
  1735         begin
       
  1736             if ((GameTicks and $3) = 0) and (Random(1) = 0) then
       
  1737             begin
       
  1738                 for i:= 1 to Random(2)+1 do
       
  1739                 begin
       
  1740                     AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
       
  1741                 end;
  1498             end;
  1742             end;
  1499     end
  1743         end
  1500 else if Gear^.Tag = 2 then
  1744         else
  1501     if Gear^.Timer > 0 then
  1745         begin
  1502         dec(Gear^.Timer)
  1746             for i:= 0 to Random(3) do
       
  1747             begin
       
  1748                 AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
       
  1749             end;
       
  1750         end;
       
  1751 
       
  1752         DeleteGear(Gear)
       
  1753     end;
       
  1754 end;
       
  1755 
       
  1756 ////////////////////////////////////////////////////////////////////////////////
       
  1757 procedure doStepFirePunchWork(Gear: PGear);
       
  1758 var 
       
  1759     HHGear: PGear;
       
  1760 begin
       
  1761     AllInactive := false;
       
  1762     if ((Gear^.Message and gm_Destroy) <> 0) then
       
  1763     begin
       
  1764         DeleteGear(Gear);
       
  1765         AfterAttack;
       
  1766         exit
       
  1767     end;
       
  1768 
       
  1769     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1770     if hwRound(HHGear^.Y) <= Gear^.Tag - 2 then
       
  1771     begin
       
  1772         Gear^.Tag := hwRound(HHGear^.Y);
       
  1773         DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y - _1, _0_5, _0, cHHRadius * 4, 2);
       
  1774         HHGear^.State := HHGear^.State or gstNoDamage;
       
  1775         Gear^.Y := HHGear^.Y;
       
  1776         AmmoShove(Gear, 30, 40);
       
  1777         HHGear^.State := HHGear^.State and not gstNoDamage
       
  1778     end;
       
  1779 
       
  1780     HHGear^.dY := HHGear^.dY + cGravity;
       
  1781     if not (HHGear^.dY.isNegative) then
       
  1782     begin
       
  1783         HHGear^.State := HHGear^.State or gstMoving;
       
  1784         DeleteGear(Gear);
       
  1785         AfterAttack;
       
  1786         exit
       
  1787     end;
       
  1788 
       
  1789     if CheckLandValue(hwRound(HHGear^.X), hwRound(HHGear^.Y + HHGear^.dY + SignAs(_6,Gear^.dY)),
       
  1790        COLOR_INDESTRUCTIBLE) then
       
  1791         HHGear^.Y := HHGear^.Y + HHGear^.dY
       
  1792 end;
       
  1793 
       
  1794 procedure doStepFirePunch(Gear: PGear);
       
  1795 var 
       
  1796     HHGear: PGear;
       
  1797 begin
       
  1798     AllInactive := false;
       
  1799     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1800     DeleteCI(HHGear);
       
  1801     HHGear^.X := int2hwFloat(hwRound(HHGear^.X)) - _0_5;
       
  1802     HHGear^.dX := SignAs(cLittle, Gear^.dX);
       
  1803 
       
  1804     HHGear^.dY := - _0_3;
       
  1805 
       
  1806     Gear^.X := HHGear^.X;
       
  1807     Gear^.dX := SignAs(_0_45, Gear^.dX);
       
  1808     Gear^.dY := - _0_9;
       
  1809     Gear^.doStep := @doStepFirePunchWork;
       
  1810     DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y + _1, _0_5, _0, cHHRadius * 4, 5);
       
  1811 
       
  1812     PlaySound(TSound(ord(sndFirePunch1) + GetRandom(6)), PHedgehog(HHGear^.Hedgehog)^.Team^.
       
  1813     voicepack)
       
  1814 end;
       
  1815 
       
  1816 ////////////////////////////////////////////////////////////////////////////////
       
  1817 
       
  1818 procedure doStepParachuteWork(Gear: PGear);
       
  1819 var 
       
  1820     HHGear: PGear;
       
  1821 begin
       
  1822     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1823 
       
  1824     inc(Gear^.Timer);
       
  1825 
       
  1826     if TestCollisionYwithGear(HHGear, 1)
       
  1827        or ((HHGear^.State and gstHHDriven) = 0)
       
  1828        or CheckGearDrowning(HHGear)
       
  1829        or ((Gear^.Message and gm_Attack) <> 0) then
       
  1830     begin
       
  1831         with HHGear^ do
       
  1832         begin
       
  1833             Message := 0;
       
  1834             SetLittle(dX);
       
  1835             dY := _0;
       
  1836             State := State or gstMoving;
       
  1837         end;
       
  1838         DeleteGear(Gear);
       
  1839         isCursorVisible := false;
       
  1840         ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
       
  1841         exit
       
  1842     end;
       
  1843 
       
  1844     if not TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
       
  1845         HHGear^.X := HHGear^.X + cWindSpeed * 200;
       
  1846 
       
  1847     if (Gear^.Message and gm_Left) <> 0 then HHGear^.X := HHGear^.X - cMaxWindSpeed * 80
       
  1848     else if (Gear^.Message and gm_Right) <> 0 then HHGear^.X := HHGear^.X + cMaxWindSpeed * 80;
       
  1849     if (Gear^.Message and gm_Up) <> 0 then HHGear^.Y := HHGear^.Y - cGravity * 40
       
  1850     else if (Gear^.Message and gm_Down) <> 0 then HHGear^.Y := HHGear^.Y + cGravity * 40;
       
  1851 
       
  1852     HHGear^.Y := HHGear^.Y + cGravity * 100;
       
  1853     Gear^.X := HHGear^.X;
       
  1854     Gear^.Y := HHGear^.Y
       
  1855 end;
       
  1856 
       
  1857 procedure doStepParachute(Gear: PGear);
       
  1858 var 
       
  1859     HHGear: PGear;
       
  1860 begin
       
  1861     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1862 
       
  1863     DeleteCI(HHGear);
       
  1864 
       
  1865     AfterAttack;
       
  1866 
       
  1867     HHGear^.State := HHGear^.State and not (gstAttacking or gstAttacked or gstMoving);
       
  1868     HHGear^.Message := HHGear^.Message and not gm_Attack;
       
  1869 
       
  1870     Gear^.doStep := @doStepParachuteWork;
       
  1871 
       
  1872     Gear^.Message := HHGear^.Message;
       
  1873     doStepParachuteWork(Gear)
       
  1874 end;
       
  1875 
       
  1876 ////////////////////////////////////////////////////////////////////////////////
       
  1877 procedure doStepAirAttackWork(Gear: PGear);
       
  1878 var 
       
  1879     i: Longint;
       
  1880 begin
       
  1881     AllInactive := false;
       
  1882     Gear^.X := Gear^.X + cAirPlaneSpeed * Gear^.Tag;
       
  1883 
       
  1884     if (Gear^.Health > 0)and(not (Gear^.X < Gear^.dX))and(Gear^.X < Gear^.dX + cAirPlaneSpeed) then
       
  1885     begin
       
  1886         dec(Gear^.Health);
       
  1887         case Gear^.State of 
       
  1888             0: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed *
       
  1889                              Gear^.Tag, _0, 0);
       
  1890             1: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine,    0, cBombsSpeed *
       
  1891                              Gear^.Tag, _0, 0);
       
  1892             2: for i:= -19 to 19 do
       
  1893                    FollowGear := AddGear(hwRound(Gear^.X) + i div 3, hwRound(Gear^.Y), gtFlame, 0,
       
  1894                                  _0_001 * i, _0, 0);
       
  1895         end;
       
  1896         Gear^.dX := Gear^.dX + int2hwFloat(30 * Gear^.Tag)
       
  1897     end;
       
  1898 
       
  1899     if (GameTicks and $3F) = 0 then
       
  1900         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
       
  1901 
       
  1902     if (hwRound(Gear^.X) > (LAND_WIDTH+1024)) or (hwRound(Gear^.X) < -1024) then DeleteGear(Gear)
       
  1903 end;
       
  1904 
       
  1905 procedure doStepAirAttack(Gear: PGear);
       
  1906 begin
       
  1907     AllInactive := false;
       
  1908 
       
  1909     if Gear^.X.QWordValue = 0 then
       
  1910     begin
       
  1911         Gear^.Tag :=  1;
       
  1912         Gear^.X := -_1024;
       
  1913     end
  1503     else
  1914     else
  1504         begin
  1915     begin
  1505             if (TrainingFlags and tfTargetRespawn) <> 0 then
  1916         Gear^.Tag := -1;
  1506                 begin
  1917         Gear^.X := int2hwFloat(LAND_WIDTH + 1024);
  1507                 TrainingTargetGear:= AddGear(0, 0, gtTarget, 0, _0, _0, 0);
  1918     end;
  1508                 FindPlace(TrainingTargetGear, false, 0, LAND_WIDTH);
  1919 
  1509                 end;
  1920     Gear^.Y := int2hwFloat(topY-300);
       
  1921     Gear^.dX := int2hwFloat(TargetPoint.X - 5 * Gear^.Tag * 15);
       
  1922 
       
  1923     if (int2hwFloat(TargetPoint.Y) - Gear^.Y > _0) and (Gear^.State <> 2) then
       
  1924         Gear^.dX := Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(TargetPoint.Y) - Gear^.Y) * 2 /
       
  1925                     cGravity) * Gear^.Tag;
       
  1926 
       
  1927     Gear^.Health := 6;
       
  1928     Gear^.doStep := @doStepAirAttackWork;
       
  1929 end;
       
  1930 
       
  1931 ////////////////////////////////////////////////////////////////////////////////
       
  1932 
       
  1933 procedure doStepAirBomb(Gear: PGear);
       
  1934 begin
       
  1935     AllInactive := false;
       
  1936     doStepFallingGear(Gear);
       
  1937     if (Gear^.State and gstCollision) <> 0 then
       
  1938     begin
       
  1939         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
       
  1940         DeleteGear(Gear);
       
  1941         exit
       
  1942     end;
       
  1943     if (GameTicks and $3F) = 0 then
       
  1944         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
       
  1945 end;
       
  1946 
       
  1947 ////////////////////////////////////////////////////////////////////////////////
       
  1948 
       
  1949 procedure doStepGirder(Gear: PGear);
       
  1950 var 
       
  1951     HHGear: PGear;
       
  1952     x, y, tx, ty: hwFloat;
       
  1953 begin
       
  1954     AllInactive := false;
       
  1955 
       
  1956     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1957     tx := int2hwFloat(TargetPoint.X);
       
  1958     ty := int2hwFloat(TargetPoint.Y);
       
  1959     x := HHGear^.X;
       
  1960     y := HHGear^.Y;
       
  1961 
       
  1962     if (Distance(tx - x, ty - y) > _256) or
       
  1963        not TryPlaceOnLand(TargetPoint.X - SpritesData[sprAmGirder].Width div 2,
       
  1964        TargetPoint.Y - SpritesData[sprAmGirder].Height div 2,
       
  1965        sprAmGirder, Gear^.State, true) then
       
  1966     begin
       
  1967         PlaySound(sndDenied);
       
  1968         HHGear^.Message := HHGear^.Message and not gm_Attack;
       
  1969         HHGear^.State := HHGear^.State and not gstAttacking;
       
  1970         HHGear^.State := HHGear^.State or gstHHChooseTarget;
       
  1971         isCursorVisible := true;
       
  1972         DeleteGear(Gear)
       
  1973     end
       
  1974     else 
       
  1975     begin
       
  1976         PlaySound(sndPlaced);
       
  1977         DeleteGear(Gear);
       
  1978         AfterAttack;
       
  1979     end;
       
  1980 
       
  1981     HHGear^.State := HHGear^.State and not (gstAttacking or gstAttacked);
       
  1982     HHGear^.Message := HHGear^.Message and not gm_Attack;
       
  1983     TargetPoint.X := NoPointX
       
  1984 end;
       
  1985 
       
  1986 ////////////////////////////////////////////////////////////////////////////////
       
  1987 procedure doStepTeleportAfter(Gear: PGear);
       
  1988 var 
       
  1989     HHGear: PGear;
       
  1990 begin
       
  1991     PHedgehog(Gear^.Hedgehog)^.Unplaced := false;
       
  1992     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1993     HHGear^.Y := HHGear^.Y + HHGear^.dY;
       
  1994     // hedgehog falling to collect cases
       
  1995     HHGear^.dY := HHGear^.dY + cGravity;
       
  1996     if TestCollisionYwithGear(HHGear, 1)
       
  1997        or CheckGearDrowning(HHGear) then
       
  1998     begin
       
  1999         DeleteGear(Gear);
       
  2000         AfterAttack
       
  2001     end
       
  2002 end;
       
  2003 
       
  2004 procedure doStepTeleportAnim(Gear: PGear);
       
  2005 begin
       
  2006     inc(Gear^.Timer);
       
  2007     if Gear^.Timer = 65 then
       
  2008     begin
       
  2009         Gear^.Timer := 0;
       
  2010         inc(Gear^.Pos);
       
  2011         if Gear^.Pos = 11 then
       
  2012             Gear^.doStep := @doStepTeleportAfter
       
  2013     end;
       
  2014 end;
       
  2015 
       
  2016 procedure doStepTeleport(Gear: PGear);
       
  2017 var 
       
  2018     HHGear: PGear;
       
  2019 begin
       
  2020     AllInactive := false;
       
  2021 
       
  2022     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2023     if not TryPlaceOnLand(TargetPoint.X - SpritesData[sprHHTelepMask].Width div 2,
       
  2024        TargetPoint.Y - SpritesData[sprHHTelepMask].Height div 2,
       
  2025        sprHHTelepMask, 0, false) then
       
  2026     begin
       
  2027         HHGear^.Message := HHGear^.Message and not gm_Attack;
       
  2028         HHGear^.State := HHGear^.State and not gstAttacking;
       
  2029         HHGear^.State := HHGear^.State or gstHHChooseTarget;
       
  2030         DeleteGear(Gear);
       
  2031         isCursorVisible := true;
       
  2032         PlaySound(sndDenied)
       
  2033     end
       
  2034     else
       
  2035     begin
       
  2036         DeleteCI(HHGear);
       
  2037         SetAllHHToActive;
       
  2038         Gear^.doStep := @doStepTeleportAnim;
       
  2039 
       
  2040   // copy old HH position and direction to Gear (because we need them for drawing the vanishing hog)
       
  2041         Gear^.dX := HHGear^.dX;
       
  2042         // retrieve the cursor direction (it was previously copied to X so it doesn't get lost)
       
  2043         HHGear^.dX.isNegative := (Gear^.X.QWordValue <> 0);
       
  2044         Gear^.X := HHGear^.X;
       
  2045         Gear^.Y := HHGear^.Y;
       
  2046         HHGear^.X := int2hwFloat(TargetPoint.X);
       
  2047         HHGear^.Y := int2hwFloat(TargetPoint.Y);
       
  2048         HHGear^.State := HHGear^.State or gstMoving;
       
  2049         playSound(sndWarp)
       
  2050     end;
       
  2051     TargetPoint.X := NoPointX;
       
  2052 end;
       
  2053 
       
  2054 ////////////////////////////////////////////////////////////////////////////////
       
  2055 procedure doStepSwitcherWork(Gear: PGear);
       
  2056 var 
       
  2057     HHGear: PGear;
       
  2058     Msg, State: Longword;
       
  2059 begin
       
  2060     AllInactive := false;
       
  2061 
       
  2062     if ((Gear^.Message and not gm_Switch) <> 0) or (TurnTimeLeft = 0) then
       
  2063     begin
       
  2064         HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2065         Msg := Gear^.Message and not gm_Switch;
       
  2066         DeleteGear(Gear);
       
  2067         OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^);
       
  2068         ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
       
  2069 
       
  2070         HHGear := CurrentHedgehog^.Gear;
       
  2071         ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
       
  2072         HHGear^.Message := Msg;
       
  2073         exit
       
  2074     end;
       
  2075 
       
  2076     if (Gear^.Message and gm_Switch) <> 0 then
       
  2077     begin
       
  2078         HHGear := CurrentHedgehog^.Gear;
       
  2079         HHGear^.Message := HHGear^.Message and not gm_Switch;
       
  2080         Gear^.Message := Gear^.Message and not gm_Switch;
       
  2081         State := HHGear^.State;
       
  2082         HHGear^.State := 0;
       
  2083         HHGear^.Active := false;
       
  2084         HHGear^.Z := cHHZ;
       
  2085         RemoveGearFromList(HHGear);
       
  2086         InsertGearToList(HHGear);
       
  2087 
       
  2088         PlaySound(sndSwitchHog);
       
  2089 
       
  2090         repeat
       
  2091             CurrentTeam^.CurrHedgehog := Succ(CurrentTeam^.CurrHedgehog) mod (CurrentTeam^.
       
  2092                                          HedgehogsNumber);
       
  2093         until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil);
       
  2094 
       
  2095         CurrentHedgehog := @CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog];
       
  2096 
       
  2097         HHGear := CurrentHedgehog^.Gear;
       
  2098         HHGear^.State := State;
       
  2099         HHGear^.Active := true;
       
  2100         FollowGear := HHGear;
       
  2101         HHGear^.Z := cCurrHHZ;
       
  2102         RemoveGearFromList(HHGear);
       
  2103         InsertGearToList(HHGear);
       
  2104         Gear^.X := HHGear^.X;
       
  2105         Gear^.Y := HHGear^.Y
       
  2106     end;
       
  2107 end;
       
  2108 
       
  2109 procedure doStepSwitcher(Gear: PGear);
       
  2110 var 
       
  2111     HHGear: PGear;
       
  2112 begin
       
  2113     Gear^.doStep := @doStepSwitcherWork;
       
  2114 
       
  2115     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2116     with HHGear^ do
       
  2117     begin
       
  2118         State := State and not gstAttacking;
       
  2119         Message := Message and not gm_Attack
       
  2120     end
       
  2121 end;
       
  2122 
       
  2123 ////////////////////////////////////////////////////////////////////////////////
       
  2124 procedure doStepMortar(Gear: PGear);
       
  2125 var 
       
  2126     dX, dY: hwFloat;
       
  2127     i: LongInt;
       
  2128     dxn, dyn: boolean;
       
  2129 begin
       
  2130     AllInactive := false;
       
  2131     dxn := Gear^.dX.isNegative;
       
  2132     dyn := Gear^.dY.isNegative;
       
  2133 
       
  2134     doStepFallingGear(Gear);
       
  2135     if (Gear^.State and gstCollision) <> 0 then
       
  2136     begin
       
  2137         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLAutoSound);
       
  2138 
       
  2139         Gear^.dX.isNegative := not dxn;
       
  2140         Gear^.dY.isNegative := not dyn;
       
  2141         for i:= 0 to 4 do
       
  2142         begin
       
  2143             dX := Gear^.dX + (GetRandom - _0_5) * _0_03;
       
  2144             dY := Gear^.dY + (GetRandom - _0_5) * _0_03;
       
  2145             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtCluster, 0, dX, dY, 25);
       
  2146         end;
       
  2147 
       
  2148         DeleteGear(Gear);
       
  2149         exit
       
  2150     end;
       
  2151 
       
  2152     if (GameTicks and $3F) = 0 then
       
  2153         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
       
  2154 end;
       
  2155 
       
  2156 ////////////////////////////////////////////////////////////////////////////////
       
  2157 procedure doStepKamikazeWork(Gear: PGear);
       
  2158 
       
  2159 const upd: Longword =   0;
       
  2160 var 
       
  2161     i: LongWord;
       
  2162     HHGear: PGear;
       
  2163 begin
       
  2164     AllInactive := false;
       
  2165 
       
  2166     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2167     HHGear^.State := HHGear^.State or gstNoDamage;
       
  2168     DeleteCI(HHGear);
       
  2169 
       
  2170     i := 2;
       
  2171     repeat
       
  2172         Gear^.X := Gear^.X + HHGear^.dX;
       
  2173         Gear^.Y := Gear^.Y + HHGear^.dY;
       
  2174         HHGear^.X := Gear^.X;
       
  2175         HHGear^.Y := Gear^.Y;
       
  2176 
       
  2177         inc(Gear^.Damage, 2);
       
  2178 
       
  2179         //  if TestCollisionXwithGear(HHGear, hwSign(Gear^.dX))
       
  2180         //      or TestCollisionYwithGear(HHGear, hwSign(Gear^.dY)) then inc(Gear^.Damage, 3);
       
  2181 
       
  2182         dec(i)
       
  2183     until (i = 0) or (Gear^.Damage > Gear^.Health);
       
  2184 
       
  2185     inc(upd);
       
  2186     if upd > 3 then
       
  2187     begin
       
  2188         if Gear^.Health < 1500 then Gear^.Pos := 2;
       
  2189 
       
  2190         AmmoShove(Gear, 30, 40);
       
  2191 
       
  2192         DrawTunnel(HHGear^.X - HHGear^.dX * 10,
       
  2193                    HHGear^.Y - _2 - HHGear^.dY * 10 + hwAbs(HHGear^.dY) * 2,
       
  2194         HHGear^.dX,
       
  2195         HHGear^.dY,
       
  2196         20 + cHHRadius * 2,
       
  2197         cHHRadius * 2 + 6);
       
  2198 
       
  2199         upd := 0
       
  2200     end;
       
  2201 
       
  2202     if Gear^.Health < Gear^.Damage then
       
  2203     begin
       
  2204         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
       
  2205         AfterAttack;
       
  2206         DeleteGear(Gear);
       
  2207         DeleteGear(HHGear);
       
  2208     end
       
  2209     else
       
  2210     begin
       
  2211         dec(Gear^.Health, Gear^.Damage);
       
  2212         Gear^.Damage := 0
       
  2213     end
       
  2214 end;
       
  2215 
       
  2216 procedure doStepKamikazeIdle(Gear: PGear);
       
  2217 begin
       
  2218     AllInactive := false;
       
  2219     dec(Gear^.Timer);
       
  2220     if Gear^.Timer = 0 then
       
  2221     begin
       
  2222         Gear^.Pos := 1;
       
  2223         PlaySound(sndKamikaze, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
       
  2224         Gear^.doStep := @doStepKamikazeWork
       
  2225     end
       
  2226 end;
       
  2227 
       
  2228 procedure doStepKamikaze(Gear: PGear);
       
  2229 var 
       
  2230     HHGear: PGear;
       
  2231 begin
       
  2232     AllInactive := false;
       
  2233 
       
  2234     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2235 
       
  2236     HHGear^.dX := Gear^.dX;
       
  2237     HHGear^.dY := Gear^.dY;
       
  2238 
       
  2239     Gear^.dX := SignAs(_0_45, Gear^.dX);
       
  2240     Gear^.dY := - _0_9;
       
  2241 
       
  2242     Gear^.Timer := 550;
       
  2243 
       
  2244     Gear^.doStep := @doStepKamikazeIdle
       
  2245 end;
       
  2246 
       
  2247 ////////////////////////////////////////////////////////////////////////////////
       
  2248 
       
  2249 const cakeh =   27;
       
  2250     cakeDmg =   75;
       
  2251 var 
       
  2252     CakePoints: array[0..Pred(cakeh)] of record
       
  2253         x, y: hwFloat;
       
  2254     end;
       
  2255     CakeI: Longword;
       
  2256 
       
  2257 procedure doStepCakeExpl(Gear: PGear);
       
  2258 begin
       
  2259     AllInactive := false;
       
  2260 
       
  2261     inc(Gear^.Tag);
       
  2262     if Gear^.Tag < 2250 then exit;
       
  2263 
       
  2264     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg, EXPLAutoSound);
       
  2265     AfterAttack;
       
  2266     DeleteGear(Gear)
       
  2267 end;
       
  2268 
       
  2269 procedure doStepCakeDown(Gear: PGear);
       
  2270 var 
       
  2271     gi: PGear;
       
  2272     dmg: LongInt;
       
  2273 begin
       
  2274     AllInactive := false;
       
  2275 
       
  2276     inc(Gear^.Tag);
       
  2277     if Gear^.Tag < 100 then exit;
       
  2278     Gear^.Tag := 0;
       
  2279 
       
  2280     if Gear^.Pos = 0 then
       
  2281     begin
       
  2282         gi := GearsList;
       
  2283         while gi <> nil do
       
  2284         begin
       
  2285             dmg := cakeDmg * 2 - hwRound(Distance(gi^.X - Gear^.X, gi^.Y - Gear^.Y));
       
  2286             if (dmg > 1) and (gi^.Kind = gtHedgehog) then
       
  2287                 if (CurrentHedgehog^.Gear = gi) and (not gi^.Invulnerable) then
       
  2288                     gi^.State := gi^.State or gstLoser
       
  2289             else
       
  2290                 gi^.State := gi^.State or gstWinner;
       
  2291             gi := gi^.NextGear
       
  2292         end;
       
  2293         Gear^.doStep := @doStepCakeExpl;
       
  2294         PlaySound(sndCake)
       
  2295     end
       
  2296     else dec(Gear^.Pos)
       
  2297 end;
       
  2298 
       
  2299 
       
  2300 procedure doStepCakeWork(Gear: PGear);
       
  2301 
       
  2302 const dirs: array[0..3] of TPoint =   ((x: 0; y: -1), (x: 1; y: 0),(x: 0; y: 1),(x: -1; y: 0));
       
  2303 var 
       
  2304     xx, yy, xxn, yyn: LongInt;
       
  2305     da: LongInt;
       
  2306     tdx, tdy: hwFloat;
       
  2307 
       
  2308 procedure PrevAngle;
       
  2309 begin
       
  2310     Gear^.Angle := (LongInt(Gear^.Angle) + 4 - dA) mod 4
       
  2311 end;
       
  2312 
       
  2313 procedure NextAngle;
       
  2314 begin
       
  2315     Gear^.Angle := (LongInt(Gear^.Angle) + 4 + dA) mod 4
       
  2316 end;
       
  2317 
       
  2318 begin
       
  2319     AllInactive := false;
       
  2320 
       
  2321     inc(Gear^.Tag);
       
  2322     if Gear^.Tag < 7 then exit;
       
  2323 
       
  2324     dA := hwSign(Gear^.dX);
       
  2325     xx := dirs[Gear^.Angle].x;
       
  2326     yy := dirs[Gear^.Angle].y;
       
  2327     xxn := dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].x;
       
  2328     yyn := dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].y;
       
  2329 
       
  2330     if (xx = 0) then
       
  2331         if TestCollisionYwithGear(Gear, yy) then
       
  2332             PrevAngle
       
  2333     else
       
  2334     begin
       
  2335         Gear^.Tag := 0;
       
  2336         Gear^.Y := Gear^.Y + int2hwFloat(yy);
       
  2337         if not TestCollisionXwithGear(Gear, xxn) then
       
  2338         begin
       
  2339             Gear^.X := Gear^.X + int2hwFloat(xxn);
       
  2340             NextAngle
       
  2341         end;
       
  2342     end;
       
  2343 
       
  2344     if (yy = 0) then
       
  2345         if TestCollisionXwithGear(Gear, xx) then
       
  2346             PrevAngle
       
  2347     else
       
  2348     begin
       
  2349         Gear^.Tag := 0;
       
  2350         Gear^.X := Gear^.X + int2hwFloat(xx);
       
  2351         if not TestCollisionYwithGear(Gear, yyn) then
       
  2352         begin
       
  2353             Gear^.Y := Gear^.Y + int2hwFloat(yyn);
       
  2354             NextAngle
       
  2355         end;
       
  2356     end;
       
  2357 
       
  2358     if Gear^.Tag = 0 then
       
  2359     begin
       
  2360         CakeI := (CakeI + 1) mod cakeh;
       
  2361         tdx := CakePoints[CakeI].x - Gear^.X;
       
  2362         tdy := - CakePoints[CakeI].y + Gear^.Y;
       
  2363         CakePoints[CakeI].x := Gear^.X;
       
  2364         CakePoints[CakeI].y := Gear^.Y;
       
  2365         Gear^.DirAngle := DxDy2Angle(tdx, tdy);
       
  2366     end;
       
  2367 
       
  2368     dec(Gear^.Health);
       
  2369     Gear^.Timer := Gear^.Health*10;
       
  2370     // This is not seconds, but at least it is *some* feedback
       
  2371     if (Gear^.Health = 0) or ((Gear^.Message and gm_Attack) <> 0) then
       
  2372     begin
       
  2373         FollowGear := Gear;
       
  2374         Gear^.RenderTimer := false;
       
  2375         Gear^.doStep := @doStepCakeDown
       
  2376     end
       
  2377 end;
       
  2378 
       
  2379 procedure doStepCakeUp(Gear: PGear);
       
  2380 var 
       
  2381     i: Longword;
       
  2382 begin
       
  2383     AllInactive := false;
       
  2384 
       
  2385     inc(Gear^.Tag);
       
  2386     if Gear^.Tag < 100 then exit;
       
  2387     Gear^.Tag := 0;
       
  2388 
       
  2389     if Gear^.Pos = 6 then
       
  2390     begin
       
  2391         for i:= 0 to Pred(cakeh) do
       
  2392         begin
       
  2393             CakePoints[i].x := Gear^.X;
       
  2394             CakePoints[i].y := Gear^.Y
       
  2395         end;
       
  2396         CakeI := 0;
       
  2397         Gear^.doStep := @doStepCakeWork
       
  2398     end
       
  2399     else inc(Gear^.Pos)
       
  2400 end;
       
  2401 
       
  2402 procedure doStepCakeFall(Gear: PGear);
       
  2403 begin
       
  2404     AllInactive := false;
       
  2405 
       
  2406     Gear^.dY := Gear^.dY + cGravity;
       
  2407     if TestCollisionYwithGear(Gear, 1) then
       
  2408         Gear^.doStep := @doStepCakeUp
       
  2409     else
       
  2410     begin
       
  2411         Gear^.Y := Gear^.Y + Gear^.dY;
       
  2412         if CheckGearDrowning(Gear) then AfterAttack
       
  2413     end
       
  2414 end;
       
  2415 
       
  2416 procedure doStepCake(Gear: PGear);
       
  2417 var 
       
  2418     HHGear: PGear;
       
  2419 begin
       
  2420     AllInactive := false;
       
  2421 
       
  2422     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2423     HHGear^.Message := HHGear^.Message and (not gm_Attack);
       
  2424     DeleteCI(HHGear);
       
  2425 
       
  2426     FollowGear := Gear;
       
  2427 
       
  2428     Gear^.doStep := @doStepCakeFall
       
  2429 end;
       
  2430 
       
  2431 ////////////////////////////////////////////////////////////////////////////////
       
  2432 procedure doStepSeductionWork(Gear: PGear);
       
  2433 var 
       
  2434     x, y: LongInt;
       
  2435 begin
       
  2436     AllInactive := false;
       
  2437 
       
  2438     Gear^.X := Gear^.X + Gear^.dX;
       
  2439     Gear^.Y := Gear^.Y + Gear^.dY;
       
  2440     x := hwRound(Gear^.X);
       
  2441     y := hwRound(Gear^.Y);
       
  2442 
       
  2443     if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
       
  2444         if (Land[y, x] <> 0) then
       
  2445         begin
       
  2446             Gear^.dX.isNegative := not Gear^.dX.isNegative;
       
  2447             Gear^.dY.isNegative := not Gear^.dY.isNegative;
       
  2448             Gear^.dX := Gear^.dX * _1_5;
       
  2449             Gear^.dY := Gear^.dY * _1_5 - _0_3;
       
  2450             AmmoShove(Gear, 0, 40);
       
  2451             AfterAttack;
       
  2452             DeleteGear(Gear)
       
  2453         end
       
  2454     else
       
  2455     else
       
  2456     begin
       
  2457         AfterAttack;
       
  2458         DeleteGear(Gear)
       
  2459     end
       
  2460 end;
       
  2461 
       
  2462 procedure doStepSeductionWear(Gear: PGear);
       
  2463 begin
       
  2464     AllInactive := false;
       
  2465     inc(Gear^.Timer);
       
  2466     if Gear^.Timer > 250 then
       
  2467     begin
       
  2468         Gear^.Timer := 0;
       
  2469         inc(Gear^.Pos);
       
  2470         if Gear^.Pos = 5 then
       
  2471             PlaySound(sndYoohoo, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
       
  2472     end;
       
  2473 
       
  2474     if Gear^.Pos = 14 then
       
  2475         Gear^.doStep := @doStepSeductionWork
       
  2476 end;
       
  2477 
       
  2478 procedure doStepSeduction(Gear: PGear);
       
  2479 begin
       
  2480     AllInactive := false;
       
  2481     DeleteCI(PHedgehog(Gear^.Hedgehog)^.Gear);
       
  2482     Gear^.doStep := @doStepSeductionWear
       
  2483 end;
       
  2484 
       
  2485 ////////////////////////////////////////////////////////////////////////////////
       
  2486 procedure doStepWaterUp(Gear: PGear);
       
  2487 var 
       
  2488     i: LongWord;
       
  2489 begin
       
  2490     AllInactive := false;
       
  2491 
       
  2492     inc(Gear^.Timer);
       
  2493     if Gear^.Timer = 17 then
       
  2494         Gear^.Timer := 0
       
  2495     else
       
  2496         exit;
       
  2497 
       
  2498     if cWaterLine > 0 then
       
  2499     begin
       
  2500         dec(cWaterLine);
       
  2501         for i:= 0 to LAND_WIDTH - 1 do
       
  2502             Land[cWaterLine, i] := 0;
       
  2503         SetAllToActive
       
  2504     end;
       
  2505 
       
  2506     inc(Gear^.Tag);
       
  2507     if (Gear^.Tag = 47) or (cWaterLine = 0) then
       
  2508         DeleteGear(Gear)
       
  2509 end;
       
  2510 
       
  2511 ////////////////////////////////////////////////////////////////////////////////
       
  2512 procedure doStepDrillDrilling(Gear: PGear);
       
  2513 var 
       
  2514     t: PGearArray;
       
  2515     ox, oy: hwFloat;
       
  2516 begin
       
  2517     AllInactive := false;
       
  2518 
       
  2519     if (Gear^.Timer > 0) and ((Gear^.Timer mod 10) = 0) then
       
  2520     begin
       
  2521         ox := Gear^.X;
       
  2522         oy := Gear^.Y;
       
  2523         Gear^.X := Gear^.X + Gear^.dX;
       
  2524         Gear^.Y := Gear^.Y + Gear^.dY;
       
  2525         DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 2, 6);
       
  2526         if (CheckGearDrowning(Gear)) then
       
  2527         begin
       
  2528             StopSound(Gear^.SoundChannel);
       
  2529             exit
       
  2530         end
       
  2531     end;
       
  2532 
       
  2533     t := CheckGearsCollision(Gear);
       
  2534     //fixes drill not exploding when touching HH bug
       
  2535     if (Gear^.Timer = 0)
       
  2536        or (t^.Count <> 0)
       
  2537        or (not TestCollisionYWithGear(Gear, hwSign(Gear^.dY))
       
  2538        and not TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))
       
  2539        or (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] = COLOR_INDESTRUCTIBLE) then
       
  2540     begin
       
  2541         //out of time or exited ground
       
  2542         StopSound(Gear^.SoundChannel);
       
  2543         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
       
  2544         DeleteGear(Gear);
       
  2545         exit
       
  2546     end;
       
  2547 
       
  2548     dec(Gear^.Timer);
       
  2549 end;
       
  2550 
       
  2551 procedure doStepDrill(Gear: PGear);
       
  2552 var 
       
  2553     t: PGearArray;
       
  2554     oldDx, oldDy: hwFloat;
       
  2555     t2: hwFloat;
       
  2556 begin
       
  2557     AllInactive := false;
       
  2558 
       
  2559     Gear^.dX := Gear^.dX + cWindSpeed;
       
  2560     oldDx := Gear^.dX;
       
  2561     oldDy := Gear^.dY;
       
  2562 
       
  2563     doStepFallingGear(Gear);
       
  2564 
       
  2565     if (GameTicks and $3F) = 0 then
       
  2566         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
       
  2567 
       
  2568     if ((Gear^.State and gstCollision) <> 0) then
       
  2569     begin
       
  2570         //hit
       
  2571         Gear^.dX := oldDx;
       
  2572         Gear^.dY := oldDy;
       
  2573 
       
  2574         t := CheckGearsCollision(Gear);
       
  2575         if (t^.Count = 0) then
       
  2576         begin
       
  2577             //hit the ground not the HH
       
  2578             t2 := _0_5 / Distance(Gear^.dX, Gear^.dY);
       
  2579             Gear^.dX := Gear^.dX * t2;
       
  2580             Gear^.dY := Gear^.dY * t2;
       
  2581         end
       
  2582         else
       
  2583         begin
       
  2584             //explode right on contact with HH
       
  2585             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
  1510             DeleteGear(Gear);
  2586             DeleteGear(Gear);
  1511             exit;
  2587             exit;
  1512         end;
  2588         end;
  1513 
  2589 
  1514 doStepCase(Gear)
  2590         Gear^.SoundChannel := LoopSound(sndDrillRocket);
  1515 end;
  2591         Gear^.doStep := @doStepDrillDrilling;
  1516 
  2592         dec(Gear^.Timer)
  1517 ////////////////////////////////////////////////////////////////////////////////
  2593     end
  1518 procedure doStepIdle(Gear: PGear);
  2594 end;
  1519 begin
  2595 
  1520 AllInactive:= false;
  2596 ////////////////////////////////////////////////////////////////////////////////
  1521 dec(Gear^.Timer);
  2597 procedure doStepBallgunWork(Gear: PGear);
  1522 if Gear^.Timer = 0 then
  2598 var 
  1523     begin
       
  1524     DeleteGear(Gear);
       
  1525     AfterAttack
       
  1526     end
       
  1527 end;
       
  1528 
       
  1529 procedure doStepShover(Gear: PGear);
       
  1530 var HHGear: PGear;
       
  1531 begin
       
  1532 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1533 HHGear^.State:= HHGear^.State or gstNoDamage;
       
  1534 DeleteCI(HHGear);
       
  1535 
       
  1536 AmmoShove(Gear, 30, 115);
       
  1537 
       
  1538 HHGear^.State:= HHGear^.State and not gstNoDamage;
       
  1539 Gear^.Timer:= 250;
       
  1540 Gear^.doStep:= @doStepIdle
       
  1541 end;
       
  1542 
       
  1543 ////////////////////////////////////////////////////////////////////////////////
       
  1544 procedure doStepWhip(Gear: PGear);
       
  1545 var HHGear: PGear;
       
  1546     i: LongInt;
       
  1547 begin
       
  1548 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1549 HHGear^.State:= HHGear^.State or gstNoDamage;
       
  1550 DeleteCI(HHGear);
       
  1551 
       
  1552 for i:= 0 to 3 do
       
  1553     begin
       
  1554     AmmoShove(Gear, 30, 25);
       
  1555     Gear^.X:= Gear^.X + Gear^.dX * 5
       
  1556     end;
       
  1557 
       
  1558 HHGear^.State:= HHGear^.State and not gstNoDamage;
       
  1559 Gear^.Timer:= 250;
       
  1560 Gear^.doStep:= @doStepIdle
       
  1561 end;
       
  1562 
       
  1563 ////////////////////////////////////////////////////////////////////////////////
       
  1564 procedure doStepFlame(Gear: PGear);
       
  1565 var gX,gY,i: LongInt;
       
  1566 begin
       
  1567     if (Gear^.State and gsttmpFlag) = 0 then AllInactive:= false;
       
  1568 
       
  1569 if not TestCollisionYwithGear(Gear, 1) then
       
  1570     begin
       
  1571     AllInactive:= false;
       
  1572     if Gear^.dX.QWordValue > _0_01.QWordValue then
       
  1573         Gear^.dX:= Gear^.dX * _0_995;
       
  1574     Gear^.dY:= Gear^.dY + cGravity;
       
  1575     if (Gear^.State and gsttmpFlag) <> 0 then Gear^.dY:= Gear^.dY + cGravity;
       
  1576     if Gear^.dY.QWordValue > _0_2.QWordValue then Gear^.dY:= Gear^.dY * _0_995;
       
  1577 
       
  1578     if (Gear^.State and gsttmpFlag) <> 0 then Gear^.X:= Gear^.X + Gear^.dX else
       
  1579     Gear^.X:= Gear^.X + Gear^.dX + cWindSpeed * 640;
       
  1580     Gear^.Y:= Gear^.Y + Gear^.dY;
       
  1581 
       
  1582     if (hwRound(Gear^.Y) > cWaterLine) then
       
  1583         begin
       
  1584         gX:= hwRound(Gear^.X);
       
  1585         for i:= 0 to 3 do
       
  1586             AddVisualGear(gX - 16 + Random(32), cWaterLine - 16 + Random(16), vgtSteam);
       
  1587         PlaySound(sndVaporize);
       
  1588         DeleteGear(Gear);
       
  1589         exit
       
  1590         end
       
  1591     end else begin
       
  1592         if (Gear^.State and gsttmpFlag) <> 0 then 
       
  1593             begin
       
  1594             Gear^.Radius:= 9;
       
  1595             AmmoShove(Gear, 2, 30);
       
  1596             Gear^.Radius:= 1
       
  1597             end;
       
  1598         if Gear^.Timer > 0 then
       
  1599             begin
       
  1600             dec(Gear^.Timer);
       
  1601             inc(Gear^.Damage)
       
  1602             end
       
  1603         else begin
       
  1604 // Standard fire
       
  1605             if (Gear^.State and gsttmpFlag) = 0 then
       
  1606                 begin
       
  1607                 Gear^.Radius:= 9;
       
  1608                 AmmoShove(Gear, 4, 100);
       
  1609                 gX:= hwRound(Gear^.X);
       
  1610                 gY:= hwRound(Gear^.Y);
       
  1611                 Gear^.Radius:= 1;
       
  1612                 doMakeExplosion(gX, gY, 4, EXPLNoDamage);
       
  1613                 if ((GameTicks and $7) = 0) and (Random(2) = 0) then
       
  1614                   for i:= 1 to Random(2)+1 do
       
  1615                     AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
       
  1616                 if Gear^.Health > 0 then dec(Gear^.Health);
       
  1617                 Gear^.Timer:= 450 - Gear^.Tag * 8
       
  1618                 end
       
  1619                 else begin
       
  1620 // Modified fire
       
  1621                 if ((GameTicks and $7FF) = 0) and ((GameFlags and gfSolidLand) = 0) then begin
       
  1622                     DrawExplosion(gX, gY, 4);
       
  1623                     
       
  1624                     for i:= 0 to Random(3) do
       
  1625                       AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
       
  1626                 end;
       
  1627                 // 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.
       
  1628                 Gear^.Timer:= 100 - Gear^.Tag * 3;
       
  1629                 if (Gear^.Damage > 3000+Gear^.Tag*1500) then Gear^.Health:= 0
       
  1630                 end
       
  1631             end
       
  1632         end;
       
  1633 if Gear^.Health = 0 then begin
       
  1634   gX:= hwRound(Gear^.X);
       
  1635   gY:= hwRound(Gear^.Y);
       
  1636   if (Gear^.State and gsttmpFlag) = 0 then begin
       
  1637     if ((GameTicks and $3) = 0) and (Random(1) = 0) then begin
       
  1638       for i:= 1 to Random(2)+1 do begin
       
  1639         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
       
  1640       end;
       
  1641     end;
       
  1642   end else begin
       
  1643     for i:= 0 to Random(3) do begin
       
  1644       AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
       
  1645     end;
       
  1646   end;
       
  1647   
       
  1648   DeleteGear(Gear)
       
  1649   end;
       
  1650 end;
       
  1651 
       
  1652 ////////////////////////////////////////////////////////////////////////////////
       
  1653 procedure doStepFirePunchWork(Gear: PGear);
       
  1654 var HHGear: PGear;
       
  1655 begin
       
  1656 AllInactive:= false;
       
  1657 if ((Gear^.Message and gm_Destroy) <> 0) then
       
  1658     begin
       
  1659     DeleteGear(Gear);
       
  1660     AfterAttack;
       
  1661     exit
       
  1662     end;
       
  1663 
       
  1664 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1665 if hwRound(HHGear^.Y) <= Gear^.Tag - 2 then
       
  1666     begin
       
  1667     Gear^.Tag:= hwRound(HHGear^.Y);
       
  1668     DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y - _1, _0_5, _0, cHHRadius * 4, 2);
       
  1669     HHGear^.State:= HHGear^.State or gstNoDamage;
       
  1670     Gear^.Y:= HHGear^.Y;
       
  1671     AmmoShove(Gear, 30, 40);
       
  1672     HHGear^.State:= HHGear^.State and not gstNoDamage
       
  1673     end;
       
  1674 
       
  1675 HHGear^.dY:= HHGear^.dY + cGravity;
       
  1676 if not (HHGear^.dY.isNegative) then
       
  1677     begin
       
  1678     HHGear^.State:= HHGear^.State or gstMoving;
       
  1679     DeleteGear(Gear);
       
  1680     AfterAttack;
       
  1681     exit
       
  1682     end;
       
  1683 
       
  1684 if CheckLandValue(hwRound(HHGear^.X), hwRound(HHGear^.Y + HHGear^.dY + SignAs(_6,Gear^.dY)), COLOR_INDESTRUCTIBLE) then
       
  1685    HHGear^.Y:= HHGear^.Y + HHGear^.dY
       
  1686 end;
       
  1687 
       
  1688 procedure doStepFirePunch(Gear: PGear);
       
  1689 var HHGear: PGear;
       
  1690 begin
       
  1691 AllInactive:= false;
       
  1692 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1693 DeleteCI(HHGear);
       
  1694 HHGear^.X:= int2hwFloat(hwRound(HHGear^.X)) - _0_5;
       
  1695 HHGear^.dX:= SignAs(cLittle, Gear^.dX);
       
  1696 
       
  1697 HHGear^.dY:= - _0_3;
       
  1698 
       
  1699 Gear^.X:= HHGear^.X;
       
  1700 Gear^.dX:= SignAs(_0_45, Gear^.dX);
       
  1701 Gear^.dY:= - _0_9;
       
  1702 Gear^.doStep:= @doStepFirePunchWork;
       
  1703 DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y + _1, _0_5, _0, cHHRadius * 4, 5);
       
  1704 
       
  1705 PlaySound(TSound(ord(sndFirePunch1) + GetRandom(6)), PHedgehog(HHGear^.Hedgehog)^.Team^.voicepack)
       
  1706 end;
       
  1707 
       
  1708 ////////////////////////////////////////////////////////////////////////////////
       
  1709 
       
  1710 procedure doStepParachuteWork(Gear: PGear);
       
  1711 var HHGear: PGear;
       
  1712 begin
       
  1713 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1714 
       
  1715 inc(Gear^.Timer);
       
  1716 
       
  1717 if TestCollisionYwithGear(HHGear, 1)
       
  1718     or ((HHGear^.State and gstHHDriven) = 0)
       
  1719     or CheckGearDrowning(HHGear)
       
  1720     or ((Gear^.Message and gm_Attack) <> 0) then
       
  1721     begin
       
  1722     with HHGear^ do
       
  1723         begin
       
  1724         Message:= 0;
       
  1725         SetLittle(dX);
       
  1726         dY:= _0;
       
  1727         State:= State or gstMoving;
       
  1728         end;
       
  1729     DeleteGear(Gear);
       
  1730     isCursorVisible:= false;
       
  1731     ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
       
  1732     exit
       
  1733     end;
       
  1734 
       
  1735 if not TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
       
  1736     HHGear^.X:= HHGear^.X + cWindSpeed * 200;
       
  1737 
       
  1738 if (Gear^.Message and gm_Left) <> 0 then HHGear^.X:= HHGear^.X - cMaxWindSpeed * 80
       
  1739 else if (Gear^.Message and gm_Right) <> 0 then HHGear^.X:= HHGear^.X + cMaxWindSpeed * 80;
       
  1740 if (Gear^.Message and gm_Up) <> 0 then HHGear^.Y:= HHGear^.Y - cGravity * 40
       
  1741 else if (Gear^.Message and gm_Down) <> 0 then HHGear^.Y:= HHGear^.Y + cGravity * 40;
       
  1742 
       
  1743 HHGear^.Y:= HHGear^.Y + cGravity * 100;
       
  1744 Gear^.X:= HHGear^.X;
       
  1745 Gear^.Y:= HHGear^.Y
       
  1746 end;
       
  1747 
       
  1748 procedure doStepParachute(Gear: PGear);
       
  1749 var HHGear: PGear;
       
  1750 begin
       
  1751 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1752 
       
  1753 DeleteCI(HHGear);
       
  1754 
       
  1755 AfterAttack;
       
  1756 
       
  1757 HHGear^.State:= HHGear^.State and not (gstAttacking or gstAttacked or gstMoving);
       
  1758 HHGear^.Message:= HHGear^.Message and not gm_Attack;
       
  1759 
       
  1760 Gear^.doStep:= @doStepParachuteWork;
       
  1761 
       
  1762 Gear^.Message:= HHGear^.Message;
       
  1763 doStepParachuteWork(Gear)
       
  1764 end;
       
  1765 
       
  1766 ////////////////////////////////////////////////////////////////////////////////
       
  1767 procedure doStepAirAttackWork(Gear: PGear);
       
  1768 var i: Longint;
       
  1769 begin
       
  1770 AllInactive:= false;
       
  1771 Gear^.X:= Gear^.X + cAirPlaneSpeed * Gear^.Tag;
       
  1772 
       
  1773 if (Gear^.Health > 0)and(not (Gear^.X < Gear^.dX))and(Gear^.X < Gear^.dX + cAirPlaneSpeed) then
       
  1774     begin
       
  1775     dec(Gear^.Health);
       
  1776     case Gear^.State of
       
  1777             0: FollowGear:= AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
       
  1778             1: FollowGear:= AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine,    0, cBombsSpeed * Gear^.Tag, _0, 0);
       
  1779             2: for i:= -19 to 19 do
       
  1780                 FollowGear:= AddGear(hwRound(Gear^.X) + i div 3, hwRound(Gear^.Y), gtFlame, 0, _0_001 * i, _0, 0);
       
  1781             end;
       
  1782     Gear^.dX:= Gear^.dX + int2hwFloat(30 * Gear^.Tag)
       
  1783     end;
       
  1784 
       
  1785 if (GameTicks and $3F) = 0 then
       
  1786     AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
       
  1787 
       
  1788 if (hwRound(Gear^.X) > (LAND_WIDTH+1024)) or (hwRound(Gear^.X) < -1024) then DeleteGear(Gear)
       
  1789 end;
       
  1790 
       
  1791 procedure doStepAirAttack(Gear: PGear);
       
  1792 begin
       
  1793 AllInactive:= false;
       
  1794 
       
  1795 if Gear^.X.QWordValue = 0 then
       
  1796     begin
       
  1797     Gear^.Tag:=  1;
       
  1798     Gear^.X:= -_1024;
       
  1799     end
       
  1800 else
       
  1801     begin
       
  1802     Gear^.Tag:= -1;
       
  1803     Gear^.X:= int2hwFloat(LAND_WIDTH + 1024);
       
  1804     end;
       
  1805 
       
  1806 Gear^.Y:= int2hwFloat(topY-300);
       
  1807 Gear^.dX:= int2hwFloat(TargetPoint.X - 5 * Gear^.Tag * 15);
       
  1808 
       
  1809 if (int2hwFloat(TargetPoint.Y) - Gear^.Y > _0) and (Gear^.State <> 2) then
       
  1810         Gear^.dX:= Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(TargetPoint.Y) - Gear^.Y) * 2 / cGravity) * Gear^.Tag;
       
  1811 
       
  1812 Gear^.Health:= 6;
       
  1813 Gear^.doStep:= @doStepAirAttackWork;
       
  1814 end;
       
  1815 
       
  1816 ////////////////////////////////////////////////////////////////////////////////
       
  1817 
       
  1818 procedure doStepAirBomb(Gear: PGear);
       
  1819 begin
       
  1820 AllInactive:= false;
       
  1821 doStepFallingGear(Gear);
       
  1822 if (Gear^.State and gstCollision) <> 0 then
       
  1823     begin
       
  1824     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
       
  1825     DeleteGear(Gear);
       
  1826     exit
       
  1827     end;
       
  1828 if (GameTicks and $3F) = 0 then
       
  1829     AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
       
  1830 end;
       
  1831 
       
  1832 ////////////////////////////////////////////////////////////////////////////////
       
  1833 
       
  1834 procedure doStepGirder(Gear: PGear);
       
  1835 var HHGear: PGear;
       
  1836     x, y, tx, ty: hwFloat;
       
  1837 begin
       
  1838 AllInactive:= false;
       
  1839 
       
  1840 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1841 tx:= int2hwFloat(TargetPoint.X);
       
  1842 ty:= int2hwFloat(TargetPoint.Y);
       
  1843 x:= HHGear^.X;
       
  1844 y:= HHGear^.Y;
       
  1845 
       
  1846 if (Distance(tx - x, ty - y) > _256) or
       
  1847    not TryPlaceOnLand(TargetPoint.X - SpritesData[sprAmGirder].Width div 2,
       
  1848                       TargetPoint.Y - SpritesData[sprAmGirder].Height div 2,
       
  1849                       sprAmGirder, Gear^.State, true) then
       
  1850     begin
       
  1851     PlaySound(sndDenied);
       
  1852     HHGear^.Message:= HHGear^.Message and not gm_Attack;
       
  1853     HHGear^.State:= HHGear^.State and not gstAttacking;
       
  1854     HHGear^.State:= HHGear^.State or gstHHChooseTarget;
       
  1855     isCursorVisible:= true;
       
  1856     DeleteGear(Gear)
       
  1857     end
       
  1858 else begin
       
  1859     PlaySound(sndPlaced);
       
  1860     DeleteGear(Gear);
       
  1861     AfterAttack;
       
  1862     end;
       
  1863 
       
  1864 HHGear^.State:= HHGear^.State and not (gstAttacking or gstAttacked);
       
  1865 HHGear^.Message:= HHGear^.Message and not gm_Attack;
       
  1866 TargetPoint.X:= NoPointX
       
  1867 end;
       
  1868 
       
  1869 ////////////////////////////////////////////////////////////////////////////////
       
  1870 procedure doStepTeleportAfter(Gear: PGear);
       
  1871 var HHGear: PGear;
       
  1872 begin
       
  1873 PHedgehog(Gear^.Hedgehog)^.Unplaced:= false;
       
  1874 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1875 HHGear^.Y:= HHGear^.Y + HHGear^.dY; // hedgehog falling to collect cases
       
  1876 HHGear^.dY:= HHGear^.dY + cGravity;
       
  1877 if TestCollisionYwithGear(HHGear, 1)
       
  1878     or CheckGearDrowning(HHGear) then
       
  1879     begin
       
  1880     DeleteGear(Gear);
       
  1881     AfterAttack
       
  1882     end
       
  1883 end;
       
  1884 
       
  1885 procedure doStepTeleportAnim(Gear: PGear);
       
  1886 begin
       
  1887 inc(Gear^.Timer);
       
  1888 if Gear^.Timer = 65 then
       
  1889     begin
       
  1890     Gear^.Timer:= 0;
       
  1891     inc(Gear^.Pos);
       
  1892     if Gear^.Pos = 11 then
       
  1893         Gear^.doStep:= @doStepTeleportAfter
       
  1894     end;
       
  1895 end;
       
  1896 
       
  1897 procedure doStepTeleport(Gear: PGear);
       
  1898 var HHGear: PGear;
       
  1899 begin
       
  1900 AllInactive:= false;
       
  1901 
       
  1902 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1903 if not TryPlaceOnLand(TargetPoint.X - SpritesData[sprHHTelepMask].Width div 2,
       
  1904                       TargetPoint.Y - SpritesData[sprHHTelepMask].Height div 2,
       
  1905                       sprHHTelepMask, 0, false) then
       
  1906         begin
       
  1907         HHGear^.Message:= HHGear^.Message and not gm_Attack;
       
  1908         HHGear^.State:= HHGear^.State and not gstAttacking;
       
  1909         HHGear^.State:= HHGear^.State or gstHHChooseTarget;
       
  1910         DeleteGear(Gear);
       
  1911         isCursorVisible:= true;
       
  1912         PlaySound(sndDenied)
       
  1913         end
       
  1914     else begin
       
  1915         DeleteCI(HHGear);
       
  1916         SetAllHHToActive;
       
  1917         Gear^.doStep:= @doStepTeleportAnim;
       
  1918         // copy old HH position and direction to Gear (because we need them for drawing the vanishing hog)
       
  1919         Gear^.dX:= HHGear^.dX;
       
  1920          // retrieve the cursor direction (it was previously copied to X so it doesn't get lost)
       
  1921          HHGear^.dX.isNegative := (Gear^.X.QWordValue <> 0);
       
  1922         Gear^.X:= HHGear^.X;
       
  1923         Gear^.Y:= HHGear^.Y;
       
  1924         HHGear^.X:= int2hwFloat(TargetPoint.X);
       
  1925         HHGear^.Y:= int2hwFloat(TargetPoint.Y);
       
  1926         HHGear^.State:= HHGear^.State or gstMoving;
       
  1927         playSound(sndWarp)
       
  1928         end;
       
  1929 TargetPoint.X:= NoPointX;
       
  1930 end;
       
  1931 
       
  1932 ////////////////////////////////////////////////////////////////////////////////
       
  1933 procedure doStepSwitcherWork(Gear: PGear);
       
  1934 var HHGear: PGear;
       
  1935     Msg, State: Longword;
       
  1936 begin
       
  1937 AllInactive:= false;
       
  1938 
       
  1939 if ((Gear^.Message and not gm_Switch) <> 0) or (TurnTimeLeft = 0) then
       
  1940     begin
       
  1941     HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1942     Msg:= Gear^.Message and not gm_Switch;
       
  1943     DeleteGear(Gear);
       
  1944     OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^);
       
  1945     ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
       
  1946 
       
  1947     HHGear:= CurrentHedgehog^.Gear;
       
  1948     ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
       
  1949     HHGear^.Message:= Msg;
       
  1950     exit
       
  1951     end;
       
  1952 
       
  1953 if (Gear^.Message and gm_Switch) <> 0 then
       
  1954     begin
       
  1955     HHGear:= CurrentHedgehog^.Gear;
       
  1956     HHGear^.Message:= HHGear^.Message and not gm_Switch;
       
  1957     Gear^.Message:= Gear^.Message and not gm_Switch;
       
  1958     State:= HHGear^.State;
       
  1959     HHGear^.State:= 0;
       
  1960     HHGear^.Active:= false;
       
  1961     HHGear^.Z:= cHHZ;
       
  1962     RemoveGearFromList(HHGear);
       
  1963     InsertGearToList(HHGear);
       
  1964 
       
  1965     PlaySound(sndSwitchHog);
       
  1966     
       
  1967     repeat
       
  1968         CurrentTeam^.CurrHedgehog:= Succ(CurrentTeam^.CurrHedgehog) mod (CurrentTeam^.HedgehogsNumber);
       
  1969     until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil);
       
  1970 
       
  1971     CurrentHedgehog:= @CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog];
       
  1972 
       
  1973     HHGear:= CurrentHedgehog^.Gear;
       
  1974     HHGear^.State:= State;
       
  1975     HHGear^.Active:= true;
       
  1976     FollowGear:= HHGear;
       
  1977     HHGear^.Z:= cCurrHHZ;
       
  1978     RemoveGearFromList(HHGear);
       
  1979     InsertGearToList(HHGear);
       
  1980     Gear^.X:= HHGear^.X;
       
  1981     Gear^.Y:= HHGear^.Y
       
  1982     end;
       
  1983 end;
       
  1984 
       
  1985 procedure doStepSwitcher(Gear: PGear);
       
  1986 var HHGear: PGear;
       
  1987 begin
       
  1988 Gear^.doStep:= @doStepSwitcherWork;
       
  1989 
       
  1990 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  1991 with HHGear^ do
       
  1992     begin
       
  1993     State:= State and not gstAttacking;
       
  1994     Message:= Message and not gm_Attack
       
  1995     end
       
  1996 end;
       
  1997 
       
  1998 ////////////////////////////////////////////////////////////////////////////////
       
  1999 procedure doStepMortar(Gear: PGear);
       
  2000 var dX, dY: hwFloat;
       
  2001     i: LongInt;
       
  2002     dxn, dyn: boolean;
       
  2003 begin
       
  2004 AllInactive:= false;
       
  2005 dxn:= Gear^.dX.isNegative;
       
  2006 dyn:= Gear^.dY.isNegative;
       
  2007 
       
  2008 doStepFallingGear(Gear);
       
  2009 if (Gear^.State and gstCollision) <> 0 then
       
  2010     begin
       
  2011     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLAutoSound);
       
  2012 
       
  2013     Gear^.dX.isNegative:= not dxn;
       
  2014     Gear^.dY.isNegative:= not dyn;
       
  2015     for i:= 0 to 4 do
       
  2016         begin
       
  2017         dX:= Gear^.dX + (GetRandom - _0_5) * _0_03;
       
  2018         dY:= Gear^.dY + (GetRandom - _0_5) * _0_03;
       
  2019         AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtCluster, 0, dX, dY, 25);
       
  2020         end;
       
  2021 
       
  2022     DeleteGear(Gear);
       
  2023     exit
       
  2024     end;
       
  2025 
       
  2026 if (GameTicks and $3F) = 0 then
       
  2027     AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
       
  2028 end;
       
  2029 
       
  2030 ////////////////////////////////////////////////////////////////////////////////
       
  2031 procedure doStepKamikazeWork(Gear: PGear);
       
  2032 const upd: Longword = 0;
       
  2033 var i: LongWord;
       
  2034     HHGear: PGear;
  2599     HHGear: PGear;
  2035 begin
       
  2036 AllInactive:= false;
       
  2037 
       
  2038 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2039 HHGear^.State:= HHGear^.State or gstNoDamage;
       
  2040 DeleteCI(HHGear);
       
  2041 
       
  2042 i:= 2;
       
  2043 repeat
       
  2044     Gear^.X:= Gear^.X + HHGear^.dX;
       
  2045     Gear^.Y:= Gear^.Y + HHGear^.dY;
       
  2046     HHGear^.X:= Gear^.X;
       
  2047     HHGear^.Y:= Gear^.Y;
       
  2048 
       
  2049     inc(Gear^.Damage, 2);
       
  2050 
       
  2051 //  if TestCollisionXwithGear(HHGear, hwSign(Gear^.dX))
       
  2052 //      or TestCollisionYwithGear(HHGear, hwSign(Gear^.dY)) then inc(Gear^.Damage, 3);
       
  2053 
       
  2054     dec(i)
       
  2055 until (i = 0) or (Gear^.Damage > Gear^.Health);
       
  2056 
       
  2057 inc(upd);
       
  2058 if upd > 3 then
       
  2059     begin
       
  2060     if Gear^.Health < 1500 then Gear^.Pos:= 2;
       
  2061 
       
  2062     AmmoShove(Gear, 30, 40);
       
  2063 
       
  2064     DrawTunnel(HHGear^.X - HHGear^.dX * 10,
       
  2065             HHGear^.Y - _2 - HHGear^.dY * 10 + hwAbs(HHGear^.dY) * 2,
       
  2066             HHGear^.dX,
       
  2067             HHGear^.dY,
       
  2068             20 + cHHRadius * 2,
       
  2069             cHHRadius * 2 + 6);
       
  2070 
       
  2071     upd:= 0
       
  2072     end;
       
  2073 
       
  2074 if Gear^.Health < Gear^.Damage then
       
  2075     begin
       
  2076     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
       
  2077     AfterAttack;
       
  2078     DeleteGear(Gear);
       
  2079     DeleteGear(HHGear);
       
  2080     end else
       
  2081     begin
       
  2082     dec(Gear^.Health, Gear^.Damage);
       
  2083     Gear^.Damage:= 0
       
  2084     end
       
  2085 end;
       
  2086 
       
  2087 procedure doStepKamikazeIdle(Gear: PGear);
       
  2088 begin
       
  2089 AllInactive:= false;
       
  2090 dec(Gear^.Timer);
       
  2091 if Gear^.Timer = 0 then
       
  2092     begin
       
  2093     Gear^.Pos:= 1;
       
  2094     PlaySound(sndKamikaze, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
       
  2095     Gear^.doStep:= @doStepKamikazeWork
       
  2096     end
       
  2097 end;
       
  2098 
       
  2099 procedure doStepKamikaze(Gear: PGear);
       
  2100 var HHGear: PGear;
       
  2101 begin
       
  2102 AllInactive:= false;
       
  2103 
       
  2104 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2105 
       
  2106 HHGear^.dX:= Gear^.dX;
       
  2107 HHGear^.dY:= Gear^.dY;
       
  2108 
       
  2109 Gear^.dX:= SignAs(_0_45, Gear^.dX);
       
  2110 Gear^.dY:= - _0_9;
       
  2111 
       
  2112 Gear^.Timer:= 550;
       
  2113 
       
  2114 Gear^.doStep:= @doStepKamikazeIdle
       
  2115 end;
       
  2116 
       
  2117 ////////////////////////////////////////////////////////////////////////////////
       
  2118 const cakeh = 27;
       
  2119       cakeDmg = 75;
       
  2120 var CakePoints: array[0..Pred(cakeh)] of record x, y: hwFloat; end;
       
  2121     CakeI: Longword;
       
  2122 
       
  2123 procedure doStepCakeExpl(Gear: PGear);
       
  2124 begin
       
  2125 AllInactive:= false;
       
  2126 
       
  2127 inc(Gear^.Tag);
       
  2128 if Gear^.Tag < 2250 then exit;
       
  2129 
       
  2130 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg, EXPLAutoSound);
       
  2131 AfterAttack;
       
  2132 DeleteGear(Gear)
       
  2133 end;
       
  2134 
       
  2135 procedure doStepCakeDown(Gear: PGear);
       
  2136 var gi: PGear;
       
  2137     dmg: LongInt;
       
  2138 begin
       
  2139 AllInactive:= false;
       
  2140 
       
  2141 inc(Gear^.Tag);
       
  2142 if Gear^.Tag < 100 then exit;
       
  2143 Gear^.Tag:= 0;
       
  2144 
       
  2145 if Gear^.Pos = 0 then
       
  2146     begin
       
  2147     gi:= GearsList;
       
  2148     while gi <> nil do
       
  2149         begin
       
  2150         dmg:= cakeDmg * 2 - hwRound(Distance(gi^.X - Gear^.X, gi^.Y - Gear^.Y));
       
  2151         if (dmg > 1) and (gi^.Kind = gtHedgehog) then
       
  2152             if (CurrentHedgehog^.Gear = gi) and (not gi^.Invulnerable) then
       
  2153                 gi^.State:= gi^.State or gstLoser
       
  2154             else
       
  2155                 gi^.State:= gi^.State or gstWinner;
       
  2156         gi:= gi^.NextGear
       
  2157         end;
       
  2158     Gear^.doStep:= @doStepCakeExpl;
       
  2159     PlaySound(sndCake)
       
  2160     end else dec(Gear^.Pos)
       
  2161 end;
       
  2162 
       
  2163 
       
  2164 procedure doStepCakeWork(Gear: PGear);
       
  2165 const dirs: array[0..3] of TPoint = ((x: 0; y: -1), (x: 1; y: 0),(x: 0; y: 1),(x: -1; y: 0));
       
  2166 var xx, yy, xxn, yyn: LongInt;
       
  2167     da: LongInt;
       
  2168     tdx, tdy: hwFloat;
       
  2169 
       
  2170     procedure PrevAngle;
       
  2171     begin
       
  2172     Gear^.Angle:= (LongInt(Gear^.Angle) + 4 - dA) mod 4
       
  2173     end;
       
  2174 
       
  2175     procedure NextAngle;
       
  2176     begin
       
  2177     Gear^.Angle:= (LongInt(Gear^.Angle) + 4 + dA) mod 4
       
  2178     end;
       
  2179 
       
  2180 begin
       
  2181 AllInactive:= false;
       
  2182 
       
  2183 inc(Gear^.Tag);
       
  2184 if Gear^.Tag < 7 then exit;
       
  2185 
       
  2186 dA:= hwSign(Gear^.dX);
       
  2187 xx:= dirs[Gear^.Angle].x;
       
  2188 yy:= dirs[Gear^.Angle].y;
       
  2189 xxn:= dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].x;
       
  2190 yyn:= dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].y;
       
  2191 
       
  2192 if (xx = 0) then
       
  2193     if TestCollisionYwithGear(Gear, yy) then
       
  2194         PrevAngle
       
  2195     else begin
       
  2196         Gear^.Tag:= 0;
       
  2197         Gear^.Y:= Gear^.Y + int2hwFloat(yy);
       
  2198         if not TestCollisionXwithGear(Gear, xxn) then
       
  2199             begin
       
  2200             Gear^.X:= Gear^.X + int2hwFloat(xxn);
       
  2201             NextAngle
       
  2202             end;
       
  2203         end;
       
  2204 
       
  2205 if (yy = 0) then
       
  2206     if TestCollisionXwithGear(Gear, xx) then
       
  2207         PrevAngle
       
  2208     else begin
       
  2209         Gear^.Tag:= 0;
       
  2210         Gear^.X:= Gear^.X + int2hwFloat(xx);
       
  2211         if not TestCollisionYwithGear(Gear, yyn) then
       
  2212             begin
       
  2213             Gear^.Y:= Gear^.Y + int2hwFloat(yyn);
       
  2214             NextAngle
       
  2215             end;
       
  2216         end;
       
  2217 
       
  2218 if Gear^.Tag = 0 then
       
  2219     begin
       
  2220     CakeI:= (CakeI + 1) mod cakeh;
       
  2221     tdx:= CakePoints[CakeI].x - Gear^.X;
       
  2222     tdy:= - CakePoints[CakeI].y + Gear^.Y;
       
  2223     CakePoints[CakeI].x:= Gear^.X;
       
  2224     CakePoints[CakeI].y:= Gear^.Y;
       
  2225     Gear^.DirAngle:= DxDy2Angle(tdx, tdy);
       
  2226     end;
       
  2227 
       
  2228 dec(Gear^.Health);
       
  2229 Gear^.Timer:= Gear^.Health*10; // This is not seconds, but at least it is *some* feedback
       
  2230 if (Gear^.Health = 0) or ((Gear^.Message and gm_Attack) <> 0) then
       
  2231     begin
       
  2232     FollowGear:= Gear;
       
  2233     Gear^.RenderTimer:= false;
       
  2234     Gear^.doStep:= @doStepCakeDown
       
  2235     end
       
  2236 end;
       
  2237 
       
  2238 procedure doStepCakeUp(Gear: PGear);
       
  2239 var i: Longword;
       
  2240 begin
       
  2241 AllInactive:= false;
       
  2242 
       
  2243 inc(Gear^.Tag);
       
  2244 if Gear^.Tag < 100 then exit;
       
  2245 Gear^.Tag:= 0;
       
  2246 
       
  2247 if Gear^.Pos = 6 then
       
  2248     begin
       
  2249     for i:= 0 to Pred(cakeh) do
       
  2250         begin
       
  2251         CakePoints[i].x:= Gear^.X;
       
  2252         CakePoints[i].y:= Gear^.Y
       
  2253         end;
       
  2254     CakeI:= 0;
       
  2255     Gear^.doStep:= @doStepCakeWork
       
  2256     end else inc(Gear^.Pos)
       
  2257 end;
       
  2258 
       
  2259 procedure doStepCakeFall(Gear: PGear);
       
  2260 begin
       
  2261 AllInactive:= false;
       
  2262 
       
  2263 Gear^.dY:= Gear^.dY + cGravity;
       
  2264 if TestCollisionYwithGear(Gear, 1) then
       
  2265     Gear^.doStep:= @doStepCakeUp
       
  2266 else
       
  2267     begin
       
  2268     Gear^.Y:= Gear^.Y + Gear^.dY;
       
  2269     if CheckGearDrowning(Gear) then AfterAttack
       
  2270     end
       
  2271 end;
       
  2272 
       
  2273 procedure doStepCake(Gear: PGear);
       
  2274 var HHGear: PGear;
       
  2275 begin
       
  2276 AllInactive:= false;
       
  2277 
       
  2278 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2279 HHGear^.Message:= HHGear^.Message and (not gm_Attack);
       
  2280 DeleteCI(HHGear);
       
  2281 
       
  2282 FollowGear:= Gear;
       
  2283 
       
  2284 Gear^.doStep:= @doStepCakeFall
       
  2285 end;
       
  2286 
       
  2287 ////////////////////////////////////////////////////////////////////////////////
       
  2288 procedure doStepSeductionWork(Gear: PGear);
       
  2289 var x, y: LongInt;
       
  2290 begin
       
  2291 AllInactive:= false;
       
  2292 
       
  2293 Gear^.X:= Gear^.X + Gear^.dX;
       
  2294 Gear^.Y:= Gear^.Y + Gear^.dY;
       
  2295 x:= hwRound(Gear^.X);
       
  2296 y:= hwRound(Gear^.Y);
       
  2297 
       
  2298 if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
       
  2299     if (Land[y, x] <> 0) then
       
  2300         begin
       
  2301         Gear^.dX.isNegative:= not Gear^.dX.isNegative;
       
  2302         Gear^.dY.isNegative:= not Gear^.dY.isNegative;
       
  2303         Gear^.dX:= Gear^.dX * _1_5;
       
  2304         Gear^.dY:= Gear^.dY * _1_5 - _0_3;
       
  2305         AmmoShove(Gear, 0, 40);
       
  2306         AfterAttack;
       
  2307         DeleteGear(Gear)
       
  2308         end
       
  2309     else
       
  2310 else
       
  2311     begin
       
  2312     AfterAttack;
       
  2313     DeleteGear(Gear)
       
  2314     end
       
  2315 end;
       
  2316 
       
  2317 procedure doStepSeductionWear(Gear: PGear);
       
  2318 begin
       
  2319 AllInactive:= false;
       
  2320 inc(Gear^.Timer);
       
  2321 if Gear^.Timer > 250 then
       
  2322     begin
       
  2323     Gear^.Timer:= 0;
       
  2324     inc(Gear^.Pos);
       
  2325     if Gear^.Pos = 5 then
       
  2326         PlaySound(sndYoohoo, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
       
  2327     end;
       
  2328 
       
  2329 if Gear^.Pos = 14 then
       
  2330     Gear^.doStep:= @doStepSeductionWork
       
  2331 end;
       
  2332 
       
  2333 procedure doStepSeduction(Gear: PGear);
       
  2334 begin
       
  2335 AllInactive:= false;
       
  2336 DeleteCI(PHedgehog(Gear^.Hedgehog)^.Gear);
       
  2337 Gear^.doStep:= @doStepSeductionWear
       
  2338 end;
       
  2339 
       
  2340 ////////////////////////////////////////////////////////////////////////////////
       
  2341 procedure doStepWaterUp(Gear: PGear);
       
  2342 var i: LongWord;
       
  2343 begin
       
  2344 AllInactive:= false;
       
  2345 
       
  2346 inc(Gear^.Timer);
       
  2347 if Gear^.Timer = 17 then
       
  2348     Gear^.Timer:= 0
       
  2349 else
       
  2350     exit;
       
  2351 
       
  2352 if cWaterLine > 0 then
       
  2353     begin
       
  2354     dec(cWaterLine);
       
  2355     for i:= 0 to LAND_WIDTH - 1 do
       
  2356         Land[cWaterLine, i]:= 0;
       
  2357     SetAllToActive
       
  2358     end;
       
  2359 
       
  2360 inc(Gear^.Tag);
       
  2361 if (Gear^.Tag = 47) or (cWaterLine = 0) then
       
  2362     DeleteGear(Gear)
       
  2363 end;
       
  2364 
       
  2365 ////////////////////////////////////////////////////////////////////////////////
       
  2366 procedure doStepDrillDrilling(Gear: PGear);
       
  2367 var t: PGearArray;
       
  2368     ox, oy: hwFloat;
       
  2369 begin
       
  2370 AllInactive:= false;
       
  2371 
       
  2372 if (Gear^.Timer > 0) and ((Gear^.Timer mod 10) = 0) then
       
  2373     begin
       
  2374     ox:= Gear^.X;
       
  2375     oy:= Gear^.Y;
       
  2376     Gear^.X:= Gear^.X + Gear^.dX;
       
  2377     Gear^.Y:= Gear^.Y + Gear^.dY;
       
  2378     DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 2, 6);
       
  2379     if(CheckGearDrowning(Gear)) then
       
  2380         begin
       
  2381         StopSound(Gear^.SoundChannel);
       
  2382         exit
       
  2383         end
       
  2384     end;
       
  2385 
       
  2386 t:= CheckGearsCollision(Gear); //fixes drill not exploding when touching HH bug
       
  2387 if (Gear^.Timer = 0)
       
  2388 or (t^.Count <> 0)
       
  2389 or (not TestCollisionYWithGear(Gear, hwSign(Gear^.dY))
       
  2390 and not TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))
       
  2391 or (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] = COLOR_INDESTRUCTIBLE) then
       
  2392     begin //out of time or exited ground
       
  2393     StopSound(Gear^.SoundChannel);
       
  2394     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
       
  2395     DeleteGear(Gear);
       
  2396     exit
       
  2397     end;
       
  2398 
       
  2399 dec(Gear^.Timer);
       
  2400 end;
       
  2401 
       
  2402 procedure doStepDrill(Gear: PGear);
       
  2403 var t: PGearArray;
       
  2404     oldDx, oldDy: hwFloat;
       
  2405     t2: hwFloat;
       
  2406 begin
       
  2407 AllInactive:= false;
       
  2408 
       
  2409 Gear^.dX:= Gear^.dX + cWindSpeed;
       
  2410 oldDx:= Gear^.dX;
       
  2411 oldDy:= Gear^.dY;
       
  2412 
       
  2413 doStepFallingGear(Gear);
       
  2414 
       
  2415 if (GameTicks and $3F) = 0 then
       
  2416     AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
       
  2417 
       
  2418 if ((Gear^.State and gstCollision) <> 0) then begin //hit
       
  2419     Gear^.dX:= oldDx;
       
  2420     Gear^.dY:= oldDy;
       
  2421 
       
  2422     t:= CheckGearsCollision(Gear);
       
  2423     if (t^.Count = 0) then begin //hit the ground not the HH
       
  2424         t2 := _0_5 / Distance(Gear^.dX, Gear^.dY);
       
  2425         Gear^.dX:= Gear^.dX * t2;
       
  2426         Gear^.dY:= Gear^.dY * t2;
       
  2427     end else begin //explode right on contact with HH
       
  2428         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
       
  2429         DeleteGear(Gear);
       
  2430         exit;
       
  2431         end;
       
  2432 
       
  2433     Gear^.SoundChannel:= LoopSound(sndDrillRocket);
       
  2434     Gear^.doStep:= @doStepDrillDrilling;
       
  2435     dec(Gear^.Timer)
       
  2436     end
       
  2437 end;
       
  2438 
       
  2439 ////////////////////////////////////////////////////////////////////////////////
       
  2440 procedure doStepBallgunWork(Gear: PGear);
       
  2441 var HHGear: PGear;
       
  2442     rx, ry: hwFloat;
  2600     rx, ry: hwFloat;
  2443     gX, gY: LongInt;
  2601     gX, gY: LongInt;
  2444 begin
  2602 begin
  2445     AllInactive:= false;
  2603     AllInactive := false;
  2446     dec(Gear^.Timer);
  2604     dec(Gear^.Timer);
  2447     HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
  2605     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
  2448     HedgehogChAngle(HHGear);
  2606     HedgehogChAngle(HHGear);
  2449     gX:= hwRound(Gear^.X);
  2607     gX := hwRound(Gear^.X);
  2450     gY:= hwRound(Gear^.Y);
  2608     gY := hwRound(Gear^.Y);
  2451     if (Gear^.Timer mod 100) = 0 then
  2609     if (Gear^.Timer mod 100) = 0 then
  2452         begin
  2610     begin
  2453         rx:= rndSign(getRandom * _0_1);
  2611         rx := rndSign(getRandom * _0_1);
  2454         ry:= rndSign(getRandom * _0_1);
  2612         ry := rndSign(getRandom * _0_1);
  2455 
  2613 
  2456         AddGear(gx, gy, gtBall, 0,
  2614         AddGear(gx, gy, gtBall, 0,
  2457                 SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx,
  2615                 SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx,
  2458                 AngleCos(HHGear^.Angle) * ( - _0_8) + ry,
  2616         AngleCos(HHGear^.Angle) * ( - _0_8) + ry,
  2459                 0);
  2617         0);
  2460 
  2618 
  2461         PlaySound(sndGun);
  2619         PlaySound(sndGun);
  2462         end;
  2620     end;
  2463 
  2621 
  2464     if (Gear^.Timer = 0) or (HHGear^.Damage <> 0) then
  2622     if (Gear^.Timer = 0) or (HHGear^.Damage <> 0) then
  2465         begin
  2623     begin
  2466         DeleteGear(Gear);
  2624         DeleteGear(Gear);
  2467         AfterAttack
  2625         AfterAttack
  2468         end
  2626     end
  2469 end;
  2627 end;
  2470 
  2628 
  2471 procedure doStepBallgun(Gear: PGear);
  2629 procedure doStepBallgun(Gear: PGear);
  2472 var HHGear: PGear;
  2630 var 
  2473 begin
  2631     HHGear: PGear;
  2474 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
  2632 begin
  2475 HHGear^.Message:= HHGear^.Message and not (gm_Up or gm_Down);
  2633     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
  2476 HHGear^.State:= HHGear^.State or gstNotKickable;
  2634     HHGear^.Message := HHGear^.Message and not (gm_Up or gm_Down);
  2477 Gear^.doStep:= @doStepBallgunWork
  2635     HHGear^.State := HHGear^.State or gstNotKickable;
       
  2636     Gear^.doStep := @doStepBallgunWork
  2478 end;
  2637 end;
  2479 
  2638 
  2480 ////////////////////////////////////////////////////////////////////////////////
  2639 ////////////////////////////////////////////////////////////////////////////////
  2481 procedure doStepRCPlaneWork(Gear: PGear);
  2640 procedure doStepRCPlaneWork(Gear: PGear);
  2482 const cAngleSpeed = 3;
  2641 
  2483 var HHGear: PGear;
  2642 const cAngleSpeed =   3;
       
  2643 var 
       
  2644     HHGear: PGear;
  2484     i: LongInt;
  2645     i: LongInt;
  2485     dX, dY: hwFloat;
  2646     dX, dY: hwFloat;
  2486     fChanged: boolean;
  2647     fChanged: boolean;
  2487     trueAngle: Longword;
  2648     trueAngle: Longword;
  2488     t: PGear;
  2649     t: PGear;
  2489 begin
  2650 begin
  2490 AllInactive:= false;
  2651     AllInactive := false;
  2491 
  2652 
  2492 if ((TrainingFlags and tfRCPlane) = 0) and (Gear^.Timer > 0) then dec(Gear^.Timer);
  2653     if ((TrainingFlags and tfRCPlane) = 0) and (Gear^.Timer > 0) then dec(Gear^.Timer);
  2493 
  2654 
  2494 if ((TrainingFlags and tfRCPlane) <> 0) and ((TrainingFlags and tfTimeTrial) <> 0 ) and (TimeTrialStartTime = 0) then TimeTrialStartTime:= RealTicks;
  2655     if ((TrainingFlags and tfRCPlane) <> 0) and ((TrainingFlags and tfTimeTrial) <> 0 ) and (
  2495 
  2656        TimeTrialStartTime = 0) then TimeTrialStartTime := RealTicks;
  2496 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
  2657 
  2497 FollowGear:= Gear;
  2658     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
  2498 
  2659     FollowGear := Gear;
  2499 fChanged:= false;
  2660 
  2500 if ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then
  2661     fChanged := false;
  2501     begin
  2662     if ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then
  2502     fChanged:= true;
  2663     begin
  2503     if Gear^.Angle > 2048 then dec(Gear^.Angle) else
  2664         fChanged := true;
  2504         if Gear^.Angle < 2048 then inc(Gear^.Angle) else fChanged:= false
  2665         if Gear^.Angle > 2048 then dec(Gear^.Angle)
  2505     end
  2666         else
  2506 else
  2667             if Gear^.Angle < 2048 then inc(Gear^.Angle)
  2507     begin
  2668         else fChanged := false
  2508     if ((Gear^.Message and gm_Left) <> 0) then
  2669     end
  2509         begin
  2670     else
  2510         fChanged:= true;
  2671     begin
  2511         Gear^.Angle:= (Gear^.Angle + (4096 - cAngleSpeed)) mod 4096
  2672         if ((Gear^.Message and gm_Left) <> 0) then
  2512         end;
  2673         begin
  2513 
  2674             fChanged := true;
  2514     if ((Gear^.Message and gm_Right) <> 0) then
  2675             Gear^.Angle := (Gear^.Angle + (4096 - cAngleSpeed)) mod 4096
  2515         begin
  2676         end;
  2516         fChanged:= true;
  2677 
  2517         Gear^.Angle:= (Gear^.Angle + cAngleSpeed) mod 4096
  2678         if ((Gear^.Message and gm_Right) <> 0) then
       
  2679         begin
       
  2680             fChanged := true;
       
  2681             Gear^.Angle := (Gear^.Angle + cAngleSpeed) mod 4096
  2518         end
  2682         end
  2519     end;
  2683     end;
  2520 
  2684 
  2521 if fChanged then
  2685     if fChanged then
  2522     begin
  2686     begin
  2523     Gear^.dX.isNegative:= (Gear^.Angle > 2048);
  2687         Gear^.dX.isNegative := (Gear^.Angle > 2048);
  2524     if Gear^.dX.isNegative then
  2688         if Gear^.dX.isNegative then
  2525         trueAngle:= 4096 - Gear^.Angle
  2689             trueAngle := 4096 - Gear^.Angle
  2526     else
  2690         else
  2527         trueAngle:= Gear^.Angle;
  2691             trueAngle := Gear^.Angle;
  2528 
  2692 
  2529     Gear^.dX:= SignAs(AngleSin(trueAngle), Gear^.dX) * _0_25;
  2693         Gear^.dX := SignAs(AngleSin(trueAngle), Gear^.dX) * _0_25;
  2530     Gear^.dY:= AngleCos(trueAngle) * -_0_25;
  2694         Gear^.dY := AngleCos(trueAngle) * -_0_25;
  2531     end;
  2695     end;
  2532 
  2696 
  2533 Gear^.X:= Gear^.X + Gear^.dX;
  2697     Gear^.X := Gear^.X + Gear^.dX;
  2534 Gear^.Y:= Gear^.Y + Gear^.dY;
  2698     Gear^.Y := Gear^.Y + Gear^.dY;
  2535 
  2699 
  2536 if (TrainingFlags and tfRCPlane) = 0 then
  2700     if (TrainingFlags and tfRCPlane) = 0 then
  2537     begin
  2701     begin
  2538     if (GameTicks and $FF) = 0 then
  2702         if (GameTicks and $FF) = 0 then
  2539         if Gear^.Timer < 3500 then
  2703             if Gear^.Timer < 3500 then
  2540             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
  2704                 AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
  2541         else
  2705         else
  2542             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  2706             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  2543 
  2707 
  2544     if ((HHGear^.Message and gm_Attack) <> 0) and (Gear^.Health <> 0) then
  2708         if ((HHGear^.Message and gm_Attack) <> 0) and (Gear^.Health <> 0) then
  2545         begin
  2709         begin
  2546         HHGear^.Message := HHGear^.Message and not gm_Attack;
  2710             HHGear^.Message := HHGear^.Message and not gm_Attack;
  2547         AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY * _0_5, 0);
  2711             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
  2548         dec(Gear^.Health)
  2712             _0_5, 0);
  2549         end;
  2713             dec(Gear^.Health)
  2550 
  2714         end;
  2551     if ((HHGear^.Message and gm_LJump) <> 0)
  2715 
  2552         and ((Gear^.State and gsttmpFlag) = 0) then
  2716         if ((HHGear^.Message and gm_LJump) <> 0)
  2553         begin
  2717            and ((Gear^.State and gsttmpFlag) = 0) then
  2554         Gear^.State:= Gear^.State or gsttmpFlag;
  2718         begin
  2555         PauseMusic;
  2719             Gear^.State := Gear^.State or gsttmpFlag;
  2556         playSound(sndRideOfTheValkyries);
  2720             PauseMusic;
  2557         end;
  2721             playSound(sndRideOfTheValkyries);
  2558 
  2722         end;
  2559     // pickup bonuses
  2723 
  2560     t:= CheckGearNear(Gear, gtCase, 36, 36);
  2724         // pickup bonuses
  2561     if t <> nil then
  2725         t := CheckGearNear(Gear, gtCase, 36, 36);
  2562         PickUp(HHGear, t);
  2726         if t <> nil then
  2563     end
  2727             PickUp(HHGear, t);
  2564 else
  2728     end
  2565     begin
  2729     else
  2566     if (GameTicks and $FF) = 0 then
  2730     begin
  2567         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  2731         if (GameTicks and $FF) = 0 then
  2568 
  2732             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  2569     // pickup targets
  2733 
  2570     t:= CheckGearNear(Gear, gtTarget, 36, 36);
  2734         // pickup targets
  2571     if t <> nil then
  2735         t := CheckGearNear(Gear, gtTarget, 36, 36);
  2572         begin
  2736         if t <> nil then
  2573         if t^.Tag <> 0 then // collect it only once
  2737         begin
       
  2738             if t^.Tag <> 0 then // collect it only once
       
  2739                 exit;
       
  2740             PlaySound(sndShotgunReload);
       
  2741             t^.Tag := 1;
       
  2742             TrainingTargetGear := nil;
       
  2743             // remove target cursor
  2574             exit;
  2744             exit;
  2575         PlaySound(sndShotgunReload);
  2745         end;
  2576         t^.Tag:= 1;
  2746 
  2577         TrainingTargetGear:= nil; // remove target cursor
  2747         if (TurnTimeLeft > 0) then
  2578         exit;
  2748             dec(TurnTimeLeft)
  2579         end;
  2749     end;
  2580 
  2750 
  2581     if (TurnTimeLeft > 0) then 
  2751     CheckCollision(Gear);
  2582         dec(TurnTimeLeft)
  2752 
  2583     end;
  2753     if ((Gear^.State and gstCollision) <> 0) or (((TrainingFlags and tfRCPlane) <> 0) and (
  2584         
  2754        TurnTimeLeft = 0))
  2585 CheckCollision(Gear);
  2755        or CheckGearDrowning(Gear) then
  2586 
  2756     begin
  2587 if ((Gear^.State and gstCollision) <> 0) or (((TrainingFlags and tfRCPlane) <> 0) and (TurnTimeLeft = 0))
  2757         if ((TrainingFlags and tfRCPlane) <> 0) and ((TrainingFlags and tfTimeTrial) <> 0 ) and (
  2588     or CheckGearDrowning(Gear) then
  2758            TimeTrialStopTime = 0) then TimeTrialStopTime := RealTicks;
  2589     begin
  2759         StopSound(Gear^.SoundChannel);
  2590     if ((TrainingFlags and tfRCPlane) <> 0) and ((TrainingFlags and tfTimeTrial) <> 0 ) and (TimeTrialStopTime = 0) then TimeTrialStopTime:= RealTicks;
  2760         StopSound(sndRideOfTheValkyries);
  2591     StopSound(Gear^.SoundChannel);
  2761         ResumeMusic;
  2592     StopSound(sndRideOfTheValkyries);
  2762 
  2593     ResumeMusic;
  2763         if ((Gear^.State and gstCollision) <> 0) or (((TrainingFlags and tfRCPlane) <> 0) and (
  2594 
  2764            TurnTimeLeft = 0)) then
  2595     if ((Gear^.State and gstCollision) <> 0) or (((TrainingFlags and tfRCPlane) <> 0) and (TurnTimeLeft = 0)) then
  2765         begin
  2596         begin
  2766             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, EXPLAutoSound);
  2597         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, EXPLAutoSound);
  2767             for i:= 0 to 32 do
  2598         for i:= 0 to 32 do
       
  2599             begin
  2768             begin
  2600             dX:= AngleCos(i * 64) * _0_5 * (GetRandom + _1);
  2769                 dX := AngleCos(i * 64) * _0_5 * (GetRandom + _1);
  2601             dY:= AngleSin(i * 64) * _0_5 * (GetRandom + _1);
  2770                 dY := AngleSin(i * 64) * _0_5 * (GetRandom + _1);
  2602             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, dY, 0);
  2771                 AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, dY, 0);
  2603             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, -dY, 0);
  2772                 AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, -dY, 0);
  2604             end;
  2773             end;
  2605         DeleteGear(Gear)
  2774             DeleteGear(Gear)
  2606         end;
  2775         end;
  2607 
  2776 
  2608     AfterAttack;
  2777         AfterAttack;
  2609     CurAmmoGear:= nil;
  2778         CurAmmoGear := nil;
  2610     TurnTimeLeft:= 14 * 125;
  2779         TurnTimeLeft := 14 * 125;
  2611     
  2780 
  2612     if (TrainingFlags and tfRCPlane) <> 0 then
  2781         if (TrainingFlags and tfRCPlane) <> 0 then
  2613         TurnTimeLeft:= 0; // HACK: RCPlane training allows unlimited plane starts in last 2 seconds
  2782             TurnTimeLeft := 0;
  2614 
  2783         // HACK: RCPlane training allows unlimited plane starts in last 2 seconds
  2615     HHGear^.Message:= 0;
  2784 
  2616     ParseCommand('/taunt '#1, true)
  2785         HHGear^.Message := 0;
       
  2786         ParseCommand('/taunt '#1, true)
  2617     end
  2787     end
  2618 end;
  2788 end;
  2619 
  2789 
  2620 procedure doStepRCPlane(Gear: PGear);
  2790 procedure doStepRCPlane(Gear: PGear);
  2621 var HHGear: PGear;
  2791 var 
  2622 begin
  2792     HHGear: PGear;
  2623 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
  2793 begin
  2624 HHGear^.Message:= 0;
  2794     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
  2625 HHGear^.State:= HHGear^.State or gstNotKickable;
  2795     HHGear^.Message := 0;
  2626 Gear^.Angle:= HHGear^.Angle;
  2796     HHGear^.State := HHGear^.State or gstNotKickable;
  2627 Gear^.Tag:= hwSign(HHGear^.dX);
  2797     Gear^.Angle := HHGear^.Angle;
  2628 if HHGear^.dX.isNegative then Gear^.Angle:= 4096 - Gear^.Angle;
  2798     Gear^.Tag := hwSign(HHGear^.dX);
  2629 Gear^.doStep:= @doStepRCPlaneWork
  2799     if HHGear^.dX.isNegative then Gear^.Angle := 4096 - Gear^.Angle;
       
  2800     Gear^.doStep := @doStepRCPlaneWork
  2630 end;
  2801 end;
  2631 
  2802 
  2632 procedure doStepJetpackWork(Gear: PGear);
  2803 procedure doStepJetpackWork(Gear: PGear);
  2633 var HHGear: PGear;
  2804 var 
       
  2805     HHGear: PGear;
  2634     fuel: LongInt;
  2806     fuel: LongInt;
  2635     move: hwFloat;
  2807     move: hwFloat;
  2636 begin
  2808 begin
  2637 AllInactive:= false;
  2809     AllInactive := false;
  2638 HHGear:=PHedgehog(Gear^.Hedgehog)^.Gear;
  2810     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
  2639 //dec(Gear^.Timer);
  2811     //dec(Gear^.Timer);
  2640 move:= _0_1;
  2812     move := _0_1;
  2641 fuel:= 50;
  2813     fuel := 50;
  2642 (*if (HHGear^.Message and gm_Precise) <> 0 then
  2814 (*if (HHGear^.Message and gm_Precise) <> 0 then
  2643     begin
  2815     begin
  2644     move:= _0_02;
  2816     move:= _0_02;
  2645     fuel:= 5;
  2817     fuel:= 5;
  2646     end;*)
  2818     end;*)
  2647 
  2819 
  2648 if (HHGear^.Message and gm_Up) <> 0 then
  2820     if (HHGear^.Message and gm_Up) <> 0 then
  2649     begin
  2821     begin
  2650     if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
  2822         if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
  2651         HHGear^.dY:= HHGear^.dY - move;
  2823             HHGear^.dY := HHGear^.dY - move;
  2652     HHGear^.dY:= HHGear^.dY - move;
  2824         HHGear^.dY := HHGear^.dY - move;
  2653     dec(Gear^.Health, fuel);
  2825         dec(Gear^.Health, fuel);
  2654     Gear^.MsgParam:= Gear^.MsgParam or gm_Up;
  2826         Gear^.MsgParam := Gear^.MsgParam or gm_Up;
  2655     Gear^.Timer:= GameTicks
  2827         Gear^.Timer := GameTicks
  2656     end;
  2828     end;
  2657 if (HHGear^.Message and gm_Left) <> 0 then move.isNegative:= true;
  2829     if (HHGear^.Message and gm_Left) <> 0 then move.isNegative := true;
  2658 if (HHGear^.Message and (gm_Left or gm_Right)) <> 0 then
  2830     if (HHGear^.Message and (gm_Left or gm_Right)) <> 0 then
  2659     begin
  2831     begin
  2660     HHGear^.dX:= HHGear^.dX + (move * _0_2);
  2832         HHGear^.dX := HHGear^.dX + (move * _0_2);
  2661     dec(Gear^.Health, fuel div 5);
  2833         dec(Gear^.Health, fuel div 5);
  2662     Gear^.MsgParam:= Gear^.MsgParam or (HHGear^.Message and (gm_Left or gm_Right));
  2834         Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gm_Left or gm_Right));
  2663     Gear^.Timer:= GameTicks
  2835         Gear^.Timer := GameTicks
  2664     end;
  2836     end;
  2665 
  2837 
  2666 // erases them all at once :-/
  2838     // erases them all at once :-/
  2667 if (Gear^.Timer <> 0) and (GameTicks - Gear^.Timer > 250) then
  2839     if (Gear^.Timer <> 0) and (GameTicks - Gear^.Timer > 250) then
  2668     begin
  2840     begin
  2669     Gear^.Timer:= 0;
  2841         Gear^.Timer := 0;
  2670     Gear^.MsgParam:= 0
  2842         Gear^.MsgParam := 0
  2671     end;
  2843     end;
  2672 
  2844 
  2673 if Gear^.Health < 0 then Gear^.Health:= 0;
  2845     if Gear^.Health < 0 then Gear^.Health := 0;
  2674 if (GameTicks and $3F) = 0 then
  2846     if (GameTicks and $3F) = 0 then
  2675        begin
  2847     begin
  2676 //AddCaption('Fuel: '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
  2848         //AddCaption('Fuel: '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
  2677        if Gear^.Tex <> nil then FreeTexture(Gear^.Tex);
  2849         if Gear^.Tex <> nil then FreeTexture(Gear^.Tex);
  2678        Gear^.Tex:= RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(round(Gear^.Health / 20)) + '%', cWhiteColor, fntSmall)
  2850         Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(round(Gear^.Health / 20)) +
  2679        end;
  2851                      '%', cWhiteColor, fntSmall)
  2680 
  2852     end;
  2681 if HHGear^.Message and (gm_Attack or gm_Up or gm_Precise or gm_Left or gm_Right) <> 0 then Gear^.State:= Gear^.State and not gsttmpFlag;
  2853 
  2682 HHGear^.Message:= HHGear^.Message and not (gm_Up or gm_Precise or gm_Left or gm_Right);
  2854     if HHGear^.Message and (gm_Attack or gm_Up or gm_Precise or gm_Left or gm_Right) <> 0 then Gear^
  2683 HHGear^.State:= HHGear^.State or gstMoving;
  2855         .State := Gear^.State and not gsttmpFlag;
  2684 
  2856     HHGear^.Message := HHGear^.Message and not (gm_Up or gm_Precise or gm_Left or gm_Right);
  2685 Gear^.X:= HHGear^.X;
  2857     HHGear^.State := HHGear^.State or gstMoving;
  2686 Gear^.Y:= HHGear^.Y;
  2858 
  2687 // For some reason I need to reapply followgear here, something else grabs it otherwise.
  2859     Gear^.X := HHGear^.X;
  2688 if not bShowAmmoMenu then FollowGear:= HHGear;
  2860     Gear^.Y := HHGear^.Y;
  2689 
  2861     // For some reason I need to reapply followgear here, something else grabs it otherwise.
  2690 if ((Gear^.State and gsttmpFlag) = 0) or (HHGear^.dY < _0) then doStepHedgehogMoving(HHGear);
  2862     if not bShowAmmoMenu then FollowGear := HHGear;
  2691 
  2863 
  2692 if  (Gear^.Health = 0)
  2864     if ((Gear^.State and gsttmpFlag) = 0) or (HHGear^.dY < _0) then doStepHedgehogMoving(HHGear);
  2693     or (HHGear^.Damage <> 0)
  2865 
  2694     or CheckGearDrowning(HHGear)
  2866     if  (Gear^.Health = 0)
  2695     or (TurnTimeLeft = 0)
  2867        or (HHGear^.Damage <> 0)
  2696     // allow brief ground touches - to be fair on this, might need another counter
  2868        or CheckGearDrowning(HHGear)
  2697     or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and TestCollisionYwithGear(HHGear, 1))
  2869        or (TurnTimeLeft = 0)
  2698     or ((Gear^.Message and gm_Attack) <> 0) then
  2870        // allow brief ground touches - to be fair on this, might need another counter
  2699     begin
  2871        or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and TestCollisionYwithGear(
       
  2872        HHGear, 1))
       
  2873        or ((Gear^.Message and gm_Attack) <> 0) then
       
  2874     begin
       
  2875         with HHGear^ do
       
  2876         begin
       
  2877             Message := 0;
       
  2878             Active := true;
       
  2879             State := State or gstMoving
       
  2880         end;
       
  2881         DeleteGear(Gear);
       
  2882         isCursorVisible := false;
       
  2883         ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
       
  2884         //    if Gear^.Tex <> nil then FreeTexture(Gear^.Tex);
       
  2885 
       
  2886 //    Gear^.Tex:= RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(round(Gear^.Health / 20)) + '%', cWhiteColor, fntSmall)
       
  2887 
       
  2888 //AddCaption(trmsg[sidFuel]+': '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
       
  2889     end
       
  2890 end;
       
  2891 
       
  2892 ////////////////////////////////////////////////////////////////////////////////
       
  2893 procedure doStepJetpack(Gear: PGear);
       
  2894 var 
       
  2895     HHGear: PGear;
       
  2896 begin
       
  2897     Gear^.doStep := @doStepJetpackWork;
       
  2898 
       
  2899     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2900     FollowGear := HHGear;
       
  2901     AfterAttack;
  2700     with HHGear^ do
  2902     with HHGear^ do
  2701         begin
  2903     begin
  2702         Message:= 0;
  2904         State := State and not gstAttacking;
  2703         Active:= true;
  2905         Message := Message and not (gm_Attack or gm_Up or gm_Precise or gm_Left or gm_Right);
  2704         State:= State or gstMoving
  2906         if (dY < _0_1) and (dY > -_0_1) then
  2705         end;
  2907         begin
  2706     DeleteGear(Gear);
  2908             Gear^.State := Gear^.State or gsttmpFlag;
  2707     isCursorVisible:= false;
  2909             dY := dY - _0_2
  2708     ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
       
  2709 //    if Gear^.Tex <> nil then FreeTexture(Gear^.Tex);
       
  2710 //    Gear^.Tex:= RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(round(Gear^.Health / 20)) + '%', cWhiteColor, fntSmall)
       
  2711     //AddCaption(trmsg[sidFuel]+': '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
       
  2712     end
       
  2713 end;
       
  2714 
       
  2715 ////////////////////////////////////////////////////////////////////////////////
       
  2716 procedure doStepJetpack(Gear: PGear);
       
  2717 var HHGear: PGear;
       
  2718 begin
       
  2719 Gear^.doStep:= @doStepJetpackWork;
       
  2720 
       
  2721 HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
       
  2722 FollowGear:= HHGear;
       
  2723 AfterAttack;
       
  2724 with HHGear^ do
       
  2725     begin
       
  2726     State:= State and not gstAttacking;
       
  2727     Message:= Message and not (gm_Attack or gm_Up or gm_Precise or gm_Left or gm_Right);
       
  2728     if (dY < _0_1) and (dY > -_0_1) then
       
  2729         begin
       
  2730         Gear^.State:= Gear^.State or gsttmpFlag;
       
  2731         dY:= dY - _0_2
       
  2732         end
  2910         end
  2733     end
  2911     end
  2734 end;
  2912 end;
  2735 
  2913 
  2736 ////////////////////////////////////////////////////////////////////////////////
  2914 ////////////////////////////////////////////////////////////////////////////////
  2737 procedure doStepBirdyDisappear(Gear: PGear);
  2915 procedure doStepBirdyDisappear(Gear: PGear);
  2738 begin
  2916 begin
  2739 AllInactive:= false;
  2917     AllInactive := false;
  2740 Gear^.Pos:= 0;
  2918     Gear^.Pos := 0;
  2741 if Gear^.Timer < 2000 then
  2919     if Gear^.Timer < 2000 then
  2742     inc(Gear^.Timer, 1)
  2920         inc(Gear^.Timer, 1)
  2743 else
  2921     else
  2744     begin
  2922     begin
  2745     DeleteGear(Gear);
  2923         DeleteGear(Gear);
  2746     end;
  2924     end;
  2747 end;
  2925 end;
  2748 
  2926 
  2749 ////////////////////////////////////////////////////////////////////////////////
  2927 ////////////////////////////////////////////////////////////////////////////////
  2750 procedure doStepBirdyFly(Gear: PGear);
  2928 procedure doStepBirdyFly(Gear: PGear);
  2751 var HHGear: PGear;
  2929 var 
       
  2930     HHGear: PGear;
  2752     fuel, i: LongInt;
  2931     fuel, i: LongInt;
  2753     move: hwFloat;
  2932     move: hwFloat;
  2754 begin
  2933 begin
  2755 HHGear:= CurrentHedgehog^.Gear;
  2934     HHGear := CurrentHedgehog^.Gear;
  2756 
  2935 
  2757 move:= _0_1;
  2936     move := _0_1;
  2758 fuel:= 50;
  2937     fuel := 50;
  2759 
  2938 
  2760 if Gear^.Pos > 0 then
  2939     if Gear^.Pos > 0 then
  2761     dec(Gear^.Pos, 1)
  2940         dec(Gear^.Pos, 1)
  2762 else if (HHGear^.Message and (gm_Left or gm_Right or gm_Up)) <> 0 then
  2941     else if (HHGear^.Message and (gm_Left or gm_Right or gm_Up)) <> 0 then
  2763     Gear^.Pos:= 500;
  2942              Gear^.Pos := 500;
  2764 
  2943 
  2765 if HHGear^.dX.isNegative then
  2944     if HHGear^.dX.isNegative then
  2766     Gear^.Tag:= -1
  2945         Gear^.Tag := -1
  2767 else
  2946     else
  2768     Gear^.Tag:= 1;
  2947         Gear^.Tag := 1;
  2769 
  2948 
  2770 if (HHGear^.Message and gm_Up) <> 0 then
  2949     if (HHGear^.Message and gm_Up) <> 0 then
  2771     begin
  2950     begin
  2772     if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
  2951         if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
  2773         HHGear^.dY:= HHGear^.dY - move;
  2952             HHGear^.dY := HHGear^.dY - move;
  2774     HHGear^.dY:= HHGear^.dY - move;
  2953         HHGear^.dY := HHGear^.dY - move;
  2775     dec(Gear^.Health, fuel);
  2954         dec(Gear^.Health, fuel);
  2776     Gear^.MsgParam:= Gear^.MsgParam or gm_Up;
  2955         Gear^.MsgParam := Gear^.MsgParam or gm_Up;
  2777     end;
  2956     end;
  2778 if (HHGear^.Message and gm_Left) <> 0 then move.isNegative:= true;
  2957     if (HHGear^.Message and gm_Left) <> 0 then move.isNegative := true;
  2779 if (HHGear^.Message and (gm_Left or gm_Right)) <> 0 then
  2958     if (HHGear^.Message and (gm_Left or gm_Right)) <> 0 then
  2780     begin
  2959     begin
  2781     HHGear^.dX:= HHGear^.dX + (move * _0_2);
  2960         HHGear^.dX := HHGear^.dX + (move * _0_2);
  2782     dec(Gear^.Health, fuel div 5);
  2961         dec(Gear^.Health, fuel div 5);
  2783     Gear^.MsgParam:= Gear^.MsgParam or (HHGear^.Message and (gm_Left or gm_Right));
  2962         Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gm_Left or gm_Right));
  2784     end;
  2963     end;
  2785 
  2964 
  2786 if Gear^.Health < 0 then Gear^.Health:= 0;
  2965     if Gear^.Health < 0 then Gear^.Health := 0;
  2787 if ((GameTicks and $FF) = 0) and (Gear^.Health < 500) then
  2966     if ((GameTicks and $FF) = 0) and (Gear^.Health < 500) then
  2788     for i:= ((500-Gear^.Health) div 250) downto 0 do
  2967         for i:= ((500-Gear^.Health) div 250) downto 0 do
  2789         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFeather);
  2968             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFeather);
  2790 
  2969 
  2791 if (HHGear^.Message and gm_Attack <> 0) then begin
  2970     if (HHGear^.Message and gm_Attack <> 0) then
       
  2971     begin
  2792         HHGear^.Message := HHGear^.Message and not gm_Attack;
  2972         HHGear^.Message := HHGear^.Message and not gm_Attack;
  2793         if Gear^.FlightTime > 0 then begin
  2973         if Gear^.FlightTime > 0 then
  2794             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + 32, gtEgg, 0, Gear^.dX * _0_5, Gear^.dY, 0);
  2974         begin
       
  2975             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + 32, gtEgg, 0, Gear^.dX * _0_5, Gear^.dY, 0)
       
  2976             ;
  2795             PlaySound(sndBirdyLay);
  2977             PlaySound(sndBirdyLay);
  2796             dec(Gear^.FlightTime)
  2978             dec(Gear^.FlightTime)
  2797         end;
  2979         end;
  2798 end;
  2980     end;
  2799 
  2981 
  2800 if HHGear^.Message and (gm_Up or gm_Precise or gm_Left or gm_Right) <> 0 then Gear^.State:= Gear^.State and not gsttmpFlag;
  2982     if HHGear^.Message and (gm_Up or gm_Precise or gm_Left or gm_Right) <> 0 then Gear^.State := 
  2801 HHGear^.Message:= HHGear^.Message and not (gm_Up or gm_Precise or gm_Left or gm_Right);
  2983                                                                                                 Gear
  2802 HHGear^.State:= HHGear^.State or gstMoving;
  2984                                                                                                  ^.
  2803 
  2985                                                                                                State
  2804 Gear^.X:= HHGear^.X;
  2986                                                                                                  and
  2805 Gear^.Y:= HHGear^.Y - int2hwFloat(32);
  2987                                                                                                  not
  2806 // For some reason I need to reapply followgear here, something else grabs it otherwise.
  2988                                                                                           gsttmpFlag
  2807 if not bShowAmmoMenu then FollowGear:= HHGear;
  2989     ;
  2808 
  2990     HHGear^.Message := HHGear^.Message and not (gm_Up or gm_Precise or gm_Left or gm_Right);
  2809 if ((Gear^.State and gsttmpFlag) = 0) or (HHGear^.dY < _0) then doStepHedgehogMoving(HHGear);
  2991     HHGear^.State := HHGear^.State or gstMoving;
  2810 
  2992 
  2811 if  (Gear^.Health = 0)
  2993     Gear^.X := HHGear^.X;
  2812     or (HHGear^.Damage <> 0)
  2994     Gear^.Y := HHGear^.Y - int2hwFloat(32);
  2813     or CheckGearDrowning(HHGear)
  2995     // For some reason I need to reapply followgear here, something else grabs it otherwise.
  2814     or (TurnTimeLeft = 0)
  2996     if not bShowAmmoMenu then FollowGear := HHGear;
  2815     // allow brief ground touches - to be fair on this, might need another counter
  2997 
  2816     or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and TestCollisionYwithGear(HHGear, 1))
  2998     if ((Gear^.State and gsttmpFlag) = 0) or (HHGear^.dY < _0) then doStepHedgehogMoving(HHGear);
  2817     or ((Gear^.Message and gm_Attack) <> 0) then
  2999 
  2818     begin
  3000     if  (Gear^.Health = 0)
       
  3001        or (HHGear^.Damage <> 0)
       
  3002        or CheckGearDrowning(HHGear)
       
  3003        or (TurnTimeLeft = 0)
       
  3004        // allow brief ground touches - to be fair on this, might need another counter
       
  3005        or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and TestCollisionYwithGear(
       
  3006        HHGear, 1))
       
  3007        or ((Gear^.Message and gm_Attack) <> 0) then
       
  3008     begin
       
  3009         with HHGear^ do
       
  3010         begin
       
  3011             Message := 0;
       
  3012             Active := true;
       
  3013             State := State or gstMoving
       
  3014         end;
       
  3015         Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
       
  3016         if HHGear^.dY < _0 then
       
  3017         begin
       
  3018             Gear^.dX := HHGear^.dX;
       
  3019             Gear^.dY := HHGear^.dY;
       
  3020         end;
       
  3021         Gear^.Timer := 0;
       
  3022         Gear^.doStep := @doStepBirdyDisappear;
       
  3023         CurAmmoGear := nil;
       
  3024         isCursorVisible := false;
       
  3025         AfterAttack;
       
  3026     end
       
  3027 end;
       
  3028 
       
  3029 ////////////////////////////////////////////////////////////////////////////////
       
  3030 procedure doStepBirdyDescend(Gear: PGear);
       
  3031 var 
       
  3032     HHGear: PGear;
       
  3033 begin
       
  3034     if Gear^.Timer > 0 then
       
  3035         dec(Gear^.Timer, 1)
       
  3036     else if CurrentHedgehog = nil then
       
  3037         begin
       
  3038             DeleteGear(Gear);
       
  3039             AfterAttack;
       
  3040             exit
       
  3041         end;
       
  3042     HHGear := CurrentHedgehog^.Gear;
       
  3043     HHGear^.Message := HHGear^.Message and not (gm_Up or gm_Precise or gm_Left or gm_Right);
       
  3044     if abs(hwRound(HHGear^.Y - Gear^.Y)) > 32 then
       
  3045     begin
       
  3046         if Gear^.Timer = 0 then
       
  3047             Gear^.Y := Gear^.Y + _0_1
       
  3048     end
       
  3049     else if Gear^.Timer = 0 then
       
  3050         begin
       
  3051             Gear^.doStep := @doStepBirdyFly;
       
  3052             HHGear^.dY := -_0_2
       
  3053         end
       
  3054 end;
       
  3055 
       
  3056 procedure doStepBirdyAppear(Gear: PGear);
       
  3057 begin
       
  3058     Gear^.Pos := 0;
       
  3059     if Gear^.Timer < 2000 then
       
  3060         inc(Gear^.Timer, 1)
       
  3061     else
       
  3062     begin
       
  3063         Gear^.Timer := 500;
       
  3064         Gear^.dX := _0;
       
  3065         Gear^.dY := _0;
       
  3066         Gear^.State :=  Gear^.State and not gstAnimation;
       
  3067         Gear^.doStep := @doStepBirdyDescend;
       
  3068     end
       
  3069 end;
       
  3070 
       
  3071 ////////////////////////////////////////////////////////////////////////////////
       
  3072 procedure doStepBirdy(Gear: PGear);
       
  3073 var 
       
  3074     HHGear: PGear;
       
  3075 begin
       
  3076     gear^.State :=  gear^.State or gstAnimation and not gstTmpFlag;
       
  3077     Gear^.doStep := @doStepBirdyAppear;
       
  3078     if CurrentHedgehog = nil then
       
  3079     begin
       
  3080         DeleteGear(Gear);
       
  3081         exit
       
  3082     end;
       
  3083 
       
  3084     HHGear := CurrentHedgehog^.Gear;
       
  3085 
       
  3086     if HHGear^.dX.isNegative then
       
  3087         Gear^.Tag := -1
       
  3088     else
       
  3089         Gear^.Tag := 1;
       
  3090     Gear^.Pos := 0;
       
  3091     AllInactive := false;
       
  3092     FollowGear := HHGear;
  2819     with HHGear^ do
  3093     with HHGear^ do
  2820         begin
  3094     begin
  2821         Message:= 0;
  3095         State := State and not gstAttacking;
  2822         Active:= true;
  3096         Message := Message and not (gm_Attack or gm_Up or gm_Precise or gm_Left or gm_Right)
  2823         State:= State or gstMoving
       
  2824         end;
       
  2825     Gear^.State:= Gear^.State or gstAnimation or gstTmpFlag;
       
  2826     if HHGear^.dY < _0 then
       
  2827         begin
       
  2828         Gear^.dX:= HHGear^.dX;
       
  2829         Gear^.dY:= HHGear^.dY;
       
  2830         end;
       
  2831     Gear^.Timer:= 0;
       
  2832     Gear^.doStep:= @doStepBirdyDisappear;
       
  2833     CurAmmoGear:= nil;
       
  2834     isCursorVisible:= false;
       
  2835     AfterAttack;
       
  2836     end
       
  2837 end;
       
  2838 
       
  2839 ////////////////////////////////////////////////////////////////////////////////
       
  2840 procedure doStepBirdyDescend(Gear: PGear);
       
  2841 var HHGear: PGear;
       
  2842 begin
       
  2843 if Gear^.Timer > 0 then
       
  2844     dec(Gear^.Timer, 1)
       
  2845 else if CurrentHedgehog = nil then
       
  2846     begin
       
  2847     DeleteGear(Gear);
       
  2848     AfterAttack;
       
  2849     exit
       
  2850     end;
       
  2851 HHGear:= CurrentHedgehog^.Gear;
       
  2852 HHGear^.Message:= HHGear^.Message and not (gm_Up or gm_Precise or gm_Left or gm_Right);
       
  2853 if abs(hwRound(HHGear^.Y - Gear^.Y)) > 32 then
       
  2854     begin
       
  2855     if Gear^.Timer = 0 then
       
  2856         Gear^.Y:= Gear^.Y + _0_1
       
  2857     end
       
  2858 else if Gear^.Timer = 0 then
       
  2859     begin
       
  2860     Gear^.doStep:= @doStepBirdyFly;
       
  2861     HHGear^.dY:= -_0_2
       
  2862     end
       
  2863 end;
       
  2864 
       
  2865 procedure doStepBirdyAppear(Gear: PGear);
       
  2866 begin
       
  2867 Gear^.Pos:= 0;
       
  2868 if Gear^.Timer < 2000 then
       
  2869     inc(Gear^.Timer, 1)
       
  2870 else
       
  2871     begin
       
  2872     Gear^.Timer:= 500;
       
  2873     Gear^.dX:= _0;
       
  2874     Gear^.dY:= _0;
       
  2875     Gear^.State:=  Gear^.State and not gstAnimation;
       
  2876     Gear^.doStep:= @doStepBirdyDescend;
       
  2877     end
       
  2878 end;
       
  2879 
       
  2880 ////////////////////////////////////////////////////////////////////////////////
       
  2881 procedure doStepBirdy(Gear: PGear);
       
  2882 var HHGear: PGear;
       
  2883 begin
       
  2884 gear^.State:=  gear^.State or gstAnimation and not gstTmpFlag;
       
  2885 Gear^.doStep:= @doStepBirdyAppear;
       
  2886 if CurrentHedgehog = nil then
       
  2887     begin
       
  2888     DeleteGear(Gear);
       
  2889     exit
       
  2890     end;
       
  2891 
       
  2892 HHGear:= CurrentHedgehog^.Gear;
       
  2893 
       
  2894 if HHGear^.dX.isNegative then
       
  2895     Gear^.Tag:= -1
       
  2896 else
       
  2897     Gear^.Tag:= 1;
       
  2898 Gear^.Pos:= 0;
       
  2899 AllInactive:= false;
       
  2900 FollowGear:= HHGear;
       
  2901 with HHGear^ do
       
  2902     begin
       
  2903     State:= State and not gstAttacking;
       
  2904     Message:= Message and not (gm_Attack or gm_Up or gm_Precise or gm_Left or gm_Right)
       
  2905     end
  3097     end
  2906 end;
  3098 end;
  2907 
  3099 
  2908 ////////////////////////////////////////////////////////////////////////////////
  3100 ////////////////////////////////////////////////////////////////////////////////
  2909 procedure doStepEggWork(Gear: PGear);
  3101 procedure doStepEggWork(Gear: PGear);
  2910 var vg: PVisualGear;
  3102 var 
  2911      i: LongInt;
  3103     vg: PVisualGear;
  2912 begin
  3104     i: LongInt;
  2913     AllInactive:= false;
  3105 begin
  2914     Gear^.dX:= Gear^.dX;
  3106     AllInactive := false;
       
  3107     Gear^.dX := Gear^.dX;
  2915     doStepFallingGear(Gear);
  3108     doStepFallingGear(Gear);
  2916 //    CheckGearDrowning(Gear); // already checked for in doStepFallingGear
  3109     //    CheckGearDrowning(Gear); // already checked for in doStepFallingGear
  2917     CalcRotationDirAngle(Gear);
  3110     CalcRotationDirAngle(Gear);
  2918 
  3111 
  2919     if (Gear^.State and gstCollision) <> 0 then
  3112     if (Gear^.State and gstCollision) <> 0 then
  2920     begin
  3113     begin
  2921         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, EXPLPoisoned or EXPLNoGfx);
  3114         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, EXPLPoisoned or EXPLNoGfx);
  2922         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, EXPLPoisoned or EXPLNoGfx);
  3115         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, EXPLPoisoned or EXPLNoGfx);
  2923         PlaySound(sndEggBreak);
  3116         PlaySound(sndEggBreak);
  2924         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
  3117         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
  2925         vg:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
  3118         vg := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
  2926         if vg <> nil then vg^.Frame:= 2;
  3119         if vg <> nil then vg^.Frame := 2;
  2927 
  3120 
  2928     for i:= 10 downto 0 do begin
  3121         for i:= 10 downto 0 do
  2929         vg := AddVisualGear(hwRound(Gear^.X) - 3 + Random(6), hwRound(Gear^.Y) - 3 + Random(6), vgtDust);
  3122         begin
  2930         if vg <> nil then vg^.dX := vg^.dX + (Gear^.dX / 5);
  3123             vg := AddVisualGear(hwRound(Gear^.X) - 3 + Random(6), hwRound(Gear^.Y) - 3 + Random(6),
       
  3124                   vgtDust);
       
  3125             if vg <> nil then vg^.dX := vg^.dX + (Gear^.dX / 5);
  2931         end;
  3126         end;
  2932 
  3127 
  2933         DeleteGear(Gear);
  3128         DeleteGear(Gear);
  2934         exit
  3129         exit
  2935     end;
  3130     end;
  2936 end;
  3131 end;
  2937 
  3132 
  2938 ////////////////////////////////////////////////////////////////////////////////
  3133 ////////////////////////////////////////////////////////////////////////////////
  2939 procedure doPortalColorSwitch();
  3134 procedure doPortalColorSwitch();
  2940 var flags: LongWord;
  3135 var 
  2941 begin
  3136     flags: LongWord;
  2942    if (CurrentHedgehog <> nil)
  3137 begin
  2943         and (CurrentHedgehog^.Gear <> nil)
  3138     if (CurrentHedgehog <> nil)
  2944             and ((CurrentHedgehog^.Gear^.Message and gm_Switch) <> 0) then
  3139        and (CurrentHedgehog^.Gear <> nil)
  2945             With CurrentHedgehog^ do
  3140        and ((CurrentHedgehog^.Gear^.Message and gm_Switch) <> 0) then
  2946                 if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
  3141         With CurrentHedgehog^ do
  2947                     begin
  3142             if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
  2948                     CurrentHedgehog^.Gear^.Message:= CurrentHedgehog^.Gear^.Message and not gm_Switch;
  3143             begin
  2949 
  3144                 CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and not gm_Switch;
  2950                     flags:= Ammo^[CurSlot, CurAmmo].Timer and not 2;
  3145 
  2951                     if (flags and 1) = 0 then
  3146                 flags := Ammo^[CurSlot, CurAmmo].Timer and not 2;
  2952                         Ammo^[CurSlot, CurAmmo].Timer:= flags or 1
  3147                 if (flags and 1) = 0 then
  2953                     else
  3148                     Ammo^[CurSlot, CurAmmo].Timer := flags or 1
  2954                         Ammo^[CurSlot, CurAmmo].Timer:= flags and not 1;
  3149                 else
  2955                     end;
  3150                     Ammo^[CurSlot, CurAmmo].Timer := flags and not 1;
       
  3151             end;
  2956 end;
  3152 end;
  2957 
  3153 
  2958 procedure doStepPortal(Gear: PGear);
  3154 procedure doStepPortal(Gear: PGear);
  2959 var iterator, conPortal: PGear;
  3155 var 
       
  3156     iterator, conPortal: PGear;
  2960     s, acptRadius, cdxy: hwFloat;
  3157     s, acptRadius, cdxy: hwFloat;
  2961     noTrap, hasdxy: Boolean;
  3158     noTrap, hasdxy: Boolean;
  2962 begin
  3159 begin
  2963     doPortalColorSwitch();
  3160     doPortalColorSwitch();
  2964 
  3161 
  2965     // destroy portal if ground it was attached too is gone
  3162     // destroy portal if ground it was attached too is gone
  2966     if ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0)
  3163     if ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0)
  2967     or (Gear^.Timer < 1)
  3164        or (Gear^.Timer < 1)
  2968     or (hwRound(Gear^.Y) > cWaterLine) then
  3165        or (hwRound(Gear^.Y) > cWaterLine) then
  2969         begin
  3166     begin
  2970         deleteGear(Gear);
  3167         deleteGear(Gear);
  2971         EXIT;
  3168         EXIT;
  2972         end;
  3169     end;
  2973 
  3170 
  2974     if (TurnTimeLeft < 1)
  3171     if (TurnTimeLeft < 1)
  2975     or (Gear^.Health < 1) then
  3172        or (Gear^.Health < 1) then
  2976         dec(Gear^.Timer);
  3173         dec(Gear^.Timer);
  2977 
  3174 
  2978     if Gear^.Timer < 10000 then
  3175     if Gear^.Timer < 10000 then
  2979         gear^.RenderTimer:= true;
  3176         gear^.RenderTimer := true;
  2980 
  3177 
  2981     // abort if there is no other portal connected to this one
  3178     // abort if there is no other portal connected to this one
  2982     if (Gear^.IntersectGear = nil) then 
  3179     if (Gear^.IntersectGear = nil) then
  2983         exit;
  3180         exit;
  2984     if ((Gear^.IntersectGear^.Tag and 1) = 0) then // or if it's still moving;
  3181     if ((Gear^.IntersectGear^.Tag and 1) = 0) then // or if it's still moving;
  2985         exit;
  3182         exit;
  2986 
  3183 
  2987     conPortal:= Gear^.IntersectGear;
  3184     conPortal := Gear^.IntersectGear;
  2988 
  3185 
  2989     // check all gears for stuff to port through
  3186     // check all gears for stuff to port through
  2990     iterator:= nil;
  3187     iterator := nil;
  2991     while true do
  3188     while true do
  2992         begin
  3189     begin
  2993 
  3190 
  2994         if iterator = nil then
  3191         if iterator = nil then
  2995             iterator:= GearsList // start
  3192             iterator := GearsList // start
  2996         else
  3193         else
  2997             iterator:= iterator^.NextGear; // iterate through GearsList
  3194             iterator := iterator^.NextGear;
  2998         
  3195         // iterate through GearsList
       
  3196 
  2999         if iterator = nil then
  3197         if iterator = nil then
  3000             break; // end of list
  3198             break;
       
  3199         // end of list
  3001 
  3200 
  3002         // don't port portals or other gear that wouldn't make sense
  3201         // don't port portals or other gear that wouldn't make sense
  3003         if (iterator^.Kind = gtPortal)
  3202         if (iterator^.Kind = gtPortal) or (iterator^.Kind = gtRope) then
  3004         or (iterator^.Kind = gtRope) then
       
  3005             continue;
  3203             continue;
  3006         
  3204 
  3007         // don't port hogs on rope
  3205         // don't port hogs on rope
  3008         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
  3206         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
  3009             and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtRope) then
  3207            and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind =
  3010                 continue;
  3208            gtRope) then
       
  3209             continue;
  3011 
  3210 
  3012         if (iterator^.Radius > Gear^.Radius) then
  3211         if (iterator^.Radius > Gear^.Radius) then
  3013             continue; // sorry, you're too fat!
  3212             continue;
       
  3213         // sorry, you're too fat!
  3014 
  3214 
  3015         // this is the range we accept incoming gears in
  3215         // this is the range we accept incoming gears in
  3016         acptRadius:= Int2hwFloat(iterator^.Radius+Gear^.Radius);
  3216         acptRadius := Int2hwFloat(iterator^.Radius+Gear^.Radius);
  3017 
  3217 
  3018         if (iterator^.X < Gear^.X - acptRadius)
  3218         if (iterator^.X < Gear^.X - acptRadius)
  3019         or (iterator^.X > Gear^.X + acptRadius)
  3219            or (iterator^.X > Gear^.X + acptRadius)
  3020         or (iterator^.Y < Gear^.Y - acptRadius)
  3220            or (iterator^.Y < Gear^.Y - acptRadius)
  3021         or (iterator^.Y > Gear^.Y + acptRadius) then
  3221            or (iterator^.Y > Gear^.Y + acptRadius) then
  3022             continue; // too far away!
  3222             continue;
  3023 
  3223         // too far away!
  3024         hasdxy:= ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0));
  3224 
       
  3225         hasdxy := ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0));
  3025 
  3226 
  3026         if hasdxy and not (Gear^.dX*iterator^.dX + Gear^.dY*iterator^.dY).isNegative then
  3227         if hasdxy and not (Gear^.dX*iterator^.dX + Gear^.dY*iterator^.dY).isNegative then
  3027             continue; // won't port stuff that moves away from me!
  3228             continue;
       
  3229         // won't port stuff that moves away from me!
  3028 
  3230 
  3029         // wow! good candidate there, let's see if the distance really is small enough!
  3231         // wow! good candidate there, let's see if the distance really is small enough!
  3030         if (Distance(Gear^.X-iterator^.X,Gear^.Y-iterator^.Y) > acptRadius) then
  3232         if (Distance(Gear^.X-iterator^.X,Gear^.Y-iterator^.Y) > acptRadius) then
  3031             continue;
  3233             continue;
  3032 
  3234 
  3033         noTrap:= ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0)) // can't be entered from above
  3235         noTrap := ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0))
  3034             or ((conPortal^.dY.isNegative and not (conPortal^.dY.QWordValue = 0)))); // can't be left downwards; 
  3236                   // can't be entered from above
  3035  
  3237                   or ((conPortal^.dY.isNegative and not (conPortal^.dY.QWordValue = 0))));
       
  3238         // can't be left downwards; 
       
  3239 
  3036         // prevent getting stuck in a ground portal loop       
  3240         // prevent getting stuck in a ground portal loop       
  3037         if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then
  3241         if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then
  3038             continue;
  3242             continue;
  3039 
  3243 
  3040         iterator^.Active:= true;
  3244         iterator^.Active := true;
  3041         iterator^.State:= iterator^.State or gstMoving;
  3245         iterator^.State := iterator^.State or gstMoving;
  3042         DeleteCI(iterator);
  3246         DeleteCI(iterator);
  3043 
  3247 
  3044 // TODO: more accurate porting
  3248         // TODO: more accurate porting
  3045         cdxy:= Distance(conPortal^.dX, conPortal^.dY);
  3249         cdxy := Distance(conPortal^.dX, conPortal^.dY);
  3046         s:= (Int2hwFloat(Gear^.Radius)) / cdxy;
  3250         s := (Int2hwFloat(Gear^.Radius)) / cdxy;
  3047 
  3251 
  3048         iterator^.X:= conPortal^.X + s * conPortal^.dX;
  3252         iterator^.X := conPortal^.X + s * conPortal^.dX;
  3049         iterator^.Y:= conPortal^.Y + s * conPortal^.dY;
  3253         iterator^.Y := conPortal^.Y + s * conPortal^.dY;
  3050 
  3254 
  3051         s:= Distance(iterator^.dX, iterator^.dY) / cdxy;
  3255         s := Distance(iterator^.dX, iterator^.dY) / cdxy;
  3052 
  3256 
  3053         iterator^.dX:= s * conPortal^.dX;
  3257         iterator^.dX := s * conPortal^.dX;
  3054         iterator^.dY:= s * conPortal^.dY;
  3258         iterator^.dY := s * conPortal^.dY;
  3055 
  3259 
  3056         FollowGear:= iterator;
  3260         FollowGear := iterator;
  3057 
  3261 
  3058         s:= _0_2 + _0_008 * Gear^.Health;
  3262         s := _0_2 + _0_008 * Gear^.Health;
  3059         iterator^.dX:= s * iterator^.dX;
  3263         iterator^.dX := s * iterator^.dX;
  3060         iterator^.dY:= s * iterator^.dY;
  3264         iterator^.dY := s * iterator^.dY;
  3061         
  3265 
  3062         if Gear^.Health > 1 then
  3266         if Gear^.Health > 1 then
  3063             begin
  3267         begin
  3064             dec(Gear^.Health);
  3268             dec(Gear^.Health);
  3065             dec(iterator^.Health);
  3269             dec(iterator^.Health);
  3066             end;
  3270         end;
  3067 
  3271 
  3068         // breaks (some) loops
  3272         // breaks (some) loops
  3069         if Distance(iterator^.dX, iterator^.dY) > _0_96 then
  3273         if Distance(iterator^.dX, iterator^.dY) > _0_96 then
       
  3274         begin
       
  3275             iterator^.dX := iterator^.dX + signAs(cGravity * getRandom(1000),iterator^.dX);
       
  3276             iterator^.dY := iterator^.dY + signAs(cGravity * getRandom(1000),iterator^.dY);
       
  3277             s := _0_96 / Distance(iterator^.dX, iterator^.dY);
       
  3278             iterator^.dX := s * iterator^.dX;
       
  3279             iterator^.dY := s * iterator^.dX;
       
  3280         end;
       
  3281     end;
       
  3282 end;
       
  3283 
       
  3284 procedure doStepMovingPortal(Gear: PGear);
       
  3285 var 
       
  3286     x, y, tx, ty: LongInt;
       
  3287     //, bx, by, tangle: LongInt;
       
  3288     s, dx, dy: hwFloat;
       
  3289 
       
  3290 procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
       
  3291 var 
       
  3292     flags: LongWord;
       
  3293 begin
       
  3294     if CurrentHedgehog <> nil then
       
  3295         With CurrentHedgehog^ do
       
  3296             if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
  3070             begin
  3297             begin
  3071             iterator^.dX:= iterator^.dX + signAs(cGravity * getRandom(1000),iterator^.dX);
  3298                 flags := Ammo^[CurSlot, CurAmmo].Timer;
  3072             iterator^.dY:= iterator^.dY + signAs(cGravity * getRandom(1000),iterator^.dY);
  3299 
  3073             s:= _0_96 / Distance(iterator^.dX, iterator^.dY);
  3300                 if destroyGear xor ((oldPortal^.Tag and 2) = 0) then
  3074             iterator^.dX:= s * iterator^.dX;
  3301                     flags := flags or 1
  3075             iterator^.dY:= s * iterator^.dX;
  3302                 else
       
  3303                     flags := flags and not 1;
       
  3304 
       
  3305                 Ammo^[CurSlot, CurAmmo].Timer := flags and not 2;
       
  3306                 // make the ball visible
  3076             end;
  3307             end;
  3077         end;
  3308 
  3078 end;
  3309     if destroyGear then deleteGear(oldPortal);
  3079 
  3310 end;
  3080 procedure doStepMovingPortal(Gear: PGear);
  3311 
  3081 var x, y, tx, ty: LongInt;//, bx, by, tangle: LongInt;
  3312 begin
  3082     s, dx, dy: hwFloat;
  3313     doPortalColorSwitch();
  3083 
  3314 
  3084 procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
  3315     Gear^.X := Gear^.X + Gear^.dX;
  3085 var flags: LongWord;
  3316     Gear^.Y := Gear^.Y + Gear^.dY;
  3086 begin
  3317     x := hwRound(Gear^.X);
  3087 if CurrentHedgehog <> nil then
  3318     y := hwRound(Gear^.Y);
  3088     With CurrentHedgehog^ do
  3319     tx := 0;
  3089         if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
  3320     ty := 0;
  3090             begin
  3321     // avoid compiler hints
  3091             flags:= Ammo^[CurSlot, CurAmmo].Timer;
  3322 
  3092 
  3323     if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
  3093             if destroyGear xor ((oldPortal^.Tag and 2) = 0) then
  3324     begin
  3094                 flags:= flags or 1
  3325         if not calcSlopeTangent(Gear, x, y, tx, ty, 255)
  3095             else
  3326            or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
  3096                 flags:= flags and not 1;
  3327         begin
  3097 
       
  3098             Ammo^[CurSlot, CurAmmo].Timer:= flags and not 2; // make the ball visible
       
  3099             end;
       
  3100 
       
  3101 if destroyGear then deleteGear(oldPortal);
       
  3102 end;
       
  3103 
       
  3104 begin
       
  3105 doPortalColorSwitch();
       
  3106 
       
  3107 Gear^.X:= Gear^.X + Gear^.dX;
       
  3108 Gear^.Y:= Gear^.Y + Gear^.dY;
       
  3109 x:= hwRound(Gear^.X);
       
  3110 y:= hwRound(Gear^.Y);
       
  3111 tx:= 0; ty:= 0; // avoid compiler hints
       
  3112 
       
  3113 if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
       
  3114     begin
       
  3115     if not calcSlopeTangent(Gear, x, y, tx, ty, 255)
       
  3116         or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
       
  3117             begin
       
  3118             loadNewPortalBall(Gear, true);
  3328             loadNewPortalBall(Gear, true);
  3119             EXIT;
  3329             EXIT;
       
  3330         end;
       
  3331 
       
  3332         // making a normalized normal vector
       
  3333         s := _1/DistanceI(tx,ty);
       
  3334         dx := -s * ty;
       
  3335         dy :=  s * tx;
       
  3336 
       
  3337         // make sure the vector is pointing outwards
       
  3338         if not (Gear^.dX*dx + Gear^.dY*dy).isNegative then
       
  3339         begin
       
  3340             dx := -dx;
       
  3341             dy := -dy;
       
  3342         end;
       
  3343 
       
  3344         Gear^.dX := dx;
       
  3345         Gear^.dY := dy;
       
  3346 
       
  3347         Gear^.DirAngle := DxDy2Angle(-dy,dx);
       
  3348         if not Gear^.dX.isNegative then Gear^.DirAngle := 180-Gear^.DirAngle;
       
  3349 
       
  3350         if ((Gear^.IntersectGear = nil)
       
  3351            or (hwRound(Distance(Gear^.X - Gear^.IntersectGear^.X,Gear^.Y-Gear^.IntersectGear^.Y)) >=
       
  3352            Gear^.Radius*2))
       
  3353             then
       
  3354         begin
       
  3355             loadNewPortalBall(Gear, false);
       
  3356             inc(Gear^.Tag);
       
  3357             Gear^.doStep := @doStepPortal;
       
  3358         end
       
  3359         else
       
  3360             loadNewPortalBall(Gear, true);
       
  3361     end
       
  3362     else if (y > cWaterLine) or (y < -LAND_WIDTH)
       
  3363             or (x > 2*LAND_WIDTH) or (x < -LAND_WIDTH) then
       
  3364              loadNewPortalBall(Gear, true);
       
  3365 end;
       
  3366 
       
  3367 procedure doStepPortalShot(newPortal: PGear);
       
  3368 var 
       
  3369     iterator: PGear;
       
  3370 begin
       
  3371     newPortal^.IntersectGear := nil;
       
  3372 
       
  3373     if CurrentHedgehog <> nil then
       
  3374         With CurrentHedgehog^ do
       
  3375         begin
       
  3376             // make portal gun look unloaded
       
  3377             Ammo^[CurSlot, CurAmmo].Timer := Ammo^[CurSlot, CurAmmo].Timer or 2;
       
  3378 
       
  3379             // set portal to the currently chosen color
       
  3380             if ((Ammo^[CurSlot, CurAmmo].Timer and 1) <> 0) then
       
  3381                 newPortal^.Tag := newPortal^.Tag or 2;
       
  3382 
       
  3383             iterator := GearsList;
       
  3384             while iterator <> nil do
       
  3385             begin
       
  3386                 if (iterator^.Kind = gtPortal) then
       
  3387                     if (iterator <> newPortal) then
       
  3388                     begin
       
  3389                         if (iterator^.Tag and 2) = (newPortal^.Tag and 2) then
       
  3390                         begin
       
  3391                             iterator := iterator^.PrevGear;
       
  3392                             deleteGear(iterator^.NextGear);
       
  3393                             continue;
       
  3394                         end
       
  3395                         else
       
  3396                         begin
       
  3397                             // link portals with each other
       
  3398                             newPortal^.IntersectGear := iterator;
       
  3399                             iterator^.IntersectGear := newPortal;
       
  3400                             iterator^.Health := newPortal^.Health;
       
  3401                         end;
       
  3402                     end;
       
  3403                 iterator := iterator^.NextGear
  3120             end;
  3404             end;
  3121     
  3405         end;
  3122     // making a normalized normal vector
  3406     newPortal^.doStep := @doStepMovingPortal;
  3123     s:= _1/DistanceI(tx,ty);
  3407 end;
  3124     dx:= -s * ty;
  3408 
  3125     dy:=  s * tx;
  3409 procedure doStepPiano(Gear: PGear);
  3126 
  3410 var 
  3127     // make sure the vector is pointing outwards
  3411     r0, r1: LongInt;
  3128     if not (Gear^.dX*dx + Gear^.dY*dy).isNegative then
  3412 begin
  3129         begin
  3413     AllInactive := false;
  3130         dx:= -dx;
  3414     if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and ((CurrentHedgehog^.Gear^.
  3131         dy:= -dy;
  3415        Message and gm_Slot) <> 0) then
  3132         end;
  3416     begin
  3133 
  3417         case CurrentHedgehog^.Gear^.MsgParam of 
  3134     Gear^.dX:= dx;
  3418             0: PlaySound(sndPiano0);
  3135     Gear^.dY:= dy;
  3419             1: PlaySound(sndPiano1);
  3136 
  3420             2: PlaySound(sndPiano2);
  3137     Gear^.DirAngle:= DxDy2Angle(-dy,dx);
  3421             3: PlaySound(sndPiano3);
  3138     if not Gear^.dX.isNegative then Gear^.DirAngle:= 180-Gear^.DirAngle;
  3422             4: PlaySound(sndPiano4);
  3139 
  3423             5: PlaySound(sndPiano5);
  3140     if ((Gear^.IntersectGear = nil)
  3424             6: PlaySound(sndPiano6);
  3141     or (hwRound(Distance(Gear^.X - Gear^.IntersectGear^.X,Gear^.Y-Gear^.IntersectGear^.Y)) >= Gear^.Radius*2)) 
  3425             7: PlaySound(sndPiano7);
  3142     then
  3426             else PlaySound(sndPiano8);
  3143         begin
  3427         end;
  3144         loadNewPortalBall(Gear, false);
  3428         CurrentHedgehog^.Gear^.MsgParam := 0;
  3145         inc(Gear^.Tag);
  3429         CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and not gm_Slot;
  3146         Gear^.doStep:= @doStepPortal;
  3430     end;
       
  3431 
       
  3432     if ((Gear^.Pos = 3) and ((GameFlags and gfSolidLand) <> 0)) or (Gear^.Pos = 20) then
       
  3433         // bounce up to 20 times (3 times on gameflagged solid land) before dropping past landscape
       
  3434     begin
       
  3435         Gear^.dY := Gear^.dY + cGravity * 3;
       
  3436         Gear^.Y := Gear^.Y + Gear^.dY;
       
  3437         CheckGearDrowning(Gear);
       
  3438         if (Gear^.State and gstDrowning) <> 0 then
       
  3439         begin
       
  3440             if CurrentHedgehog^.Gear <> nil then
       
  3441             begin
       
  3442                 // Drown the hedgehog.  Could also just delete it, but hey, this gets a caption
       
  3443                 CurrentHedgehog^.Gear^.Active := true;
       
  3444                 CurrentHedgehog^.Gear^.X := Gear^.X;
       
  3445                 CurrentHedgehog^.Gear^.Y := int2hwFloat(cWaterLine+cVisibleWater)+_128;
       
  3446                 CurrentHedgehog^.Unplaced := false
       
  3447             end;
       
  3448             ResumeMusic
       
  3449         end;
       
  3450         exit
       
  3451     end;
       
  3452 
       
  3453     doStepFallingGear(Gear);
       
  3454 
       
  3455     if (Gear^.State and gstDrowning) <> 0 then
       
  3456     begin
       
  3457         if CurrentHedgehog^.Gear <> nil then
       
  3458         begin
       
  3459             // Drown the hedgehog.  Could also just delete it, but hey, this gets a caption
       
  3460             CurrentHedgehog^.Gear^.Active := true;
       
  3461             CurrentHedgehog^.Gear^.X := Gear^.X;
       
  3462             CurrentHedgehog^.Gear^.Y := int2hwFloat(cWaterLine+cVisibleWater)+_128;
       
  3463             CurrentHedgehog^.Unplaced := false
       
  3464         end;
       
  3465         ResumeMusic
       
  3466     end
       
  3467     else if (Gear^.State and gstCollision) <> 0 then
       
  3468         begin
       
  3469             r0 := GetRandom(21);
       
  3470             r1 := GetRandom(21);
       
  3471             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 80 + r0, EXPLAutoSound);
       
  3472             doMakeExplosion(hwRound(Gear^.X) - 30 - r0, hwRound(Gear^.Y) + 40, 40 + r1,
       
  3473             EXPLAutoSound);
       
  3474             doMakeExplosion(hwRound(Gear^.X) + 30 + r1, hwRound(Gear^.Y) + 40, 40 + r0,
       
  3475             EXPLAutoSound);
       
  3476             Gear^.dY := -_1;
       
  3477             Gear^.Pos := Gear^.Pos + 1;
  3147         end
  3478         end
  3148     else
  3479     else
  3149         loadNewPortalBall(Gear, true);
  3480         Gear^.dY := Gear^.dY + cGravity * 2;
  3150     end
  3481     // let it fall faster so itdoesn't take too long for the whole attack
  3151 else if (y > cWaterLine) or (y < -LAND_WIDTH)
       
  3152      or (x > 2*LAND_WIDTH) or (x < -LAND_WIDTH) then
       
  3153         loadNewPortalBall(Gear, true);
       
  3154 end;
       
  3155 
       
  3156 procedure doStepPortalShot(newPortal: PGear);
       
  3157 var iterator: PGear;
       
  3158 begin
       
  3159 newPortal^.IntersectGear:= nil;
       
  3160 
       
  3161 if CurrentHedgehog <> nil then
       
  3162     With CurrentHedgehog^ do
       
  3163     begin
       
  3164     // make portal gun look unloaded
       
  3165     Ammo^[CurSlot, CurAmmo].Timer:= Ammo^[CurSlot, CurAmmo].Timer or 2;
       
  3166 
       
  3167     // set portal to the currently chosen color
       
  3168     if ((Ammo^[CurSlot, CurAmmo].Timer and 1) <> 0) then
       
  3169         newPortal^.Tag:= newPortal^.Tag or 2;
       
  3170 
       
  3171     iterator:= GearsList;
       
  3172     while iterator <> nil do
       
  3173         begin
       
  3174         if (iterator^.Kind = gtPortal) then
       
  3175             if (iterator <> newPortal) then
       
  3176                 begin
       
  3177                 if (iterator^.Tag and 2) = (newPortal^.Tag and 2) then
       
  3178                     begin
       
  3179                     iterator:= iterator^.PrevGear;
       
  3180                     deleteGear(iterator^.NextGear);
       
  3181                     continue;
       
  3182                     end
       
  3183                 else
       
  3184                     begin // link portals with each other
       
  3185                     newPortal^.IntersectGear:= iterator;
       
  3186                     iterator^.IntersectGear:= newPortal;
       
  3187                     iterator^.Health:= newPortal^.Health;
       
  3188                     end;
       
  3189                 end;
       
  3190         iterator:= iterator^.NextGear
       
  3191         end;
       
  3192     end;
       
  3193 newPortal^.doStep:= @doStepMovingPortal;
       
  3194 end;
       
  3195 
       
  3196 procedure doStepPiano(Gear: PGear);
       
  3197 var r0, r1: LongInt;
       
  3198 begin
       
  3199 AllInactive:= false;
       
  3200 if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and ((CurrentHedgehog^.Gear^.Message and gm_Slot) <> 0) then
       
  3201     begin
       
  3202     case CurrentHedgehog^.Gear^.MsgParam of
       
  3203         0: PlaySound(sndPiano0);
       
  3204         1: PlaySound(sndPiano1);
       
  3205         2: PlaySound(sndPiano2);
       
  3206         3: PlaySound(sndPiano3);
       
  3207         4: PlaySound(sndPiano4);
       
  3208         5: PlaySound(sndPiano5);
       
  3209         6: PlaySound(sndPiano6);
       
  3210         7: PlaySound(sndPiano7);
       
  3211         else PlaySound(sndPiano8);
       
  3212         end;
       
  3213     CurrentHedgehog^.Gear^.MsgParam:= 0;
       
  3214     CurrentHedgehog^.Gear^.Message:= CurrentHedgehog^.Gear^.Message and not gm_Slot;
       
  3215     end;
       
  3216 
       
  3217 if ((Gear^.Pos = 3) and ((GameFlags and gfSolidLand) <> 0)) or (Gear^.Pos = 20) then // bounce up to 20 times (3 times on gameflagged solid land) before dropping past landscape
       
  3218     begin
       
  3219     Gear^.dY:= Gear^.dY + cGravity * 3;
       
  3220     Gear^.Y:= Gear^.Y + Gear^.dY;
       
  3221     CheckGearDrowning(Gear);
       
  3222     if (Gear^.State and gstDrowning) <> 0 then
       
  3223         begin
       
  3224         if CurrentHedgehog^.Gear <> nil then
       
  3225             begin
       
  3226             // Drown the hedgehog.  Could also just delete it, but hey, this gets a caption
       
  3227             CurrentHedgehog^.Gear^.Active:= true;
       
  3228             CurrentHedgehog^.Gear^.X:= Gear^.X;
       
  3229             CurrentHedgehog^.Gear^.Y:=int2hwFloat(cWaterLine+cVisibleWater)+_128;
       
  3230             CurrentHedgehog^.Unplaced:= false
       
  3231             end;
       
  3232         ResumeMusic
       
  3233         end;
       
  3234     exit
       
  3235     end;
       
  3236 
       
  3237 doStepFallingGear(Gear);
       
  3238 
       
  3239 if (Gear^.State and gstDrowning) <> 0 then
       
  3240     begin
       
  3241     if CurrentHedgehog^.Gear <> nil then
       
  3242         begin
       
  3243         // Drown the hedgehog.  Could also just delete it, but hey, this gets a caption
       
  3244         CurrentHedgehog^.Gear^.Active:= true;
       
  3245         CurrentHedgehog^.Gear^.X:= Gear^.X;
       
  3246         CurrentHedgehog^.Gear^.Y:=int2hwFloat(cWaterLine+cVisibleWater)+_128;
       
  3247         CurrentHedgehog^.Unplaced:= false
       
  3248         end;
       
  3249     ResumeMusic
       
  3250     end
       
  3251 else if (Gear^.State and gstCollision) <> 0 then
       
  3252     begin
       
  3253     r0:= GetRandom(21);
       
  3254     r1:= GetRandom(21);
       
  3255     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 80 + r0, EXPLAutoSound);
       
  3256     doMakeExplosion(hwRound(Gear^.X) - 30 - r0, hwRound(Gear^.Y) + 40, 40 + r1, EXPLAutoSound);
       
  3257     doMakeExplosion(hwRound(Gear^.X) + 30 + r1, hwRound(Gear^.Y) + 40, 40 + r0, EXPLAutoSound);
       
  3258     Gear^.dY:= -_1;
       
  3259     Gear^.Pos:= Gear^.Pos + 1;
       
  3260     end
       
  3261 else
       
  3262     Gear^.dY:= Gear^.dY + cGravity * 2; // let it fall faster so itdoesn't take too long for the whole attack
       
  3263 end;
  3482 end;
  3264 
  3483 
  3265 
  3484 
  3266 ////////////////////////////////////////////////////////////////////////////////
  3485 ////////////////////////////////////////////////////////////////////////////////
  3267 procedure doStepSineGunShotWork(Gear: PGear);
  3486 procedure doStepSineGunShotWork(Gear: PGear);
  3268 var x, y, rX, rY, t, tmp, initHealth: LongInt;
  3487 var 
       
  3488     x, y, rX, rY, t, tmp, initHealth: LongInt;
  3269     oX, oY, ldX, ldY, sdX, sdY, sine, lx, ly, amp: hwFloat;
  3489     oX, oY, ldX, ldY, sdX, sdY, sine, lx, ly, amp: hwFloat;
  3270     justCollided: boolean;
  3490     justCollided: boolean;
  3271 begin
  3491 begin
  3272 AllInactive:= false;
  3492     AllInactive := false;
  3273 initHealth:= Gear^.Health;
  3493     initHealth := Gear^.Health;
  3274 lX:= Gear^.X;
  3494     lX := Gear^.X;
  3275 lY:= Gear^.Y;
  3495     lY := Gear^.Y;
  3276 ldX:= Gear^.dX;
  3496     ldX := Gear^.dX;
  3277 ldY:= Gear^.dY;
  3497     ldY := Gear^.dY;
  3278 sdy:= _0_5/Distance(Gear^.dX,Gear^.dY);
  3498     sdy := _0_5/Distance(Gear^.dX,Gear^.dY);
  3279 ldX:= ldX * sdy;
  3499     ldX := ldX * sdy;
  3280 ldY:= ldY * sdy;
  3500     ldY := ldY * sdy;
  3281 sdY:= hwAbs(ldX) + hwAbs(ldY);
  3501     sdY := hwAbs(ldX) + hwAbs(ldY);
  3282 sdX:= _1 - hwAbs(ldX/sdY);
  3502     sdX := _1 - hwAbs(ldX/sdY);
  3283 sdY:= _1 - hwAbs(ldY/sdY);
  3503     sdY := _1 - hwAbs(ldY/sdY);
  3284 if (ldX.isNegative = ldY.isNegative) then sdY:= -sdY;
  3504     if (ldX.isNegative = ldY.isNegative) then sdY := -sdY;
  3285 
  3505 
  3286 // initial angle depends on current GameTicks
  3506     // initial angle depends on current GameTicks
  3287 t:= GameTicks mod 4096;
  3507     t := GameTicks mod 4096;
  3288 
  3508 
  3289 
  3509 
  3290 // used for a work-around detection of area that is within land array, but outside borders
  3510     // used for a work-around detection of area that is within land array, but outside borders
  3291 justCollided:= false;
  3511     justCollided := false;
  3292 
  3512 
  3293 repeat
  3513     repeat
  3294     lX:= lX + ldX;
  3514         lX := lX + ldX;
  3295     lY:= lY + ldY;
  3515         lY := lY + ldY;
  3296     oX:= Gear^.X;
  3516         oX := Gear^.X;
  3297     oY:= Gear^.Y;
  3517         oY := Gear^.Y;
  3298     rX:= hwRound(oX);
  3518         rX := hwRound(oX);
  3299     rY:= hwRound(oY);
  3519         rY := hwRound(oY);
  3300     tmp:= t mod 4096;
  3520         tmp := t mod 4096;
  3301     amp:= _128 * (_1 - hwSqr(int2hwFloat(Gear^.Health)/initHealth));
  3521         amp := _128 * (_1 - hwSqr(int2hwFloat(Gear^.Health)/initHealth));
  3302     sine:= amp * AngleSin(tmp mod 2048);
  3522         sine := amp * AngleSin(tmp mod 2048);
  3303     sine.isNegative:= (tmp < 2048);
  3523         sine.isNegative := (tmp < 2048);
  3304     inc(t,Gear^.Health div 313);
  3524         inc(t,Gear^.Health div 313);
  3305     Gear^.X:= lX + (sine * sdX);
  3525         Gear^.X := lX + (sine * sdX);
  3306     Gear^.Y:= ly + (sine * sdY);
  3526         Gear^.Y := ly + (sine * sdY);
  3307     Gear^.dX:= Gear^.X - oX;
  3527         Gear^.dX := Gear^.X - oX;
  3308     Gear^.dY:= Gear^.Y - oY;
  3528         Gear^.dY := Gear^.Y - oY;
  3309     
  3529 
  3310     x:= hwRound(Gear^.X);
  3530         x := hwRound(Gear^.X);
  3311     y:= hwRound(Gear^.Y);
  3531         y := hwRound(Gear^.Y);
  3312     
  3532 
  3313     // if borders are on, stop outside land array
  3533         // if borders are on, stop outside land array
  3314     if hasBorder and (((x and LAND_WIDTH_MASK) <> 0) or ((y and LAND_HEIGHT_MASK) <> 0)) then
  3534         if hasBorder and (((x and LAND_WIDTH_MASK) <> 0) or ((y and LAND_HEIGHT_MASK) <> 0)) then
       
  3535         begin
       
  3536             Gear^.Damage := 0;
       
  3537             Gear^.Health := 0;
       
  3538         end
       
  3539         else
       
  3540         begin
       
  3541             if (rY <= cWaterLine) or (y <= cWaterLine) then
  3315             begin
  3542             begin
  3316             Gear^.Damage:= 0;
  3543                 if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0)
  3317             Gear^.Health:= 0;
  3544                    and (Land[y, x] <> 0) then
       
  3545                 begin
       
  3546                     if justCollided then
       
  3547                     begin
       
  3548                         Gear^.Damage := 0;
       
  3549                         Gear^.Health := 0;
       
  3550                     end
       
  3551                     else
       
  3552                     begin
       
  3553                         inc(Gear^.Damage,3);
       
  3554                         justCollided := true;
       
  3555                     end;
       
  3556                 end
       
  3557                 else
       
  3558                     justCollided := false;
       
  3559 
       
  3560                 // kick nearby hogs, dig tunnel and add some fire
       
  3561                 // if at least 5 collisions occured
       
  3562                 if Gear^.Damage > 0 then
       
  3563                 begin
       
  3564                     DrawExplosion(rX,rY,Gear^.Radius);
       
  3565 
       
  3566                     // kick nearby hogs
       
  3567                     AmmoShove(Gear, 35, 50);
       
  3568 
       
  3569                     dec(Gear^.Health, Gear^.Damage);
       
  3570                     Gear^.Damage := 0;
       
  3571 
       
  3572                     // add some fire to the tunnel
       
  3573                     if getRandom(6) = 0 then
       
  3574                         AddGear(x - Gear^.Radius + LongInt(getRandom(2 * Gear^.Radius)), y -
       
  3575                         getRandom(Gear^.Radius + 1), gtFlame, gsttmpFlag, _0, _0, 0);
       
  3576                 end;
       
  3577 
       
  3578                 if getRandom(100) = 0 then
       
  3579                     AddVisualGear(x, y, vgtSmokeTrace); 
  3318             end
  3580             end
  3319     else
  3581             else dec(Gear^.Health, 5); // if underwater get additional damage
  3320         begin
  3582         end;
  3321         if (rY <= cWaterLine) or (y <= cWaterLine) then
  3583 
  3322             begin
  3584         dec(Gear^.Health);
  3323             if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0)
  3585 
  3324                 and (Land[y, x] <> 0) then
  3586         // decrease bullet size towards the end
  3325                     begin
  3587         if (Gear^.Radius > 4) then begin
  3326                     if justCollided then
  3588             if (Gear^.Health <= (initHealth div 3)) then dec(Gear^.Radius) end
  3327                         begin
  3589         else if (Gear^.Radius > 3) then begin
  3328                         Gear^.Damage:= 0;
  3590             if (Gear^.Health <= (initHealth div 4)) then dec(Gear^.Radius) end
  3329                         Gear^.Health:= 0;
  3591         else if (Gear^.Radius > 2) then begin
  3330                         end
  3592             if (Gear^.Health <= (initHealth div 5)) then dec(Gear^.Radius) end
  3331                     else
  3593         else if (Gear^.Radius > 1) then begin
  3332                         begin
  3594             if (Gear^.Health <= (initHealth div 6)) then dec(Gear^.Radius) end;
  3333                         inc(Gear^.Damage,3);
  3595 
  3334                         justCollided:= true;
  3596     until (Gear^.Health <= 0);
  3335                         end;
  3597 
  3336                     end
  3598     DeleteGear(Gear);
  3337                 else
  3599     AfterAttack;
  3338                     justCollided:= false;
       
  3339 
       
  3340         // kick nearby hogs, dig tunnel and add some fire
       
  3341         // if at least 5 collisions occured
       
  3342         if Gear^.Damage > 0 then
       
  3343             begin
       
  3344             DrawExplosion(rX,rY,Gear^.Radius);
       
  3345             
       
  3346             // kick nearby hogs
       
  3347             AmmoShove(Gear, 35, 50);
       
  3348             
       
  3349             dec(Gear^.Health, Gear^.Damage);
       
  3350             Gear^.Damage:= 0;
       
  3351             
       
  3352             // add some fire to the tunnel
       
  3353             if getRandom(6) = 0 then
       
  3354                 AddGear(x - Gear^.Radius + LongInt(getRandom(2 * Gear^.Radius)), y - getRandom(Gear^.Radius + 1), gtFlame, gsttmpFlag, _0, _0, 0);
       
  3355             end;
       
  3356 
       
  3357         if getRandom(100) = 0 then
       
  3358             AddVisualGear(x, y, vgtSmokeTrace);
       
  3359         
       
  3360         end
       
  3361         // if underwater get additional damage
       
  3362         else dec(Gear^.Health, 5);
       
  3363     end;
       
  3364 
       
  3365     dec(Gear^.Health);
       
  3366     
       
  3367     // decrease bullet size towards the end
       
  3368     if (Gear^.Radius > 4) then begin 
       
  3369         if (Gear^.Health <= (initHealth div 3)) then dec(Gear^.Radius) end
       
  3370     else if (Gear^.Radius > 3) then begin
       
  3371         if (Gear^.Health <= (initHealth div 4)) then dec(Gear^.Radius) end
       
  3372     else if (Gear^.Radius > 2) then begin
       
  3373         if (Gear^.Health <= (initHealth div 5)) then dec(Gear^.Radius) end
       
  3374     else if (Gear^.Radius > 1) then begin
       
  3375         if (Gear^.Health <= (initHealth div 6)) then dec(Gear^.Radius) end;
       
  3376 
       
  3377 until (Gear^.Health <= 0);
       
  3378 
       
  3379 DeleteGear(Gear);
       
  3380 AfterAttack;
       
  3381 end;
  3600 end;
  3382 
  3601 
  3383 procedure doStepSineGunShot(Gear: PGear);
  3602 procedure doStepSineGunShot(Gear: PGear);
  3384 var HHGear: PGear;
  3603 var 
  3385 begin
  3604     HHGear: PGear;
  3386 PlaySound(sndSineGun);
  3605 begin
  3387 
  3606     PlaySound(sndSineGun); 
  3388 
  3607 
  3389 // push the shooting Hedgehog back
  3608     // push the shooting Hedgehog back
  3390 HHGear:= CurrentHedgehog^.Gear;
  3609     HHGear := CurrentHedgehog^.Gear;
  3391 Gear^.dX.isNegative:= not Gear^.dX.isNegative;
  3610     Gear^.dX.isNegative := not Gear^.dX.isNegative;
  3392 Gear^.dY.isNegative:= not Gear^.dY.isNegative;
  3611     Gear^.dY.isNegative := not Gear^.dY.isNegative;
  3393 HHGear^.dX:= Gear^.dX;
  3612     HHGear^.dX := Gear^.dX;
  3394 HHGear^.dY:= Gear^.dY;
  3613     HHGear^.dY := Gear^.dY;
  3395 AmmoShove(Gear, 0, 80);
  3614     AmmoShove(Gear, 0, 80);
  3396 Gear^.dX.isNegative:= not Gear^.dX.isNegative;
  3615     Gear^.dX.isNegative := not Gear^.dX.isNegative;
  3397 Gear^.dY.isNegative:= not Gear^.dY.isNegative;
  3616     Gear^.dY.isNegative := not Gear^.dY.isNegative;
  3398 
  3617 
  3399 Gear^.doStep:= @doStepSineGunShotWork
  3618     Gear^.doStep := @doStepSineGunShotWork; 
  3400 
  3619 end;
  3401 end;