hedgewars/VGSHandlers.inc
branchwebgl
changeset 9521 8054d9d775fd
parent 9282 92af50454cf2
parent 9519 b8b5c82eb61b
child 9950 2759212a27de
equal deleted inserted replaced
9282:92af50454cf2 9521:8054d9d775fd
     1 (*
       
     2  * Hedgewars, a free turn based strategy game
       
     3  * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; version 2 of the License
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    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
       
    17  *)
       
    18 
       
    19 (*
       
    20  * This file contains the step handlers for visual gears.
       
    21  *
       
    22  * Since the effects of visual gears do not affect the course of the game,
       
    23  * no "synchronization" between players is required.
       
    24  * => The usage of safe functions or data types (e.g. GetRandom() or hwFloat)
       
    25  * is usually not necessary and therefore undesirable.
       
    26  *)
       
    27 
       
    28 procedure doStepFlake(Gear: PVisualGear; Steps: Longword);
       
    29 var sign: real;
       
    30     moved: boolean;
       
    31 begin
       
    32 if vobCount = 0 then exit;
       
    33 
       
    34 sign:= 1;
       
    35 with Gear^ do
       
    36     begin
       
    37     inc(FrameTicks, Steps);
       
    38     if not SuddenDeathDmg and (FrameTicks > vobFrameTicks) then
       
    39         begin
       
    40         dec(FrameTicks, vobFrameTicks);
       
    41         inc(Frame);
       
    42         if Frame = vobFramesCount then
       
    43             Frame:= 0
       
    44         end
       
    45     else if SuddenDeathDmg and (FrameTicks > vobSDFrameTicks) then
       
    46         begin
       
    47         dec(FrameTicks, vobSDFrameTicks);
       
    48         inc(Frame);
       
    49         if Frame = vobSDFramesCount then
       
    50             Frame:= 0
       
    51         end;
       
    52     X:= X + (cWindSpeedf * 400 + dX + tdX) * Steps * Gear^.Scale;
       
    53     if SuddenDeathDmg then
       
    54         Y:= Y + (dY + tdY + cGravityf * vobSDFallSpeed) * Steps * Gear^.Scale
       
    55     else
       
    56         Y:= Y + (dY + tdY + cGravityf * vobFallSpeed) * Steps * Gear^.Scale;
       
    57     Angle:= Angle + dAngle * Steps;
       
    58     if Angle > 360 then
       
    59         Angle:= Angle - 360
       
    60     else
       
    61         if Angle < - 360 then
       
    62             Angle:= Angle + 360;
       
    63 
       
    64 
       
    65     if (round(X) >= cLeftScreenBorder)
       
    66     and (round(X) <= cRightScreenBorder)
       
    67     and (round(Y) - 75 <= LAND_HEIGHT)
       
    68     and (Timer > 0) and (Timer-Steps > 0) then
       
    69         begin
       
    70         if tdX > 0 then
       
    71             sign := 1
       
    72         else
       
    73             sign:= -1;
       
    74         tdX:= tdX - 0.005*Steps*sign;
       
    75         if ((sign < 0) and (tdX > 0)) or ((sign > 0) and (tdX < 0)) then
       
    76             tdX:= 0;
       
    77         if tdX > 0 then
       
    78             sign := 1
       
    79         else
       
    80             sign:= -1;
       
    81         tdY:= tdY - 0.005*Steps*sign;
       
    82         if ((sign < 0) and (tdY > 0)) or ((sign > 0) and (tdY < 0)) then
       
    83             tdY:= 0;
       
    84         dec(Timer, Steps)
       
    85         end
       
    86     else
       
    87         begin
       
    88         moved:= false;
       
    89         if round(X) < cLeftScreenBorder then
       
    90             begin
       
    91             X:= X + cScreenSpace;
       
    92             moved:= true
       
    93             end
       
    94         else
       
    95             if round(X) > cRightScreenBorder then
       
    96                 begin
       
    97                 X:= X - cScreenSpace;
       
    98                 moved:= true
       
    99                 end;
       
   100             // if round(Y) < (LAND_HEIGHT - 1024 - 75) then Y:= Y + 25.0; // For if flag is set for flakes rising upwards?
       
   101         if (Gear^.Layer = 2) and (round(Y) - 225 > LAND_HEIGHT) then
       
   102             begin
       
   103             X:= cLeftScreenBorder + random(cScreenSpace);
       
   104             Y:= Y - (1024 + 250 + random(50)); // TODO - configure in theme (jellies for example could use limited range)
       
   105             moved:= true
       
   106             end
       
   107         else if (Gear^.Layer <> 2) and (round(Y) + 50 > LAND_HEIGHT) then
       
   108             begin
       
   109             X:= cLeftScreenBorder + random(cScreenSpace);
       
   110             Y:= Y - (1024 + random(25));
       
   111             moved:= true
       
   112             end;
       
   113         if moved then
       
   114             begin
       
   115             Angle:= random(360);
       
   116             dx:= 0.0000038654705 * random(10000);
       
   117             dy:= 0.000003506096 * random(7000);
       
   118             if random(2) = 0 then dx := -dx
       
   119             end;
       
   120         Timer:= 0;
       
   121         tdX:= 0;
       
   122         tdY:= 0
       
   123         end;
       
   124     end;
       
   125 
       
   126 end;
       
   127 
       
   128 ////////////////////////////////////////////////////////////////////////////////
       
   129 procedure doStepBeeTrace(Gear: PVisualGear; Steps: Longword);
       
   130 begin
       
   131 if Gear^.FrameTicks > Steps then
       
   132     dec(Gear^.FrameTicks, Steps)
       
   133 else
       
   134     DeleteVisualGear(Gear);
       
   135 end;
       
   136 
       
   137 ////////////////////////////////////////////////////////////////////////////////
       
   138 procedure doStepCloud(Gear: PVisualGear; Steps: Longword);
       
   139 var s: Longword;
       
   140     t: real;
       
   141 begin
       
   142 Gear^.X:= Gear^.X + (cWindSpeedf * 750 * Gear^.dX * Gear^.Scale) * Steps;
       
   143 
       
   144 // up-and-down-bounce magic
       
   145 s := (GameTicks + Gear^.Timer) mod 4096;
       
   146 t := 8 * Gear^.Scale * hwFloat2Float(AngleSin(s mod 2048));
       
   147 if (s < 2048) then t := -t;
       
   148 
       
   149 Gear^.Y := LAND_HEIGHT - 1184 + LongInt(Gear^.Timer mod 8) + t;
       
   150 
       
   151 if round(Gear^.X) < cLeftScreenBorder then
       
   152     Gear^.X:= Gear^.X + cScreenSpace
       
   153 else
       
   154     if round(Gear^.X) > cRightScreenBorder then
       
   155         Gear^.X:= Gear^.X - cScreenSpace
       
   156 end;
       
   157 
       
   158 ////////////////////////////////////////////////////////////////////////////////
       
   159 procedure doStepExpl(Gear: PVisualGear; Steps: Longword);
       
   160 var s: LongInt;
       
   161 begin
       
   162 s:= min(Steps, cExplFrameTicks);
       
   163 
       
   164 Gear^.X:= Gear^.X + Gear^.dX * s;
       
   165 Gear^.Y:= Gear^.Y + Gear^.dY * s;
       
   166 //Gear^.dY:= Gear^.dY + cGravityf;
       
   167 
       
   168 if Gear^.FrameTicks <= Steps then
       
   169     if Gear^.Frame = 0 then
       
   170         DeleteVisualGear(Gear)
       
   171     else
       
   172         begin
       
   173         dec(Gear^.Frame);
       
   174         Gear^.FrameTicks:= cExplFrameTicks
       
   175         end
       
   176     else dec(Gear^.FrameTicks, Steps)
       
   177 end;
       
   178 
       
   179 ////////////////////////////////////////////////////////////////////////////////
       
   180 procedure doStepNote(Gear: PVisualGear; Steps: Longword);
       
   181 begin
       
   182 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   183 
       
   184 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   185 Gear^.dY:= Gear^.dY + cGravityf * Steps / 2;
       
   186 
       
   187 Gear^.Angle:= Gear^.Angle + (Gear^.Frame + 1) * Steps / 10;
       
   188 while Gear^.Angle > cMaxAngle do
       
   189     Gear^.Angle:= Gear^.Angle - cMaxAngle;
       
   190 
       
   191 if Gear^.FrameTicks <= Steps then
       
   192     DeleteVisualGear(Gear)
       
   193 else
       
   194     dec(Gear^.FrameTicks, Steps)
       
   195 end;
       
   196 
       
   197 ////////////////////////////////////////////////////////////////////////////////
       
   198 procedure doStepLineTrail(Gear: PVisualGear; Steps: Longword);
       
   199 begin
       
   200 {$IFNDEF PAS2C}
       
   201 Steps := Steps;
       
   202 {$ENDIF}
       
   203 if Gear^.Timer <= Steps then
       
   204     DeleteVisualGear(Gear)
       
   205 else
       
   206     dec(Gear^.Timer, Steps)
       
   207 end;
       
   208 
       
   209 ////////////////////////////////////////////////////////////////////////////////
       
   210 procedure doStepEgg(Gear: PVisualGear; Steps: Longword);
       
   211 begin
       
   212 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   213 
       
   214 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   215 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   216 
       
   217 Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
       
   218 
       
   219 if Gear^.FrameTicks <= Steps then
       
   220     begin
       
   221     DeleteVisualGear(Gear);
       
   222     exit
       
   223     end
       
   224 else
       
   225     dec(Gear^.FrameTicks, Steps);
       
   226 
       
   227 if Gear^.FrameTicks < $FF then
       
   228    Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or Gear^.FrameTicks
       
   229 end;
       
   230 
       
   231 ////////////////////////////////////////////////////////////////////////////////
       
   232 procedure doStepFire(Gear: PVisualGear; Steps: Longword);
       
   233 var vgt: PVisualGear;
       
   234 begin
       
   235 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   236 
       
   237 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;// + cGravityf * (Steps * Steps);
       
   238 if (Gear^.State and gstTmpFlag) = 0 then
       
   239     begin
       
   240     Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   241     if ((GameTicks mod 200) < Steps + 1) then
       
   242         begin
       
   243         vgt:= AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtFire);
       
   244         if vgt <> nil then
       
   245             begin
       
   246             vgt^.dx:= 0;
       
   247             vgt^.dy:= 0;
       
   248             vgt^.State:= gstTmpFlag;
       
   249             end;
       
   250         end
       
   251     end
       
   252 else
       
   253     inc(Steps, Steps);
       
   254 
       
   255 if Gear^.FrameTicks <= Steps then
       
   256        DeleteVisualGear(Gear)
       
   257 else
       
   258     dec(Gear^.FrameTicks, Steps)
       
   259 end;
       
   260 
       
   261 ////////////////////////////////////////////////////////////////////////////////
       
   262 procedure doStepShell(Gear: PVisualGear; Steps: Longword);
       
   263 begin
       
   264 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   265 
       
   266 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   267 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   268 
       
   269 Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
       
   270 
       
   271 if Gear^.FrameTicks <= Steps then
       
   272     DeleteVisualGear(Gear)
       
   273 else
       
   274     dec(Gear^.FrameTicks, Steps)
       
   275 end;
       
   276 
       
   277 procedure doStepSmallDamage(Gear: PVisualGear; Steps: Longword);
       
   278 begin
       
   279 Gear^.Y:= Gear^.Y - 0.02 * Steps;
       
   280 
       
   281 if Gear^.FrameTicks <= Steps then
       
   282     DeleteVisualGear(Gear)
       
   283 else
       
   284     dec(Gear^.FrameTicks, Steps)
       
   285 end;
       
   286 
       
   287 ////////////////////////////////////////////////////////////////////////////////
       
   288 procedure doStepBubble(Gear: PVisualGear; Steps: Longword);
       
   289 begin
       
   290 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   291 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   292 Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
       
   293 Gear^.dX := Gear^.dX / (1.001 * Steps);
       
   294 Gear^.dY := Gear^.dY / (1.001 * Steps);
       
   295 
       
   296 if (Gear^.FrameTicks <= Steps) or (round(Gear^.Y) < cWaterLine) then
       
   297     DeleteVisualGear(Gear)
       
   298 else
       
   299     dec(Gear^.FrameTicks, Steps)
       
   300 end;
       
   301 
       
   302 ////////////////////////////////////////////////////////////////////////////////
       
   303 procedure doStepSteam(Gear: PVisualGear; Steps: Longword);
       
   304 begin
       
   305 Gear^.X:= Gear^.X + (cWindSpeedf * 100 + Gear^.dX) * Steps;
       
   306 Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
       
   307 
       
   308 if Gear^.FrameTicks <= Steps then
       
   309     if Gear^.Frame = 0 then
       
   310         DeleteVisualGear(Gear)
       
   311     else
       
   312         begin
       
   313         if Random(2) = 0 then
       
   314             dec(Gear^.Frame);
       
   315         Gear^.FrameTicks:= cExplFrameTicks
       
   316         end
       
   317 else dec(Gear^.FrameTicks, Steps)
       
   318 end;
       
   319 
       
   320 ////////////////////////////////////////////////////////////////////////////////
       
   321 procedure doStepAmmo(Gear: PVisualGear; Steps: Longword);
       
   322 begin
       
   323 Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
       
   324 
       
   325 Gear^.scale:= Gear^.scale + 0.0025 * Steps;
       
   326 Gear^.alpha:= Gear^.alpha - 0.0015 * Steps;
       
   327 
       
   328 if Gear^.alpha < 0 then
       
   329     DeleteVisualGear(Gear)
       
   330 end;
       
   331 
       
   332 ////////////////////////////////////////////////////////////////////////////////
       
   333 procedure doStepSmoke(Gear: PVisualGear; Steps: Longword);
       
   334 begin
       
   335 Gear^.X:= Gear^.X + (cWindSpeedf + Gear^.dX) * Steps;
       
   336 Gear^.Y:= Gear^.Y - (cDrownSpeedf + Gear^.dY) * Steps;
       
   337 
       
   338 Gear^.dX := Gear^.dX + (cWindSpeedf * 0.3 * Steps);
       
   339 //Gear^.dY := Gear^.dY - (cDrownSpeedf * 0.995);
       
   340 
       
   341 if Gear^.FrameTicks <= Steps then
       
   342     if Gear^.Frame = 0 then
       
   343         DeleteVisualGear(Gear)
       
   344     else
       
   345         begin
       
   346         if Random(2) = 0 then
       
   347             dec(Gear^.Frame);
       
   348         Gear^.FrameTicks:= cExplFrameTicks
       
   349         end
       
   350     else dec(Gear^.FrameTicks, Steps)
       
   351 end;
       
   352 
       
   353 ////////////////////////////////////////////////////////////////////////////////
       
   354 procedure doStepDust(Gear: PVisualGear; Steps: Longword);
       
   355 begin
       
   356 Gear^.X:= Gear^.X + (cWindSpeedf + (cWindSpeedf * 0.03 * Steps) + Gear^.dX) * Steps;
       
   357 Gear^.Y:= Gear^.Y - (Gear^.dY) * Steps;
       
   358 
       
   359 Gear^.dX := Gear^.dX - (Gear^.dX * 0.005 * Steps);
       
   360 Gear^.dY := Gear^.dY - (cDrownSpeedf * 0.001 * Steps);
       
   361 
       
   362 if Gear^.FrameTicks <= Steps then
       
   363     if Gear^.Frame = 0 then
       
   364             DeleteVisualGear(Gear)
       
   365     else
       
   366         begin
       
   367         dec(Gear^.Frame);
       
   368         Gear^.FrameTicks:= cExplFrameTicks
       
   369         end
       
   370     else dec(Gear^.FrameTicks, Steps)
       
   371 end;
       
   372 
       
   373 ////////////////////////////////////////////////////////////////////////////////
       
   374 procedure doStepSplash(Gear: PVisualGear; Steps: Longword);
       
   375 begin
       
   376 if Gear^.FrameTicks <= Steps then
       
   377     DeleteVisualGear(Gear)
       
   378 else
       
   379     dec(Gear^.FrameTicks, Steps);
       
   380 end;
       
   381 
       
   382 ////////////////////////////////////////////////////////////////////////////////
       
   383 procedure doStepDroplet(Gear: PVisualGear; Steps: Longword);
       
   384 begin
       
   385 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   386 
       
   387 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   388 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   389 
       
   390 if round(Gear^.Y) > cWaterLine then
       
   391     begin
       
   392     DeleteVisualGear(Gear);
       
   393     PlaySound(TSound(ord(sndDroplet1) + Random(3)));
       
   394     end;
       
   395 end;
       
   396 
       
   397 ////////////////////////////////////////////////////////////////////////////////
       
   398 procedure doStepSmokeRing(Gear: PVisualGear; Steps: Longword);
       
   399 begin
       
   400 inc(Gear^.Timer, Steps);
       
   401 if Gear^.Timer >= Gear^.FrameTicks then
       
   402     DeleteVisualGear(Gear)
       
   403 else
       
   404     begin
       
   405     Gear^.scale := 1.25 * (-power(2, -10 * Int(Gear^.Timer)/Gear^.FrameTicks) + 1) + 0.4;
       
   406     Gear^.alpha := 1 - power(Gear^.Timer / 350, 4);
       
   407     if Gear^.alpha < 0 then
       
   408         Gear^.alpha:= 0;
       
   409     end;
       
   410 end;
       
   411 
       
   412 ////////////////////////////////////////////////////////////////////////////////
       
   413 procedure doStepFeather(Gear: PVisualGear; Steps: Longword);
       
   414 begin
       
   415 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   416 
       
   417 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   418 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   419 
       
   420 Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
       
   421 
       
   422 if Gear^.FrameTicks <= Steps then
       
   423     DeleteVisualGear(Gear)
       
   424 else
       
   425     dec(Gear^.FrameTicks, Steps)
       
   426 end;
       
   427 
       
   428 ////////////////////////////////////////////////////////////////////////////////
       
   429 const cSorterWorkTime = 640;
       
   430 var thexchar: array[0..cMaxTeams] of
       
   431             record
       
   432             dy, ny, dw: LongInt;
       
   433             team: PTeam;
       
   434             SortFactor: QWord;
       
   435             end;
       
   436     currsorter: PVisualGear = nil;
       
   437 
       
   438 procedure doStepTeamHealthSorterWork(Gear: PVisualGear; Steps: Longword);
       
   439 var i, t: LongInt;
       
   440 begin
       
   441 for t:= 1 to min(Steps, Gear^.Timer) do
       
   442     begin
       
   443     dec(Gear^.Timer);
       
   444     if (Gear^.Timer and 15) = 0 then
       
   445         for i:= 0 to Pred(TeamsCount) do
       
   446             with thexchar[i] do
       
   447                 begin
       
   448                 {$WARNINGS OFF}
       
   449                 team^.DrawHealthY:= ny + dy * LongInt(Gear^.Timer) div cSorterWorkTime;
       
   450                 team^.TeamHealthBarWidth:= team^.NewTeamHealthBarWidth + dw * LongInt(Gear^.Timer) div cSorterWorkTime;
       
   451                 {$WARNINGS ON}
       
   452                 end;
       
   453     end;
       
   454 
       
   455 if (Gear^.Timer = 0) or (currsorter <> Gear) then
       
   456     begin
       
   457     if currsorter = Gear then
       
   458         currsorter:= nil;
       
   459     DeleteVisualGear(Gear);
       
   460     exit
       
   461     end
       
   462 end;
       
   463 
       
   464 procedure doStepTeamHealthSorter(Gear: PVisualGear; Steps: Longword);
       
   465 var i: Longword;
       
   466     b: boolean;
       
   467     t: LongInt;
       
   468 begin
       
   469 {$IFNDEF PAS2C}
       
   470 Steps:= Steps; // avoid compiler hint
       
   471 {$ENDIF}
       
   472 
       
   473 for t:= 0 to Pred(TeamsCount) do
       
   474     with thexchar[t] do
       
   475         begin
       
   476         team:= TeamsArray[t];
       
   477         dy:= team^.DrawHealthY;
       
   478         dw:= team^.TeamHealthBarWidth - team^.NewTeamHealthBarWidth;
       
   479         if team^.TeamHealth > 0 then
       
   480             begin
       
   481             SortFactor:= team^.Clan^.ClanHealth;
       
   482             SortFactor:= (SortFactor shl  3) + team^.Clan^.ClanIndex;
       
   483             SortFactor:= (SortFactor shl 30) + team^.TeamHealth;
       
   484             end
       
   485         else
       
   486             SortFactor:= 0;
       
   487         end;
       
   488 
       
   489 if TeamsCount > 1 then
       
   490     repeat
       
   491     b:= true;
       
   492     for t:= 0 to TeamsCount - 2 do
       
   493         if (thexchar[t].SortFactor > thexchar[Succ(t)].SortFactor) then
       
   494             begin
       
   495             thexchar[cMaxTeams]:= thexchar[t];
       
   496             thexchar[t]:= thexchar[Succ(t)];
       
   497             thexchar[Succ(t)]:= thexchar[cMaxTeams];
       
   498             b:= false
       
   499             end
       
   500     until b;
       
   501 
       
   502 t:= - 4;
       
   503 for i:= 0 to Pred(TeamsCount) do
       
   504         with thexchar[i] do
       
   505           if team^.TeamHealth > 0 then
       
   506             begin
       
   507             dec(t, team^.HealthTex^.h + 2);
       
   508             ny:= t;
       
   509             dy:= dy - ny
       
   510             end;
       
   511 
       
   512 Gear^.Timer:= cSorterWorkTime;
       
   513 Gear^.doStep:= @doStepTeamHealthSorterWork;
       
   514 currsorter:= Gear;
       
   515 //doStepTeamHealthSorterWork(Gear, Steps)
       
   516 end;
       
   517 
       
   518 ////////////////////////////////////////////////////////////////////////////////
       
   519 procedure doStepSpeechBubbleWork(Gear: PVisualGear; Steps: Longword);
       
   520 begin
       
   521 if Gear^.Timer > Steps then dec(Gear^.Timer, Steps) else Gear^.Timer:= 0;
       
   522 
       
   523 if (Gear^.Hedgehog^.Gear <> nil) then
       
   524     begin
       
   525     Gear^.X:= hwFloat2Float(Gear^.Hedgehog^.Gear^.X) + (Gear^.Tex^.w div 2  - Gear^.FrameTicks);
       
   526     Gear^.Y:= hwFloat2Float(Gear^.Hedgehog^.Gear^.Y) - (16 + Gear^.Tex^.h);
       
   527     end;
       
   528 
       
   529 if Gear^.Timer = 0 then
       
   530     begin
       
   531     if Gear^.Hedgehog^.SpeechGear = Gear then
       
   532         Gear^.Hedgehog^.SpeechGear:= nil;
       
   533     DeleteVisualGear(Gear)
       
   534     end;
       
   535 end;
       
   536 
       
   537 procedure doStepSpeechBubble(Gear: PVisualGear; Steps: Longword);
       
   538 begin
       
   539 
       
   540 {$IFNDEF PAS2C}
       
   541 Steps:= Steps; // avoid compiler hint
       
   542 {$ENDIF}
       
   543 
       
   544 with Gear^.Hedgehog^ do
       
   545     if SpeechGear <> nil then
       
   546         SpeechGear^.Timer:= 0;
       
   547 
       
   548 Gear^.Hedgehog^.SpeechGear:= Gear;
       
   549 
       
   550 Gear^.Timer:= max(LongInt(Length(Gear^.Text)) * 150, 3000);
       
   551 
       
   552 Gear^.Tex:= RenderSpeechBubbleTex(Gear^.Text, Gear^.FrameTicks, fnt16);
       
   553 
       
   554 case Gear^.FrameTicks of
       
   555     1: Gear^.FrameTicks:= SpritesData[sprSpeechTail].Width-28;
       
   556     2: Gear^.FrameTicks:= SpritesData[sprThoughtTail].Width-20;
       
   557     3: Gear^.FrameTicks:= SpritesData[sprShoutTail].Width-10;
       
   558     end;
       
   559 
       
   560 Gear^.doStep:= @doStepSpeechBubbleWork;
       
   561 
       
   562 Gear^.Y:= Gear^.Y - Gear^.Tex^.h
       
   563 end;
       
   564 
       
   565 ////////////////////////////////////////////////////////////////////////////////
       
   566 procedure doStepHealthTagWork(Gear: PVisualGear; Steps: Longword);
       
   567 begin
       
   568 if Steps > Gear^.Timer then
       
   569     DeleteVisualGear(Gear)
       
   570 else
       
   571     begin
       
   572     dec(Gear^.Timer, Steps);
       
   573     Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   574     Gear^.X:= Gear^.X + Gear^.dX * Steps
       
   575     end;
       
   576 end;
       
   577 
       
   578 procedure doStepHealthTagWorkUnderWater(Gear: PVisualGear; Steps: Longword);
       
   579 begin
       
   580 if round(Gear^.Y) - 10 < cWaterLine then
       
   581     DeleteVisualGear(Gear)
       
   582 else
       
   583     Gear^.Y:= Gear^.Y - 0.08 * Steps;
       
   584 
       
   585 end;
       
   586 
       
   587 procedure doStepHealthTag(Gear: PVisualGear; Steps: Longword);
       
   588 var s: shortstring;
       
   589 begin
       
   590 s:= '';
       
   591 
       
   592 str(Gear^.State, s);
       
   593 if Gear^.Hedgehog <> nil then
       
   594     Gear^.Tex:= RenderStringTex(s, Gear^.Hedgehog^.Team^.Clan^.Color, fnt16)
       
   595 else
       
   596     Gear^.Tex:= RenderStringTex(s, cWhiteColor, fnt16);
       
   597 
       
   598 Gear^.doStep:= @doStepHealthTagWork;
       
   599 
       
   600 if (round(Gear^.Y) > cWaterLine) and (Gear^.Frame = 0)  then
       
   601     Gear^.doStep:= @doStepHealthTagWorkUnderWater;
       
   602 
       
   603 Gear^.Y:= Gear^.Y - Gear^.Tex^.h;
       
   604 
       
   605 if Steps > 1 then
       
   606     Gear^.doStep(Gear, Steps-1);
       
   607 end;
       
   608 
       
   609 ////////////////////////////////////////////////////////////////////////////////
       
   610 procedure doStepSmokeTrace(Gear: PVisualGear; Steps: Longword);
       
   611 begin
       
   612 inc(Gear^.Timer, Steps );
       
   613 if Gear^.Timer > 64 then
       
   614     begin
       
   615     if Gear^.State = 0 then
       
   616         begin
       
   617         DeleteVisualGear(Gear);
       
   618         exit;
       
   619         end;
       
   620     dec(Gear^.State, Gear^.Timer div 65);
       
   621     Gear^.Timer:= Gear^.Timer mod 65;
       
   622     end;
       
   623 Gear^.dX:= Gear^.dX + cWindSpeedf * Steps;
       
   624 Gear^.X:= Gear^.X + Gear^.dX;
       
   625 end;
       
   626 
       
   627 ////////////////////////////////////////////////////////////////////////////////
       
   628 procedure doStepExplosionWork(Gear: PVisualGear; Steps: Longword);
       
   629 begin
       
   630 inc(Gear^.Timer, Steps);
       
   631 if Gear^.Timer > 75 then
       
   632     begin
       
   633     inc(Gear^.State, Gear^.Timer div 76);
       
   634     Gear^.Timer:= Gear^.Timer mod 76;
       
   635     if Gear^.State > 5 then
       
   636         DeleteVisualGear(Gear);
       
   637     end;
       
   638 end;
       
   639 
       
   640 procedure doStepExplosion(Gear: PVisualGear; Steps: Longword);
       
   641 var i: LongWord;
       
   642     gX,gY: LongInt;
       
   643     vg: PVisualGear;
       
   644 begin
       
   645 gX:= round(Gear^.X);
       
   646 gY:= round(Gear^.Y);
       
   647 for i:= 0 to 31 do
       
   648     begin
       
   649     vg:= AddVisualGear(gX, gY, vgtFire);
       
   650     if vg <> nil then
       
   651         begin
       
   652         vg^.State:= gstTmpFlag;
       
   653         inc(vg^.FrameTicks, vg^.FrameTicks)
       
   654         end
       
   655     end;
       
   656 for i:= 0 to  8 do AddVisualGear(gX, gY, vgtExplPart);
       
   657 for i:= 0 to  8 do AddVisualGear(gX, gY, vgtExplPart2);
       
   658 Gear^.doStep:= @doStepExplosionWork;
       
   659 if Steps > 1 then
       
   660     Gear^.doStep(Gear, Steps-1);
       
   661 end;
       
   662 
       
   663 
       
   664 ////////////////////////////////////////////////////////////////////////////////
       
   665 procedure doStepBigExplosionWork(Gear: PVisualGear; Steps: Longword);
       
   666 var maxMovement: LongInt;
       
   667 begin
       
   668 
       
   669 inc(Gear^.Timer, Steps);
       
   670 if (Gear^.Timer and 5) = 0 then
       
   671     begin
       
   672     maxMovement := max(1, 13 - ((Gear^.Timer * 15) div 250));
       
   673     ShakeCamera(maxMovement);
       
   674     end;
       
   675 
       
   676 if Gear^.Timer > 250 then
       
   677     DeleteVisualGear(Gear);
       
   678 end;
       
   679 
       
   680 procedure doStepBigExplosion(Gear: PVisualGear; Steps: Longword);
       
   681 var i: LongWord;
       
   682     gX,gY: LongInt;
       
   683     vg: PVisualGear;
       
   684 begin
       
   685 //ScreenFade:= sfFromWhite;
       
   686 //ScreenFadeValue:= round(60 * zoom * zoom);
       
   687 //ScreenFadeSpeed:= 5;
       
   688 gX:= round(Gear^.X);
       
   689 gY:= round(Gear^.Y);
       
   690 AddVisualGear(gX, gY, vgtSmokeRing);
       
   691 for i:= 0 to 46 do
       
   692     begin
       
   693     vg:= AddVisualGear(gX, gY, vgtFire);
       
   694     if vg <> nil then
       
   695         begin
       
   696         vg^.State:= gstTmpFlag;
       
   697         inc(vg^.FrameTicks, vg^.FrameTicks)
       
   698         end
       
   699     end;
       
   700 for i:= 0 to 15 do
       
   701     AddVisualGear(gX, gY, vgtExplPart);
       
   702 for i:= 0 to 15 do
       
   703     AddVisualGear(gX, gY, vgtExplPart2);
       
   704 Gear^.doStep:= @doStepBigExplosionWork;
       
   705 if Steps > 1 then
       
   706     Gear^.doStep(Gear, Steps-1);
       
   707 
       
   708 {$IFNDEF PAS2C}
       
   709 with mobileRecord do
       
   710     if (performRumble <> nil) and (not fastUntilLag) then
       
   711         performRumble(kSystemSoundID_Vibrate);
       
   712 {$ENDIF}
       
   713 end;
       
   714 
       
   715 procedure doStepChunk(Gear: PVisualGear; Steps: Longword);
       
   716 begin
       
   717 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   718 
       
   719 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   720 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   721 
       
   722 Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
       
   723 
       
   724 if (round(Gear^.Y) > cWaterLine) and ((cReducedQuality and rqPlainSplash) = 0) then
       
   725     begin
       
   726     AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtDroplet);
       
   727     DeleteVisualGear(Gear);
       
   728     end
       
   729 end;
       
   730 
       
   731 ////////////////////////////////////////////////////////////////////////////////
       
   732 procedure doStepBulletHit(Gear: PVisualGear; Steps: Longword);
       
   733 begin
       
   734 if Gear^.FrameTicks <= Steps then
       
   735     DeleteVisualGear(Gear)
       
   736 else
       
   737     dec(Gear^.FrameTicks, Steps);
       
   738 end;
       
   739 
       
   740 ////////////////////////////////////////////////////////////////////////////////
       
   741 procedure doStepCircle(Gear: PVisualGear; Steps: Longword);
       
   742 var tmp: LongInt;
       
   743     i: LongWord;
       
   744 begin
       
   745 with Gear^ do
       
   746     if Frame <> 0 then
       
   747         for i:= 1 to Steps do
       
   748             begin
       
   749             inc(FrameTicks);
       
   750             if (FrameTicks mod Frame) = 0 then
       
   751                 begin
       
   752                 tmp:= Gear^.Tint and $FF;
       
   753                 if tdY >= 0 then
       
   754                     inc(tmp)
       
   755                 else
       
   756                     dec(tmp);
       
   757                 if tmp < round(dX) then
       
   758                     tdY:= 1;
       
   759                 if tmp > round(dY) then
       
   760                     tdY:= -1;
       
   761                 if tmp > 255 then
       
   762                     tmp := 255;
       
   763                 if tmp < 0 then
       
   764                     tmp := 0;
       
   765                 Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or Longword(tmp)
       
   766                 end
       
   767             end
       
   768 end;
       
   769 
       
   770 ////////////////////////////////////////////////////////////////////////////////
       
   771 procedure doStepSmoothWindBar(Gear: PVisualGear; Steps: Longword);
       
   772 begin
       
   773 inc(Gear^.Timer, Steps);
       
   774 
       
   775 while Gear^.Timer >= 10 do
       
   776     begin
       
   777     dec(Gear^.Timer, 10);
       
   778     if WindBarWidth < Gear^.Tag then
       
   779         inc(WindBarWidth)
       
   780     else if WindBarWidth > Gear^.Tag then
       
   781         dec(WindBarWidth);
       
   782     end;
       
   783 if cWindspeedf > Gear^.dAngle then
       
   784     begin
       
   785     cWindspeedf := cWindspeedf - Gear^.Angle*Steps;
       
   786     if cWindspeedf < Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
       
   787     end
       
   788 else if cWindspeedf < Gear^.dAngle then
       
   789     begin
       
   790     cWindspeedf := cWindspeedf + Gear^.Angle*Steps;
       
   791     if cWindspeedf > Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
       
   792     end;
       
   793 
       
   794 if (WindBarWidth = Gear^.Tag) and (cWindspeedf = Gear^.dAngle)  then
       
   795     DeleteVisualGear(Gear)
       
   796 end;
       
   797 ////////////////////////////////////////////////////////////////////////////////
       
   798 procedure doStepStraightShot(Gear: PVisualGear; Steps: Longword);
       
   799 begin
       
   800 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   801 Gear^.Y:= Gear^.Y - Gear^.dY * Steps;
       
   802 
       
   803 if Gear^.FrameTicks <= Steps then
       
   804     DeleteVisualGear(Gear)
       
   805 else
       
   806     begin
       
   807     dec(Gear^.FrameTicks, Steps);
       
   808     if (Gear^.FrameTicks < 501) and (Gear^.FrameTicks mod 5 = 0) then
       
   809         Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or (((Gear^.Tint and $000000FF) * Gear^.FrameTicks) div 500)
       
   810     end
       
   811 end;
       
   812