hedgewars/uVisualGearsHandlers.pas
changeset 9283 76e68c136a11
parent 9080 9b42757d7e71
child 9521 8054d9d775fd
child 9656 18422d205080
equal deleted inserted replaced
9280:c3b11f913145 9283:76e68c136a11
       
     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 Steps := Steps;
       
   252 if Gear^.Timer <= Steps then
       
   253     DeleteVisualGear(Gear)
       
   254 else
       
   255     dec(Gear^.Timer, Steps)
       
   256 end;
       
   257 
       
   258 ////////////////////////////////////////////////////////////////////////////////
       
   259 procedure doStepEgg(Gear: PVisualGear; Steps: Longword);
       
   260 begin
       
   261 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   262 
       
   263 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   264 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   265 
       
   266 Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
       
   267 
       
   268 if Gear^.FrameTicks <= Steps then
       
   269     begin
       
   270     DeleteVisualGear(Gear);
       
   271     exit
       
   272     end
       
   273 else
       
   274     dec(Gear^.FrameTicks, Steps);
       
   275 
       
   276 if Gear^.FrameTicks < $FF then
       
   277    Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or Gear^.FrameTicks
       
   278 end;
       
   279 
       
   280 ////////////////////////////////////////////////////////////////////////////////
       
   281 procedure doStepFire(Gear: PVisualGear; Steps: Longword);
       
   282 var vgt: PVisualGear;
       
   283 begin
       
   284 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   285 
       
   286 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;// + cGravityf * (Steps * Steps);
       
   287 if (Gear^.State and gstTmpFlag) = 0 then
       
   288     begin
       
   289     Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   290     if ((GameTicks mod 200) < Steps + 1) then
       
   291         begin
       
   292         vgt:= AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtFire);
       
   293         if vgt <> nil then
       
   294             begin
       
   295             vgt^.dx:= 0;
       
   296             vgt^.dy:= 0;
       
   297             vgt^.State:= gstTmpFlag;
       
   298             end;
       
   299         end
       
   300     end
       
   301 else
       
   302     inc(Steps, Steps);
       
   303 
       
   304 if Gear^.FrameTicks <= Steps then
       
   305        DeleteVisualGear(Gear)
       
   306 else
       
   307     dec(Gear^.FrameTicks, Steps)
       
   308 end;
       
   309 
       
   310 ////////////////////////////////////////////////////////////////////////////////
       
   311 procedure doStepShell(Gear: PVisualGear; Steps: Longword);
       
   312 begin
       
   313 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   314 
       
   315 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   316 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   317 
       
   318 Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
       
   319 
       
   320 if Gear^.FrameTicks <= Steps then
       
   321     DeleteVisualGear(Gear)
       
   322 else
       
   323     dec(Gear^.FrameTicks, Steps)
       
   324 end;
       
   325 
       
   326 procedure doStepSmallDamage(Gear: PVisualGear; Steps: Longword);
       
   327 begin
       
   328 Gear^.Y:= Gear^.Y - 0.02 * Steps;
       
   329 
       
   330 if Gear^.FrameTicks <= Steps then
       
   331     DeleteVisualGear(Gear)
       
   332 else
       
   333     dec(Gear^.FrameTicks, Steps)
       
   334 end;
       
   335 
       
   336 ////////////////////////////////////////////////////////////////////////////////
       
   337 procedure doStepBubble(Gear: PVisualGear; Steps: Longword);
       
   338 begin
       
   339 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   340 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   341 Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
       
   342 Gear^.dX := Gear^.dX / (1.001 * Steps);
       
   343 Gear^.dY := Gear^.dY / (1.001 * Steps);
       
   344 
       
   345 if (Gear^.FrameTicks <= Steps) or (round(Gear^.Y) < cWaterLine) then
       
   346     DeleteVisualGear(Gear)
       
   347 else
       
   348     dec(Gear^.FrameTicks, Steps)
       
   349 end;
       
   350 
       
   351 ////////////////////////////////////////////////////////////////////////////////
       
   352 procedure doStepSteam(Gear: PVisualGear; Steps: Longword);
       
   353 begin
       
   354 Gear^.X:= Gear^.X + (cWindSpeedf * 100 + Gear^.dX) * Steps;
       
   355 Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
       
   356 
       
   357 if Gear^.FrameTicks <= Steps then
       
   358     if Gear^.Frame = 0 then
       
   359         DeleteVisualGear(Gear)
       
   360     else
       
   361         begin
       
   362         if Random(2) = 0 then
       
   363             dec(Gear^.Frame);
       
   364         Gear^.FrameTicks:= cExplFrameTicks
       
   365         end
       
   366 else dec(Gear^.FrameTicks, Steps)
       
   367 end;
       
   368 
       
   369 ////////////////////////////////////////////////////////////////////////////////
       
   370 procedure doStepAmmo(Gear: PVisualGear; Steps: Longword);
       
   371 begin
       
   372 Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
       
   373 
       
   374 Gear^.scale:= Gear^.scale + 0.0025 * Steps;
       
   375 Gear^.alpha:= Gear^.alpha - 0.0015 * Steps;
       
   376 
       
   377 if Gear^.alpha < 0 then
       
   378     DeleteVisualGear(Gear)
       
   379 end;
       
   380 
       
   381 ////////////////////////////////////////////////////////////////////////////////
       
   382 procedure doStepSmoke(Gear: PVisualGear; Steps: Longword);
       
   383 begin
       
   384 Gear^.X:= Gear^.X + (cWindSpeedf + Gear^.dX) * Steps;
       
   385 Gear^.Y:= Gear^.Y - (cDrownSpeedf + Gear^.dY) * Steps;
       
   386 
       
   387 Gear^.dX := Gear^.dX + (cWindSpeedf * 0.3 * Steps);
       
   388 //Gear^.dY := Gear^.dY - (cDrownSpeedf * 0.995);
       
   389 
       
   390 if Gear^.FrameTicks <= Steps then
       
   391     if Gear^.Frame = 0 then
       
   392         DeleteVisualGear(Gear)
       
   393     else
       
   394         begin
       
   395         if Random(2) = 0 then
       
   396             dec(Gear^.Frame);
       
   397         Gear^.FrameTicks:= cExplFrameTicks
       
   398         end
       
   399     else dec(Gear^.FrameTicks, Steps)
       
   400 end;
       
   401 
       
   402 ////////////////////////////////////////////////////////////////////////////////
       
   403 procedure doStepDust(Gear: PVisualGear; Steps: Longword);
       
   404 begin
       
   405 Gear^.X:= Gear^.X + (cWindSpeedf + (cWindSpeedf * 0.03 * Steps) + Gear^.dX) * Steps;
       
   406 Gear^.Y:= Gear^.Y - (Gear^.dY) * Steps;
       
   407 
       
   408 Gear^.dX := Gear^.dX - (Gear^.dX * 0.005 * Steps);
       
   409 Gear^.dY := Gear^.dY - (cDrownSpeedf * 0.001 * Steps);
       
   410 
       
   411 if Gear^.FrameTicks <= Steps then
       
   412     if Gear^.Frame = 0 then
       
   413             DeleteVisualGear(Gear)
       
   414     else
       
   415         begin
       
   416         dec(Gear^.Frame);
       
   417         Gear^.FrameTicks:= cExplFrameTicks
       
   418         end
       
   419     else dec(Gear^.FrameTicks, Steps)
       
   420 end;
       
   421 
       
   422 ////////////////////////////////////////////////////////////////////////////////
       
   423 procedure doStepSplash(Gear: PVisualGear; Steps: Longword);
       
   424 begin
       
   425 if Gear^.FrameTicks <= Steps then
       
   426     DeleteVisualGear(Gear)
       
   427 else
       
   428     dec(Gear^.FrameTicks, Steps);
       
   429 end;
       
   430 
       
   431 ////////////////////////////////////////////////////////////////////////////////
       
   432 procedure doStepDroplet(Gear: PVisualGear; Steps: Longword);
       
   433 begin
       
   434 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   435 
       
   436 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   437 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   438 
       
   439 if round(Gear^.Y) > cWaterLine then
       
   440     begin
       
   441     DeleteVisualGear(Gear);
       
   442     PlaySound(TSound(ord(sndDroplet1) + Random(3)));
       
   443     end;
       
   444 end;
       
   445 
       
   446 ////////////////////////////////////////////////////////////////////////////////
       
   447 procedure doStepSmokeRing(Gear: PVisualGear; Steps: Longword);
       
   448 begin
       
   449 inc(Gear^.Timer, Steps);
       
   450 if Gear^.Timer >= Gear^.FrameTicks then
       
   451     DeleteVisualGear(Gear)
       
   452 else
       
   453     begin
       
   454     Gear^.scale := 1.25 * (-power(2, -10 * Int(Gear^.Timer)/Gear^.FrameTicks) + 1) + 0.4;
       
   455     Gear^.alpha := 1 - power(Gear^.Timer / 350, 4);
       
   456     if Gear^.alpha < 0 then
       
   457         Gear^.alpha:= 0;
       
   458     end;
       
   459 end;
       
   460 
       
   461 ////////////////////////////////////////////////////////////////////////////////
       
   462 procedure doStepFeather(Gear: PVisualGear; Steps: Longword);
       
   463 begin
       
   464 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   465 
       
   466 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   467 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   468 
       
   469 Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
       
   470 
       
   471 if Gear^.FrameTicks <= Steps then
       
   472     DeleteVisualGear(Gear)
       
   473 else
       
   474     dec(Gear^.FrameTicks, Steps)
       
   475 end;
       
   476 
       
   477 ////////////////////////////////////////////////////////////////////////////////
       
   478 const cSorterWorkTime = 640;
       
   479 var thexchar: array[0..cMaxTeams] of
       
   480             record
       
   481             dy, ny, dw: LongInt;
       
   482             team: PTeam;
       
   483             SortFactor: QWord;
       
   484             end;
       
   485     currsorter: PVisualGear = nil;
       
   486 
       
   487 procedure doStepTeamHealthSorterWork(Gear: PVisualGear; Steps: Longword);
       
   488 var i, t: LongInt;
       
   489 begin
       
   490 for t:= 1 to min(Steps, Gear^.Timer) do
       
   491     begin
       
   492     dec(Gear^.Timer);
       
   493     if (Gear^.Timer and 15) = 0 then
       
   494         for i:= 0 to Pred(TeamsCount) do
       
   495             with thexchar[i] do
       
   496                 begin
       
   497                 {$WARNINGS OFF}
       
   498                 team^.DrawHealthY:= ny + dy * LongInt(Gear^.Timer) div cSorterWorkTime;
       
   499                 team^.TeamHealthBarWidth:= team^.NewTeamHealthBarWidth + dw * LongInt(Gear^.Timer) div cSorterWorkTime;
       
   500                 {$WARNINGS ON}
       
   501                 end;
       
   502     end;
       
   503 
       
   504 if (Gear^.Timer = 0) or (currsorter <> Gear) then
       
   505     begin
       
   506     if currsorter = Gear then
       
   507         currsorter:= nil;
       
   508     DeleteVisualGear(Gear);
       
   509     exit
       
   510     end
       
   511 end;
       
   512 
       
   513 procedure doStepTeamHealthSorter(Gear: PVisualGear; Steps: Longword);
       
   514 var i: Longword;
       
   515     b: boolean;
       
   516     t: LongInt;
       
   517 begin
       
   518 Steps:= Steps; // avoid compiler hint
       
   519 
       
   520 for t:= 0 to Pred(TeamsCount) do
       
   521     with thexchar[t] do
       
   522         begin
       
   523         team:= TeamsArray[t];
       
   524         dy:= team^.DrawHealthY;
       
   525         dw:= team^.TeamHealthBarWidth - team^.NewTeamHealthBarWidth;
       
   526         if team^.TeamHealth > 0 then
       
   527             begin
       
   528             SortFactor:= team^.Clan^.ClanHealth;
       
   529             SortFactor:= (SortFactor shl  3) + team^.Clan^.ClanIndex;
       
   530             SortFactor:= (SortFactor shl 30) + team^.TeamHealth;
       
   531             end
       
   532         else
       
   533             SortFactor:= 0;
       
   534         end;
       
   535 
       
   536 if TeamsCount > 1 then
       
   537     repeat
       
   538     b:= true;
       
   539     for t:= 0 to TeamsCount - 2 do
       
   540         if (thexchar[t].SortFactor > thexchar[Succ(t)].SortFactor) then
       
   541             begin
       
   542             thexchar[cMaxTeams]:= thexchar[t];
       
   543             thexchar[t]:= thexchar[Succ(t)];
       
   544             thexchar[Succ(t)]:= thexchar[cMaxTeams];
       
   545             b:= false
       
   546             end
       
   547     until b;
       
   548 
       
   549 t:= - 4;
       
   550 for i:= 0 to Pred(TeamsCount) do
       
   551         with thexchar[i] do
       
   552           if team^.TeamHealth > 0 then
       
   553             begin
       
   554             dec(t, team^.HealthTex^.h + 2);
       
   555             ny:= t;
       
   556             dy:= dy - ny
       
   557             end;
       
   558 
       
   559 Gear^.Timer:= cSorterWorkTime;
       
   560 Gear^.doStep:= @doStepTeamHealthSorterWork;
       
   561 currsorter:= Gear;
       
   562 //doStepTeamHealthSorterWork(Gear, Steps)
       
   563 end;
       
   564 
       
   565 ////////////////////////////////////////////////////////////////////////////////
       
   566 procedure doStepSpeechBubbleWork(Gear: PVisualGear; Steps: Longword);
       
   567 begin
       
   568 if Gear^.Timer > Steps then dec(Gear^.Timer, Steps) else Gear^.Timer:= 0;
       
   569 
       
   570 if (Gear^.Hedgehog^.Gear <> nil) then
       
   571     begin
       
   572     Gear^.X:= hwFloat2Float(Gear^.Hedgehog^.Gear^.X) + (Gear^.Tex^.w div 2  - Gear^.FrameTicks);
       
   573     Gear^.Y:= hwFloat2Float(Gear^.Hedgehog^.Gear^.Y) - (16 + Gear^.Tex^.h);
       
   574     end;
       
   575 
       
   576 if Gear^.Timer = 0 then
       
   577     begin
       
   578     if Gear^.Hedgehog^.SpeechGear = Gear then
       
   579         Gear^.Hedgehog^.SpeechGear:= nil;
       
   580     DeleteVisualGear(Gear)
       
   581     end;
       
   582 end;
       
   583 
       
   584 procedure doStepSpeechBubble(Gear: PVisualGear; Steps: Longword);
       
   585 begin
       
   586 Steps:= Steps; // avoid compiler hint
       
   587 
       
   588 with Gear^.Hedgehog^ do
       
   589     if SpeechGear <> nil then
       
   590         SpeechGear^.Timer:= 0;
       
   591 
       
   592 Gear^.Hedgehog^.SpeechGear:= Gear;
       
   593 
       
   594 Gear^.Timer:= max(LongInt(Length(Gear^.Text)) * 150, 3000);
       
   595 
       
   596 Gear^.Tex:= RenderSpeechBubbleTex(Gear^.Text, Gear^.FrameTicks, fnt16);
       
   597 
       
   598 case Gear^.FrameTicks of
       
   599     1: Gear^.FrameTicks:= SpritesData[sprSpeechTail].Width-28;
       
   600     2: Gear^.FrameTicks:= SpritesData[sprThoughtTail].Width-20;
       
   601     3: Gear^.FrameTicks:= SpritesData[sprShoutTail].Width-10;
       
   602     end;
       
   603 
       
   604 Gear^.doStep:= @doStepSpeechBubbleWork;
       
   605 
       
   606 Gear^.Y:= Gear^.Y - Gear^.Tex^.h
       
   607 end;
       
   608 
       
   609 ////////////////////////////////////////////////////////////////////////////////
       
   610 procedure doStepHealthTagWork(Gear: PVisualGear; Steps: Longword);
       
   611 begin
       
   612 if Steps > Gear^.Timer then
       
   613     DeleteVisualGear(Gear)
       
   614 else
       
   615     begin
       
   616     dec(Gear^.Timer, Steps);
       
   617     Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   618     Gear^.X:= Gear^.X + Gear^.dX * Steps
       
   619     end;
       
   620 end;
       
   621 
       
   622 procedure doStepHealthTagWorkUnderWater(Gear: PVisualGear; Steps: Longword);
       
   623 begin
       
   624 if round(Gear^.Y) - 10 < cWaterLine then
       
   625     DeleteVisualGear(Gear)
       
   626 else
       
   627     Gear^.Y:= Gear^.Y - 0.08 * Steps;
       
   628 
       
   629 end;
       
   630 
       
   631 procedure doStepHealthTag(Gear: PVisualGear; Steps: Longword);
       
   632 var s: shortstring;
       
   633 begin
       
   634 s:= '';
       
   635 
       
   636 str(Gear^.State, s);
       
   637 if Gear^.Hedgehog <> nil then
       
   638     Gear^.Tex:= RenderStringTex(s, Gear^.Hedgehog^.Team^.Clan^.Color, fnt16)
       
   639 else
       
   640     Gear^.Tex:= RenderStringTex(s, cWhiteColor, fnt16);
       
   641 
       
   642 Gear^.doStep:= @doStepHealthTagWork;
       
   643 
       
   644 if (round(Gear^.Y) > cWaterLine) and (Gear^.Frame = 0)  then
       
   645     Gear^.doStep:= @doStepHealthTagWorkUnderWater;
       
   646 
       
   647 Gear^.Y:= Gear^.Y - Gear^.Tex^.h;
       
   648 
       
   649 if Steps > 1 then
       
   650     Gear^.doStep(Gear, Steps-1);
       
   651 end;
       
   652 
       
   653 ////////////////////////////////////////////////////////////////////////////////
       
   654 procedure doStepSmokeTrace(Gear: PVisualGear; Steps: Longword);
       
   655 begin
       
   656 inc(Gear^.Timer, Steps );
       
   657 if Gear^.Timer > 64 then
       
   658     begin
       
   659     if Gear^.State = 0 then
       
   660         begin
       
   661         DeleteVisualGear(Gear);
       
   662         exit;
       
   663         end;
       
   664     dec(Gear^.State, Gear^.Timer div 65);
       
   665     Gear^.Timer:= Gear^.Timer mod 65;
       
   666     end;
       
   667 Gear^.dX:= Gear^.dX + cWindSpeedf * Steps;
       
   668 Gear^.X:= Gear^.X + Gear^.dX;
       
   669 end;
       
   670 
       
   671 ////////////////////////////////////////////////////////////////////////////////
       
   672 procedure doStepExplosionWork(Gear: PVisualGear; Steps: Longword);
       
   673 begin
       
   674 inc(Gear^.Timer, Steps);
       
   675 if Gear^.Timer > 75 then
       
   676     begin
       
   677     inc(Gear^.State, Gear^.Timer div 76);
       
   678     Gear^.Timer:= Gear^.Timer mod 76;
       
   679     if Gear^.State > 5 then
       
   680         DeleteVisualGear(Gear);
       
   681     end;
       
   682 end;
       
   683 
       
   684 procedure doStepExplosion(Gear: PVisualGear; Steps: Longword);
       
   685 var i: LongWord;
       
   686     gX,gY: LongInt;
       
   687     vg: PVisualGear;
       
   688 begin
       
   689 gX:= round(Gear^.X);
       
   690 gY:= round(Gear^.Y);
       
   691 for i:= 0 to 31 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  8 do AddVisualGear(gX, gY, vgtExplPart);
       
   701 for i:= 0 to  8 do AddVisualGear(gX, gY, vgtExplPart2);
       
   702 Gear^.doStep:= @doStepExplosionWork;
       
   703 if Steps > 1 then
       
   704     Gear^.doStep(Gear, Steps-1);
       
   705 end;
       
   706 
       
   707 
       
   708 ////////////////////////////////////////////////////////////////////////////////
       
   709 procedure doStepBigExplosionWork(Gear: PVisualGear; Steps: Longword);
       
   710 var maxMovement: LongInt;
       
   711 begin
       
   712 
       
   713 inc(Gear^.Timer, Steps);
       
   714 if (Gear^.Timer and 5) = 0 then
       
   715     begin
       
   716     maxMovement := max(1, 13 - ((Gear^.Timer * 15) div 250));
       
   717     ShakeCamera(maxMovement);
       
   718     end;
       
   719 
       
   720 if Gear^.Timer > 250 then
       
   721     DeleteVisualGear(Gear);
       
   722 end;
       
   723 
       
   724 procedure doStepBigExplosion(Gear: PVisualGear; Steps: Longword);
       
   725 var i: LongWord;
       
   726     gX,gY: LongInt;
       
   727     vg: PVisualGear;
       
   728 begin
       
   729 //ScreenFade:= sfFromWhite;
       
   730 //ScreenFadeValue:= round(60 * zoom * zoom);
       
   731 //ScreenFadeSpeed:= 5;
       
   732 gX:= round(Gear^.X);
       
   733 gY:= round(Gear^.Y);
       
   734 AddVisualGear(gX, gY, vgtSmokeRing);
       
   735 for i:= 0 to 46 do 
       
   736     begin
       
   737     vg:= AddVisualGear(gX, gY, vgtFire);
       
   738     if vg <> nil then 
       
   739         begin
       
   740         vg^.State:= gstTmpFlag;
       
   741         inc(vg^.FrameTicks, vg^.FrameTicks)
       
   742         end
       
   743     end;
       
   744 for i:= 0 to 15 do
       
   745     AddVisualGear(gX, gY, vgtExplPart);
       
   746 for i:= 0 to 15 do
       
   747     AddVisualGear(gX, gY, vgtExplPart2);
       
   748 Gear^.doStep:= @doStepBigExplosionWork;
       
   749 if Steps > 1 then
       
   750     Gear^.doStep(Gear, Steps-1);
       
   751 with mobileRecord do
       
   752     if (performRumble <> nil) and (not fastUntilLag) then
       
   753         performRumble(kSystemSoundID_Vibrate);
       
   754 end;
       
   755 
       
   756 procedure doStepChunk(Gear: PVisualGear; Steps: Longword);
       
   757 begin
       
   758 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   759 
       
   760 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
       
   761 Gear^.dY:= Gear^.dY + cGravityf * Steps;
       
   762 
       
   763 Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
       
   764 
       
   765 if (round(Gear^.Y) > cWaterLine) and ((cReducedQuality and rqPlainSplash) = 0) then
       
   766     begin
       
   767     AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtDroplet);
       
   768     DeleteVisualGear(Gear);
       
   769     end
       
   770 end;
       
   771 
       
   772 ////////////////////////////////////////////////////////////////////////////////
       
   773 procedure doStepBulletHit(Gear: PVisualGear; Steps: Longword);
       
   774 begin
       
   775 if Gear^.FrameTicks <= Steps then
       
   776     DeleteVisualGear(Gear)
       
   777 else
       
   778     dec(Gear^.FrameTicks, Steps);
       
   779 end;
       
   780 
       
   781 ////////////////////////////////////////////////////////////////////////////////
       
   782 procedure doStepCircle(Gear: PVisualGear; Steps: Longword);
       
   783 var tmp: LongInt;
       
   784     i: LongWord;
       
   785 begin
       
   786 with Gear^ do
       
   787     if Frame <> 0 then
       
   788         for i:= 1 to Steps do
       
   789             begin
       
   790             inc(FrameTicks);
       
   791             if (FrameTicks mod Frame) = 0 then
       
   792                 begin
       
   793                 tmp:= Gear^.Tint and $FF;
       
   794                 if tdY >= 0 then
       
   795                     inc(tmp)
       
   796                 else
       
   797                     dec(tmp);
       
   798                 if tmp < round(dX) then
       
   799                     tdY:= 1;
       
   800                 if tmp > round(dY) then
       
   801                     tdY:= -1;
       
   802                 if tmp > 255 then
       
   803                     tmp := 255;
       
   804                 if tmp < 0 then
       
   805                     tmp := 0;
       
   806                 Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or Longword(tmp)
       
   807                 end
       
   808             end
       
   809 end;
       
   810 
       
   811 ////////////////////////////////////////////////////////////////////////////////
       
   812 procedure doStepSmoothWindBar(Gear: PVisualGear; Steps: Longword);
       
   813 begin
       
   814 inc(Gear^.Timer, Steps);
       
   815     
       
   816 while Gear^.Timer >= 10 do
       
   817     begin
       
   818     dec(Gear^.Timer, 10);
       
   819     if WindBarWidth < Gear^.Tag then
       
   820         inc(WindBarWidth)
       
   821     else if WindBarWidth > Gear^.Tag then
       
   822         dec(WindBarWidth);
       
   823     end;
       
   824 if cWindspeedf > Gear^.dAngle then
       
   825     begin
       
   826     cWindspeedf := cWindspeedf - Gear^.Angle*Steps;
       
   827     if cWindspeedf < Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
       
   828     end
       
   829 else if cWindspeedf < Gear^.dAngle then
       
   830     begin
       
   831     cWindspeedf := cWindspeedf + Gear^.Angle*Steps;
       
   832     if cWindspeedf > Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
       
   833     end;
       
   834         
       
   835 if (WindBarWidth = Gear^.Tag) and (cWindspeedf = Gear^.dAngle)  then 
       
   836     DeleteVisualGear(Gear)
       
   837 end;
       
   838 ////////////////////////////////////////////////////////////////////////////////
       
   839 procedure doStepStraightShot(Gear: PVisualGear; Steps: Longword);
       
   840 begin
       
   841 Gear^.X:= Gear^.X + Gear^.dX * Steps;
       
   842 Gear^.Y:= Gear^.Y - Gear^.dY * Steps;
       
   843 
       
   844 if Gear^.FrameTicks <= Steps then
       
   845     DeleteVisualGear(Gear)
       
   846 else
       
   847     begin
       
   848     dec(Gear^.FrameTicks, Steps);
       
   849     if (Gear^.FrameTicks < 501) and (Gear^.FrameTicks mod 5 = 0) then 
       
   850         Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or (((Gear^.Tint and $000000FF) * Gear^.FrameTicks) div 500)
       
   851     end
       
   852 end;
       
   853 
       
   854 
       
   855 const handlers: array[TVisualGearType] of TVGearStepProcedure =
       
   856         (
       
   857             @doStepFlake,
       
   858             @doStepCloud,
       
   859             @doStepExpl,
       
   860             @doStepExpl,
       
   861             @doStepFire,
       
   862             @doStepSmallDamage,
       
   863             @doStepTeamHealthSorter,
       
   864             @doStepSpeechBubble,
       
   865             @doStepBubble,
       
   866             @doStepSteam,
       
   867             @doStepAmmo,
       
   868             @doStepSmoke,
       
   869             @doStepSmoke,
       
   870             @doStepShell,
       
   871             @doStepDust,
       
   872             @doStepSplash,
       
   873             @doStepDroplet,
       
   874             @doStepSmokeRing,
       
   875             @doStepBeeTrace,
       
   876             @doStepEgg,
       
   877             @doStepFeather,
       
   878             @doStepHealthTag,
       
   879             @doStepSmokeTrace,
       
   880             @doStepSmokeTrace,
       
   881             @doStepExplosion,
       
   882             @doStepBigExplosion,
       
   883             @doStepChunk,
       
   884             @doStepNote,
       
   885             @doStepLineTrail,
       
   886             @doStepBulletHit,
       
   887             @doStepCircle,
       
   888             @doStepSmoothWindBar,
       
   889             @doStepStraightShot
       
   890         );
       
   891 
       
   892 procedure initModule;
       
   893 begin
       
   894     doStepHandlers:= handlers
       
   895 end;
       
   896 
       
   897 end.