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