hedgewars/uVisualGears.pas
changeset 6179 b529f88d37d0
parent 6117 2a4829172a29
child 6184 335ece2bce9c
--- a/hedgewars/uVisualGears.pas	Sat Oct 22 02:41:59 2011 +0200
+++ b/hedgewars/uVisualGears.pas	Sat Oct 22 00:49:55 2011 -0400
@@ -145,6 +145,7 @@
 gear^.State:= 0;
 gear^.Tint:= $FFFFFFFF;
 gear^.uid:= VGCounter;
+gear^.Layer:= 0;
 
 with gear^ do
     case Kind of
@@ -336,19 +337,14 @@
 if State <> 0 then gear^.State:= State;
 
 case Gear^.Kind of
+    vgtFlake: if random(2) = 0 then gear^.Layer:= 0
+              else gear^.Layer:= random(3)+1;
+
     // 0: this layer is very distant in the background when stereo
     vgtTeamHealthSorter,
     vgtSmoothWindBar,
-    vgtFlake, 
-    vgtCloud: begin
-              if VisualGearsLayer0 <> nil then
-                  begin
-                  VisualGearsLayer0^.PrevGear:= gear;
-                  gear^.NextGear:= VisualGearsLayer0
-                  end;
-              gear^.Layer:= 0;
-              VisualGearsLayer0:= gear
-              end; 
+    vgtCloud: gear^.Layer:= 0;
+
     // 1: this layer is on the land level (which is close but behind the screen plane) when stereo
     vgtSmokeTrace,
     vgtEvilTrace,
@@ -359,29 +355,15 @@
     vgtFire,
     vgtSplash,
     vgtDroplet,
-    vgtBubble: begin
-              if VisualGearsLayer1 <> nil then
-                  begin
-                  VisualGearsLayer1^.PrevGear:= gear;
-                  gear^.NextGear:= VisualGearsLayer1
-                  end;
-              gear^.Layer:= 1;
-              VisualGearsLayer1:= gear
-              end; 
+    vgtBubble: gear^.Layer:= 1;
+
     // 3: this layer is on the screen plane (depth = 0) when stereo
     vgtSpeechBubble,
     vgtSmallDamageTag,
     vgtHealthTag,
     vgtStraightShot,
-    vgtChunk: begin
-              if VisualGearsLayer3 <> nil then
-                  begin
-                  VisualGearsLayer3^.PrevGear:= gear;
-                  gear^.NextGear:= VisualGearsLayer3
-                  end;
-              gear^.Layer:= 3;
-              VisualGearsLayer3:= gear
-              end; 
+    vgtChunk: gear^.Layer:= 3;
+
     // 2: this layer is outside the screen when stereo
     vgtExplosion,
     vgtBigExplosion,
@@ -396,17 +378,16 @@
     vgtSmokeRing,
     vgtNote,
     vgtBulletHit,
-    vgtCircle: begin
-              if VisualGearsLayer2 <> nil then
-                  begin
-                  VisualGearsLayer2^.PrevGear:= gear;
-                  gear^.NextGear:= VisualGearsLayer2
-                  end;
-              gear^.Layer:= 2;
-              VisualGearsLayer2:= gear
-              end; 
+    vgtCircle: gear^.Layer:= 2
 end;
 
+if VisualGearLayers[gear^.Layer] <> nil then
+    begin
+    VisualGearLayers[gear^.Layer]^.PrevGear:= gear;
+    gear^.NextGear:= VisualGearLayers[gear^.Layer]
+    end;
+VisualGearLayers[gear^.Layer]:= gear;
+
 AddVisualGear:= gear;
 end;
 
@@ -418,13 +399,7 @@
 
     if Gear^.NextGear <> nil then Gear^.NextGear^.PrevGear:= Gear^.PrevGear;
     if Gear^.PrevGear <> nil then Gear^.PrevGear^.NextGear:= Gear^.NextGear
-    else
-        case Gear^.Layer of
-            0: VisualGearsLayer0:= Gear^.NextGear;
-            1: VisualGearsLayer1:= Gear^.NextGear;
-            2: VisualGearsLayer2:= Gear^.NextGear;
-            3: VisualGearsLayer3:= Gear^.NextGear;
-        end;
+    else VisualGearLayers[Gear^.Layer]:= Gear^.NextGear;
 
     if lastVisualGearByUID = Gear then lastVisualGearByUID:= nil;
 
@@ -433,37 +408,20 @@
 
 procedure ProcessVisualGears(Steps: Longword);
 var Gear, t: PVisualGear;
+    i: LongWord;
 begin
 if Steps = 0 then exit;
 
-t:= VisualGearsLayer0;
-while t <> nil do
-      begin
-      Gear:= t;
-      t:= Gear^.NextGear;
-      Gear^.doStep(Gear, Steps)
-      end;
-t:= VisualGearsLayer1;
-while t <> nil do
-      begin
-      Gear:= t;
-      t:= Gear^.NextGear;
-      Gear^.doStep(Gear, Steps)
-      end;
-t:= VisualGearsLayer2;
-while t <> nil do
-      begin
-      Gear:= t;
-      t:= Gear^.NextGear;
-      Gear^.doStep(Gear, Steps)
-      end;
-t:= VisualGearsLayer3;
-while t <> nil do
-      begin
-      Gear:= t;
-      t:= Gear^.NextGear;
-      Gear^.doStep(Gear, Steps)
-      end
+for i:= 0 to 3 do
+    begin
+    t:= VisualGearLayers[i];
+    while t <> nil do
+          begin
+          Gear:= t;
+          t:= Gear^.NextGear;
+          Gear^.doStep(Gear, Steps)
+          end;
+    end
 end;
 
 procedure KickFlakes(Radius, X, Y: LongInt);
@@ -471,7 +429,26 @@
     dmg: LongInt;
 begin
 if (vobCount = 0) or (vobCount > 200) then exit;
-t:= VisualGearsLayer0;
+t:= VisualGearLayers[1];
+while t <> nil do
+      begin
+      Gear:= t;
+      if Gear^.Kind = vgtFlake then
+          begin
+          // Damage calc from doMakeExplosion
+          dmg:= Min(101, Radius + cHHRadius div 2 - LongInt(abs(round(Gear^.X) - X) + abs(round(Gear^.Y) - Y)) div 5);
+          if dmg > 1 then
+              begin
+              Gear^.tdX:= 0.02 * dmg + 0.01;
+              if Gear^.X - X < 0 then Gear^.tdX := -Gear^.tdX;
+              Gear^.tdY:= 0.02 * dmg + 0.01;
+              if Gear^.Y - Y < 0 then Gear^.tdY := -Gear^.tdY;
+              Gear^.Timer:= 200
+              end
+          end;
+      t:= Gear^.NextGear
+      end;
+t:= VisualGearLayers[3];
 while t <> nil do
       begin
       Gear:= t;
@@ -501,21 +478,21 @@
 case Layer of
     // this layer is very distant in the background when stereo
     0: begin
-       Gear:= VisualGearsLayer0;
+       Gear:= VisualGearLayers[0];
        while Gear <> nil do
            begin
            if Gear^.Tint <> $FFFFFFFF then Tint(Gear^.Tint);
            case Gear^.Kind of
                vgtFlake: if SuddenDeathDmg then
                              if vobSDVelocity = 0 then
-                                 DrawSprite(sprSDFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame)
+                                 DrawTextureF(SpritesData[sprSDFlake].Texture, 0.5, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, SpritesData[sprFlake].Width, SpritesData[sprFlake].Height)
                              else
-                                 DrawRotatedF(sprSDFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, Gear^.Angle)
+                                 DrawRotatedTextureF(SpritesData[sprSDFlake].Texture, 0.5, 0, 0, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, SpritesData[sprFlake].Width, SpritesData[sprFlake].Height, Gear^.Angle)
                          else
                              if vobVelocity = 0 then
-                                 DrawSprite(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame)
+                                 DrawTextureF(SpritesData[sprFlake].Texture, 0.5, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, SpritesData[sprFlake].Width, SpritesData[sprFlake].Height)
                              else
-                                 DrawRotatedF(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, Gear^.Angle);
+                                 DrawRotatedTextureF(SpritesData[sprFlake].Texture, 0.5, 0, 0, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, SpritesData[sprFlake].Width, SpritesData[sprFlake].Height, Gear^.Angle);
                vgtCloud: if SuddenDeathDmg then
                              DrawSprite(sprSDCloud, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame)
                          else
@@ -527,12 +504,22 @@
        end;
     // this layer is on the land level (which is close but behind the screen plane) when stereo
     1: begin
-       Gear:= VisualGearsLayer1;
+       Gear:= VisualGearLayers[1];
        while Gear <> nil do
           begin
           //tinted:= false;
           if Gear^.Tint <> $FFFFFFFF then Tint(Gear^.Tint);
           case Gear^.Kind of
+              vgtFlake: if SuddenDeathDmg then
+                             if vobSDVelocity = 0 then
+                                 DrawSprite(sprSDFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame)
+                             else
+                                 DrawRotatedF(sprSDFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, Gear^.Angle)
+                         else
+                             if vobVelocity = 0 then
+                                 DrawSprite(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame)
+                             else
+                                 DrawRotatedF(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, Gear^.Angle);
               vgtSmokeTrace: if Gear^.State < 8 then DrawSprite(sprSmokeTrace, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.State);
               vgtEvilTrace: if Gear^.State < 8 then DrawSprite(sprEvilTrace, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.State);
               vgtLineTrail: DrawLine(Gear^.X, Gear^.Y, Gear^.dX, Gear^.dY, 1.0, $FF, min(Gear^.Timer, $C0), min(Gear^.Timer, $80), min(Gear^.Timer, $FF));
@@ -566,12 +553,22 @@
        end;
     // this layer is on the screen plane (depth = 0) when stereo
     3: begin
-       Gear:= VisualGearsLayer3;
+       Gear:= VisualGearLayers[3];
        while Gear <> nil do
            begin
            tinted:= false;
            if Gear^.Tint <> $FFFFFFFF then Tint(Gear^.Tint);
            case Gear^.Kind of
+              vgtFlake: if SuddenDeathDmg then
+                             if vobSDVelocity = 0 then
+                                 DrawSprite(sprSDFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame)
+                             else
+                                 DrawRotatedF(sprSDFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, Gear^.Angle)
+                         else
+                             if vobVelocity = 0 then
+                                 DrawSprite(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame)
+                             else
+                                 DrawRotatedF(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, Gear^.Angle);
                vgtSpeechBubble: begin
                                 if (Gear^.Tex <> nil) and (((Gear^.State = 0) and (Gear^.Hedgehog^.Team <> CurrentTeam)) or (Gear^.State = 1)) then
                                     begin
@@ -610,7 +607,7 @@
        end;
     // this layer is outside the screen when stereo
     2: begin
-       Gear:= VisualGearsLayer2;
+       Gear:= VisualGearLayers[2];
        while Gear <> nil do
            begin
            tinted:= false;
@@ -668,6 +665,16 @@
                    vgtBulletHit: DrawRotatedF(sprBulletHit, round(Gear^.X) + WorldDx - 0, round(Gear^.Y) + WorldDy - 0, 7 - (Gear^.FrameTicks div 50), 1, Gear^.Angle);
                end;
            case Gear^.Kind of
+               vgtFlake: if SuddenDeathDmg then
+                             if vobSDVelocity = 0 then
+                                 DrawTextureF(SpritesData[sprSDFlake].Texture, 1.5, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, SpritesData[sprFlake].Width, SpritesData[sprFlake].Height)
+                             else
+                                 DrawRotatedTextureF(SpritesData[sprSDFlake].Texture, 1.5, 0, 0, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, SpritesData[sprFlake].Width, SpritesData[sprFlake].Height, Gear^.Angle)
+                         else
+                             if vobVelocity = 0 then
+                                 DrawTextureF(SpritesData[sprFlake].Texture, 1.5, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, SpritesData[sprFlake].Width, SpritesData[sprFlake].Height)
+                             else
+                                 DrawRotatedTextureF(SpritesData[sprFlake].Texture, 1.5, 0, 0, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, SpritesData[sprFlake].Width, SpritesData[sprFlake].Height, Gear^.Angle);
                vgtCircle: if gear^.Angle = 1 then
                               begin
                               tmp:= Gear^.State / 100;
@@ -684,6 +691,7 @@
 
 function  VisualGearByUID(uid : Longword) : PVisualGear;
 var vg: PVisualGear;
+    i: LongWord;
 begin
 VisualGearByUID:= nil;
 if uid = 0 then exit;
@@ -692,49 +700,20 @@
     VisualGearByUID:= lastVisualGearByUID;
     exit
     end;
-vg:= VisualGearsLayer0;
-while vg <> nil do
+// 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
+for i:= 2 to 5 do
     begin
-    if vg^.uid = uid then
-        begin
-        lastVisualGearByUID:= vg;
-        VisualGearByUID:= vg;
-        exit
-        end;
-    vg:= vg^.NextGear
-    end;
-vg:= VisualGearsLayer1;
-while vg <> nil do
-    begin
-    if vg^.uid = uid then
+    vg:= VisualGearLayers[i mod 4];
+    while vg <> nil do
         begin
-        lastVisualGearByUID:= vg;
-        VisualGearByUID:= vg;
-        exit
-        end;
-    vg:= vg^.NextGear
-    end;
-vg:= VisualGearsLayer2;
-while vg <> nil do
-    begin
-    if vg^.uid = uid then
-        begin
-        lastVisualGearByUID:= vg;
-        VisualGearByUID:= vg;
-        exit
-        end;
-    vg:= vg^.NextGear
-    end;
-vg:= VisualGearsLayer3;
-while vg <> nil do
-    begin
-    if vg^.uid = uid then
-        begin
-        lastVisualGearByUID:= vg;
-        VisualGearByUID:= vg;
-        exit
-        end;
-    vg:= vg^.NextGear
+        if vg^.uid = uid then
+    	    begin
+    	    lastVisualGearByUID:= vg;
+    	    VisualGearByUID:= vg;
+    	    exit
+    	    end;
+        vg:= vg^.NextGear
+        end
     end
 end;
 
@@ -750,7 +729,7 @@
     vg, tmp: PVisualGear;
 begin
 if cCloudsNumber = cSDCloudsNumber then exit;
-vg:= VisualGearsLayer0;
+vg:= VisualGearLayers[0];
 while vg <> nil do
     if vg^.Kind = vgtCloud then
         begin
@@ -782,15 +761,18 @@
 begin
 if (cReducedQuality and rqKillFlakes) <> 0 then exit;
 if vobCount = vobSDCount then exit;
-vg:= VisualGearsLayer0;
-while vg <> nil do
-    if vg^.Kind = vgtFlake then
+for i:= 0 to 3 do
+    begin
+    vg:= VisualGearLayers[i];
+    while vg <> nil do
+        if vg^.Kind = vgtFlake then
         begin
         tmp:= vg^.NextGear;
         DeleteVisualGear(vg);
         vg:= tmp
         end
-    else vg:= vg^.NextGear;
+        else vg:= vg^.NextGear;
+    end;
 if ((GameFlags and gfBorder) <> 0) or ((Theme <> 'Snow') and (Theme <> 'Christmas')) then
     for i:= 0 to Pred(vobSDCount * cScreenSpace div LAND_WIDTH) do
         AddVisualGear(cLeftScreenBorder + random(cScreenSpace), random(1024+200) - 100 + LAND_HEIGHT, vgtFlake)
@@ -800,19 +782,17 @@
 end;
 
 procedure initModule;
+var i: LongWord;
 begin
-    VisualGearsLayer0:= nil;
-    VisualGearsLayer1:= nil;
-    VisualGearsLayer2:= nil;
-    VisualGearsLayer3:= nil;
+for i:= 0 to 3 do
+    VisualGearLayers[i]:= nil;
 end;
 
 procedure freeModule;
+var i: LongWord;
 begin
-    while VisualGearsLayer0 <> nil do DeleteVisualGear(VisualGearsLayer0);
-    while VisualGearsLayer1 <> nil do DeleteVisualGear(VisualGearsLayer1);
-    while VisualGearsLayer2 <> nil do DeleteVisualGear(VisualGearsLayer2);
-    while VisualGearsLayer3 <> nil do DeleteVisualGear(VisualGearsLayer3);
+for i:= 0 to 3 do
+    while VisualGearLayers[i] <> nil do DeleteVisualGear(VisualGearLayers[i]);
 end;
 
 end.