hedgewars/uVisualGears.pas
changeset 9283 76e68c136a11
parent 9080 9b42757d7e71
child 9285 8e8b908970c2
equal deleted inserted replaced
9280:c3b11f913145 9283:76e68c136a11
    32 uses uConsts, uFloat, GLunit, uTypes, uWorld;
    32 uses uConsts, uFloat, GLunit, uTypes, uWorld;
    33 
    33 
    34 procedure initModule;
    34 procedure initModule;
    35 procedure freeModule;
    35 procedure freeModule;
    36 
    36 
    37 function  AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
       
    38 function  AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
       
    39 function  AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear;
       
    40 
       
    41 procedure ProcessVisualGears(Steps: Longword);
    37 procedure ProcessVisualGears(Steps: Longword);
    42 procedure DrawVisualGears(Layer: LongWord);
    38 procedure DrawVisualGears(Layer: LongWord);
    43 procedure DeleteVisualGear(Gear: PVisualGear);
       
    44 function  VisualGearByUID(uid : Longword) : PVisualGear;
       
    45 
    39 
    46 procedure AddClouds;
    40 procedure AddClouds;
    47 procedure AddFlakes;
    41 procedure AddFlakes;
    48 procedure AddDamageTag(X, Y, Damage, Color: LongWord);
    42 procedure AddDamageTag(X, Y, Damage, Color: LongWord);
    49 
    43 
    51 procedure ChangeToSDFlakes;
    45 procedure ChangeToSDFlakes;
    52 
    46 
    53 procedure KickFlakes(Radius, X, Y: LongInt);
    47 procedure KickFlakes(Radius, X, Y: LongInt);
    54 
    48 
    55 implementation
    49 implementation
    56 uses uSound, uVariables, uTextures, uRender, Math, uRenderUtils, uStore, uUtils;
    50 uses uSound, uVariables, uTextures, uRender, Math, uRenderUtils, uStore, uUtils
    57 
    51     , uVisualGearsHandlers, uVisualGearsList;
    58 const 
       
    59     cExplFrameTicks = 110;
       
    60     //cSmokeZ = 499;
       
    61 var VGCounter: LongWord;
       
    62     VisualGearLayers: array[0..6] of PVisualGear;
       
    63 
       
    64 // For better maintainability the step handlers of visual gears are stored
       
    65 // in a separate file.
       
    66 {$INCLUDE "VGSHandlers.inc"}
       
    67 
    52 
    68 procedure AddDamageTag(X, Y, Damage, Color: LongWord);
    53 procedure AddDamageTag(X, Y, Damage, Color: LongWord);
    69 var s: shortstring;
    54 var s: shortstring;
    70     Gear: PVisualGear;
    55     Gear: PVisualGear;
    71 begin
    56 begin
    81     end
    66     end
    82 end;
    67 end;
    83 
    68 
    84 
    69 
    85 // ==================================================================
    70 // ==================================================================
    86 
       
    87 // ==================================================================
       
    88 const doStepHandlers: array[TVisualGearType] of TVGearStepProcedure =
       
    89         (
       
    90             @doStepFlake,
       
    91             @doStepCloud,
       
    92             @doStepExpl,
       
    93             @doStepExpl,
       
    94             @doStepFire,
       
    95             @doStepSmallDamage,
       
    96             @doStepTeamHealthSorter,
       
    97             @doStepSpeechBubble,
       
    98             @doStepBubble,
       
    99             @doStepSteam,
       
   100             @doStepAmmo,
       
   101             @doStepSmoke,
       
   102             @doStepSmoke,
       
   103             @doStepShell,
       
   104             @doStepDust,
       
   105             @doStepSplash,
       
   106             @doStepDroplet,
       
   107             @doStepSmokeRing,
       
   108             @doStepBeeTrace,
       
   109             @doStepEgg,
       
   110             @doStepFeather,
       
   111             @doStepHealthTag,
       
   112             @doStepSmokeTrace,
       
   113             @doStepSmokeTrace,
       
   114             @doStepExplosion,
       
   115             @doStepBigExplosion,
       
   116             @doStepChunk,
       
   117             @doStepNote,
       
   118             @doStepLineTrail,
       
   119             @doStepBulletHit,
       
   120             @doStepCircle,
       
   121             @doStepSmoothWindBar,
       
   122             @doStepStraightShot
       
   123         );
       
   124 
       
   125 function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
       
   126 begin
       
   127     AddVisualGear:= AddVisualGear(X, Y, Kind, 0, false);
       
   128 end;
       
   129 
       
   130 function  AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
       
   131 begin
       
   132     AddVisualGear:= AddVisualGear(X, Y, Kind, State, false);
       
   133 end;
       
   134 
       
   135 function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear;
       
   136 var gear: PVisualGear;
       
   137     t: Longword;
       
   138     sp: real;
       
   139 begin
       
   140 AddVisualGear:= nil;
       
   141 if ((GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet)) or fastScrolling) and // we are scrolling now
       
   142    ((Kind <> vgtCloud) and (not Critical)) then
       
   143        exit;
       
   144 
       
   145 if ((cReducedQuality and rqAntiBoom) <> 0) and
       
   146    (not Critical) and
       
   147    (not (Kind in
       
   148    [vgtTeamHealthSorter,
       
   149     vgtSmallDamageTag,
       
   150     vgtSpeechBubble,
       
   151     vgtHealthTag,
       
   152     vgtExplosion,
       
   153     vgtSmokeTrace,
       
   154     vgtEvilTrace,
       
   155     vgtNote,
       
   156     vgtSmoothWindBar])) then
       
   157     
       
   158         exit;
       
   159 
       
   160 inc(VGCounter);
       
   161 New(gear);
       
   162 FillChar(gear^, sizeof(TVisualGear), 0);
       
   163 gear^.X:= real(X);
       
   164 gear^.Y:= real(Y);
       
   165 gear^.Kind := Kind;
       
   166 gear^.doStep:= doStepHandlers[Kind];
       
   167 gear^.State:= 0;
       
   168 gear^.Tint:= $FFFFFFFF;
       
   169 gear^.uid:= VGCounter;
       
   170 gear^.Layer:= 0;
       
   171 
       
   172 with gear^ do
       
   173     case Kind of
       
   174     vgtFlake:
       
   175                 begin
       
   176                 Timer:= 0;
       
   177                 tdX:= 0;
       
   178                 tdY:= 0;
       
   179                 Scale:= 1.0;
       
   180                 if SuddenDeathDmg then
       
   181                     begin
       
   182                     FrameTicks:= random(vobSDFrameTicks);
       
   183                     Frame:= random(vobSDFramesCount);
       
   184                     end
       
   185                 else
       
   186                     begin
       
   187                     FrameTicks:= random(vobFrameTicks);
       
   188                     Frame:= random(vobFramesCount);
       
   189                     end;
       
   190                 Angle:= random(360);
       
   191                 dx:= 0.0000038654705 * random(10000);
       
   192                 dy:= 0.000003506096 * random(7000);
       
   193                 if random(2) = 0 then
       
   194                     dx := -dx;
       
   195                 if SuddenDeathDmg then
       
   196                     dAngle:= (random(2) * 2 - 1) * (vobSDVelocity + random(vobSDVelocity)) / 1000
       
   197                 else
       
   198                     dAngle:= (random(2) * 2 - 1) * (vobVelocity + random(vobVelocity)) / 1000
       
   199                 end;
       
   200     vgtCloud:
       
   201                 begin
       
   202                 Frame:= random(4);
       
   203                 dx:= 0.5 + 0.1 * random(5); // how much the cloud will be affected by wind
       
   204                 timer:= random(4096);
       
   205                 Scale:= 1.0
       
   206                 end;
       
   207     vgtExplPart,
       
   208     vgtExplPart2:
       
   209                 begin
       
   210                 t:= random(1024);
       
   211                 sp:= 0.001 * (random(95) + 70);
       
   212                 dx:= hwFloat2Float(AngleSin(t)) * sp;
       
   213                 dy:= hwFloat2Float(AngleCos(t)) * sp;
       
   214                 if random(2) = 0 then
       
   215                     dx := -dx;
       
   216                 if random(2) = 0 then
       
   217                     dy := -dy;
       
   218                 Frame:= 7 - random(3);
       
   219                 FrameTicks:= cExplFrameTicks
       
   220                 end;
       
   221         vgtFire:
       
   222                 begin
       
   223                 t:= random(1024);
       
   224                 sp:= 0.001 * (random(85) + 95);
       
   225                 dx:= hwFloat2Float(AngleSin(t)) * sp;
       
   226                 dy:= hwFloat2Float(AngleCos(t)) * sp;
       
   227                 if random(2) = 0 then
       
   228                     dx := -dx;
       
   229                 if random(2) = 0 then
       
   230                     dy := -dy;
       
   231                 FrameTicks:= 650 + random(250);
       
   232                 Frame:= random(8)
       
   233                 end;
       
   234          vgtEgg:
       
   235                 begin
       
   236                 t:= random(1024);
       
   237                 sp:= 0.001 * (random(85) + 95);
       
   238                 dx:= hwFloat2Float(AngleSin(t)) * sp;
       
   239                 dy:= hwFloat2Float(AngleCos(t)) * sp;
       
   240                 if random(2) = 0 then
       
   241                     dx := -dx;
       
   242                 if random(2) = 0 then
       
   243                     dy := -dy;
       
   244                 FrameTicks:= 650 + random(250);
       
   245                 Frame:= 1
       
   246                 end;
       
   247         vgtShell: FrameTicks:= 500;
       
   248     vgtSmallDamageTag:
       
   249                 begin
       
   250                 gear^.FrameTicks:= 1100
       
   251                 end;
       
   252     vgtBubble:
       
   253                 begin
       
   254                 dx:= 0.0000038654705 * random(10000);
       
   255                 dy:= 0;
       
   256                 if random(2) = 0 then
       
   257                     dx := -dx;
       
   258                 FrameTicks:= 250 + random(1751);
       
   259                 Frame:= random(5)
       
   260                 end;
       
   261     vgtSteam:
       
   262                 begin
       
   263                 dx:= 0.0000038654705 * random(10000);
       
   264                 dy:= 0.001 * (random(85) + 95);
       
   265                 if random(2) = 0 then
       
   266                     dx := -dx;
       
   267                 Frame:= 7 - random(3);
       
   268                 FrameTicks:= cExplFrameTicks * 2;
       
   269                 end;
       
   270     vgtAmmo:
       
   271                 begin
       
   272                 alpha:= 1.0;
       
   273                 scale:= 1.0
       
   274                 end;
       
   275   vgtSmokeWhite,
       
   276   vgtSmoke:
       
   277                 begin
       
   278                 Scale:= 1.0;
       
   279                 dx:= 0.0002 * (random(45) + 10);
       
   280                 dy:= 0.0002 * (random(45) + 10);
       
   281                 if random(2) = 0 then
       
   282                     dx := -dx;
       
   283                 Frame:= 7 - random(2);
       
   284                 FrameTicks:= cExplFrameTicks * 2;
       
   285                 end;
       
   286   vgtDust:
       
   287                 begin
       
   288                 dx:= 0.005 * (random(15) + 10);
       
   289                 dy:= 0.001 * (random(40) + 20);
       
   290                 if random(2) = 0 then dx := -dx;
       
   291                 if random(2) = 0 then Tag:= 1
       
   292                 else Tag:= -1;
       
   293                 Frame:= 7 - random(2);
       
   294                 FrameTicks:= random(20) + 15;
       
   295                 end;
       
   296   vgtSplash:
       
   297                 begin
       
   298                 dx:= 0;
       
   299                 dy:= 0;
       
   300                 FrameTicks:= 740;
       
   301                 Frame:= 19;
       
   302                 Scale:= 0.75;
       
   303                 Timer:= 1;
       
   304                 end;
       
   305     vgtDroplet:
       
   306                 begin
       
   307                 dx:= 0.001 * (random(180) - 90);
       
   308                 dy:= -0.001 * (random(160) + 40);
       
   309                 FrameTicks:= 250 + random(1751);
       
   310                 Frame:= random(3)
       
   311                 end;
       
   312    vgtBeeTrace:
       
   313                 begin
       
   314                 FrameTicks:= 1000;
       
   315                 Frame:= random(16);
       
   316                 end;
       
   317     vgtSmokeRing:
       
   318                 begin
       
   319                 dx:= 0;
       
   320                 dy:= 0;
       
   321                 FrameTicks:= 600;
       
   322                 Timer:= 0;
       
   323                 Frame:= 0;
       
   324                 scale:= 0.6;
       
   325                 alpha:= 1;
       
   326                 angle:= random(360);
       
   327                 end;
       
   328      vgtFeather:
       
   329                 begin
       
   330                 t:= random(1024);
       
   331                 sp:= 0.001 * (random(85) + 95);
       
   332                 dx:= hwFloat2Float(AngleSin(t)) * sp;
       
   333                 dy:= hwFloat2Float(AngleCos(t)) * sp;
       
   334                 if random(2) = 0 then
       
   335                     dx := -dx;
       
   336                 if random(2) = 0 then
       
   337                     dy := -dy;
       
   338                 FrameTicks:= 650 + random(250);
       
   339                 Frame:= 1
       
   340                 end;
       
   341   vgtHealthTag:
       
   342                 begin
       
   343                 Frame:= 0;
       
   344                 Timer:= 1500;
       
   345                 dY:= -0.08;
       
   346                 dX:= 0;
       
   347                 //gear^.Z:= 2002;
       
   348                 end;
       
   349   vgtSmokeTrace,
       
   350   vgtEvilTrace:
       
   351                 begin
       
   352                 gear^.X:= gear^.X - 16;
       
   353                 gear^.Y:= gear^.Y - 16;
       
   354                 gear^.State:= 8;
       
   355                 //gear^.Z:= cSmokeZ
       
   356                 end;
       
   357 vgtBigExplosion:
       
   358                 begin
       
   359                 gear^.Angle:= random(360);
       
   360                 end;
       
   361       vgtChunk:
       
   362                 begin
       
   363                 gear^.Frame:= random(4);
       
   364                 t:= random(1024);
       
   365                 sp:= 0.001 * (random(85) + 47);
       
   366                 dx:= hwFloat2Float(AngleSin(t)) * sp;
       
   367                 dy:= hwFloat2Float(AngleCos(t)) * sp * -2;
       
   368                 if random(2) = 0 then
       
   369                     dx := -dx;
       
   370                 end;
       
   371       vgtNote: 
       
   372                 begin
       
   373                 dx:= 0.005 * (random(15) + 10);
       
   374                 dy:= -0.001 * (random(40) + 20);
       
   375                 if random(2) = 0 then
       
   376                     dx := -dx;
       
   377                 Frame:= random(4);
       
   378                 FrameTicks:= random(2000) + 1500;
       
   379                 end;
       
   380   vgtBulletHit:
       
   381                 begin
       
   382                 dx:= 0;
       
   383                 dy:= 0;
       
   384                 FrameTicks:= 350;
       
   385                 Frame:= 7;
       
   386                 Angle:= 0;
       
   387                 end;
       
   388 vgtSmoothWindBar: 
       
   389                 begin
       
   390                 Angle:= hwFloat2Float(cMaxWindSpeed)*2 / 1440; // seems rate below is supposed to change wind bar at 1px per 10ms. Max time, 1440ms. This tries to match the rate of change
       
   391                 Tag:= hwRound(cWindSpeed * 72 / cMaxWindSpeed);
       
   392                 end;
       
   393  vgtStraightShot:
       
   394                 begin
       
   395                 Angle:= 0;
       
   396                 Scale:= 1.0;
       
   397                 dx:= 0.001 * random(45);
       
   398                 dy:= 0.001 * (random(20) + 25);
       
   399                 State:= ord(sprHealth);
       
   400                 if random(2) = 0 then
       
   401                     dx := -dx;
       
   402                 Frame:= 0;
       
   403                 FrameTicks:= random(750) + 1250;
       
   404                 State:= ord(sprSnowDust);
       
   405                 end;
       
   406         end;
       
   407 
       
   408 if State <> 0 then
       
   409     gear^.State:= State;
       
   410 
       
   411 case Gear^.Kind of
       
   412     vgtFlake: if cFlattenFlakes then
       
   413         gear^.Layer:= 0
       
   414               else if random(3) = 0 then 
       
   415                   begin
       
   416                   gear^.Scale:= 0.5;
       
   417                   gear^.Layer:= 0   // 33% - far back
       
   418                   end
       
   419               else if random(3) = 0 then
       
   420                   begin
       
   421                   gear^.Scale:= 0.8;
       
   422                   gear^.Layer:= 4   // 22% - mid-distance
       
   423                   end
       
   424               else if random(3) <> 0 then
       
   425                   gear^.Layer:= 5  // 30% - just behind land
       
   426               else if random(2) = 0 then
       
   427                   gear^.Layer:= 6   // 7% - just in front of land
       
   428               else
       
   429                   begin
       
   430                   gear^.Scale:= 1.5;
       
   431                   gear^.Layer:= 2;  // 7% - close up
       
   432                   end;
       
   433 
       
   434     vgtCloud: if cFlattenClouds then gear^.Layer:= 5
       
   435               else if random(3) = 0 then
       
   436                   begin
       
   437                   gear^.Scale:= 0.25;
       
   438                   gear^.Layer:= 0
       
   439                   end
       
   440               else if random(2) = 0 then
       
   441                   gear^.Layer:= 5
       
   442               else
       
   443                   begin
       
   444                   gear^.Scale:= 0.4;
       
   445                   gear^.Layer:= 4
       
   446                   end;
       
   447 
       
   448     // 0: this layer is very distant in the background when in stereo
       
   449     vgtTeamHealthSorter,
       
   450     vgtSmoothWindBar: gear^.Layer:= 0;
       
   451 
       
   452 
       
   453     // 1: this layer is on the land level (which is close but behind the screen plane) when stereo
       
   454     vgtSmokeTrace,
       
   455     vgtEvilTrace,
       
   456     vgtLineTrail,
       
   457     vgtSmoke,
       
   458     vgtSmokeWhite,
       
   459     vgtDust,
       
   460     vgtFire,
       
   461     vgtSplash,
       
   462     vgtDroplet,
       
   463     vgtBubble: gear^.Layer:= 1;
       
   464 
       
   465     // 3: this layer is on the screen plane (depth = 0) when stereo
       
   466     vgtSpeechBubble,
       
   467     vgtSmallDamageTag,
       
   468     vgtHealthTag,
       
   469     vgtStraightShot,
       
   470     vgtChunk: gear^.Layer:= 3;
       
   471 
       
   472     // 2: this layer is outside the screen when stereo
       
   473     vgtExplosion,
       
   474     vgtBigExplosion,
       
   475     vgtExplPart,
       
   476     vgtExplPart2,
       
   477     vgtSteam,
       
   478     vgtAmmo,
       
   479     vgtShell,
       
   480     vgtFeather,
       
   481     vgtEgg,
       
   482     vgtBeeTrace,
       
   483     vgtSmokeRing,
       
   484     vgtNote,
       
   485     vgtBulletHit,
       
   486     vgtCircle: gear^.Layer:= 2
       
   487 end;
       
   488 
       
   489 if VisualGearLayers[gear^.Layer] <> nil then
       
   490     begin
       
   491     VisualGearLayers[gear^.Layer]^.PrevGear:= gear;
       
   492     gear^.NextGear:= VisualGearLayers[gear^.Layer]
       
   493     end;
       
   494 VisualGearLayers[gear^.Layer]:= gear;
       
   495 
       
   496 AddVisualGear:= gear;
       
   497 end;
       
   498 
       
   499 procedure DeleteVisualGear(Gear: PVisualGear);
       
   500 begin
       
   501     FreeTexture(Gear^.Tex);
       
   502     Gear^.Tex:= nil;
       
   503 
       
   504     if Gear^.NextGear <> nil then
       
   505         Gear^.NextGear^.PrevGear:= Gear^.PrevGear;
       
   506     if Gear^.PrevGear <> nil then
       
   507         Gear^.PrevGear^.NextGear:= Gear^.NextGear
       
   508     else
       
   509         VisualGearLayers[Gear^.Layer]:= Gear^.NextGear;
       
   510 
       
   511     if lastVisualGearByUID = Gear then
       
   512         lastVisualGearByUID:= nil;
       
   513 
       
   514     Dispose(Gear);
       
   515 end;
       
   516 
    71 
   517 procedure ProcessVisualGears(Steps: Longword);
    72 procedure ProcessVisualGears(Steps: Longword);
   518 var Gear, t: PVisualGear;
    73 var Gear, t: PVisualGear;
   519     i: LongWord;
    74     i: LongWord;
   520 begin
    75 begin
   898             end
   453             end
   899         end;
   454         end;
   900     end;
   455     end;
   901 end;
   456 end;
   902 
   457 
   903 function  VisualGearByUID(uid : Longword) : PVisualGear;
       
   904 var vg: PVisualGear;
       
   905     i: LongWord;
       
   906 begin
       
   907 VisualGearByUID:= nil;
       
   908 if uid = 0 then
       
   909     exit;
       
   910 if (lastVisualGearByUID <> nil) and (lastVisualGearByUID^.uid = uid) then
       
   911     begin
       
   912     VisualGearByUID:= lastVisualGearByUID;
       
   913     exit
       
   914     end;
       
   915 // search in an order that is more likely to return layers they actually use.  Could perhaps track statistically AddVisualGear in uScript, since that is most likely the ones they want
       
   916 for i:= 2 to 5 do
       
   917     begin
       
   918     vg:= VisualGearLayers[i mod 4];
       
   919     while vg <> nil do
       
   920         begin
       
   921         if vg^.uid = uid then
       
   922             begin
       
   923             lastVisualGearByUID:= vg;
       
   924             VisualGearByUID:= vg;
       
   925             exit
       
   926             end;
       
   927         vg:= vg^.NextGear
       
   928         end
       
   929     end
       
   930 end;
       
   931 
       
   932 procedure AddClouds;
   458 procedure AddClouds;
   933 var i: LongInt;
   459 var i: LongInt;
   934 begin
   460 begin
   935 for i:= 0 to cCloudsNumber - 1 do
   461 for i:= 0 to cCloudsNumber - 1 do
   936     AddVisualGear(cLeftScreenBorder + i * LongInt(cScreenSpace div (cCloudsNumber + 1)), LAND_HEIGHT-1184, vgtCloud)
   462     AddVisualGear(cLeftScreenBorder + i * LongInt(cScreenSpace div (cCloudsNumber + 1)), LAND_HEIGHT-1184, vgtCloud)