--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uVisualGearsList.pas Thu Jun 27 15:48:30 2013 +0400
@@ -0,0 +1,462 @@
+(*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *)
+
+{$INCLUDE "options.inc"}
+
+unit uVisualGearsList;
+interface
+uses uTypes;
+
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear;
+procedure DeleteVisualGear(Gear: PVisualGear);
+function VisualGearByUID(uid : Longword) : PVisualGear;
+
+const
+ cExplFrameTicks = 110;
+
+var VGCounter: LongWord;
+ VisualGearLayers: array[0..6] of PVisualGear;
+
+implementation
+uses uFloat, uVariables, uConsts, uTextures, uVisualGearsHandlers;
+
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
+begin
+ AddVisualGear:= AddVisualGear(X, Y, Kind, 0, false);
+end;
+
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
+begin
+ AddVisualGear:= AddVisualGear(X, Y, Kind, State, false);
+end;
+
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear;
+var gear: PVisualGear;
+ t: Longword;
+ sp: real;
+begin
+AddVisualGear:= nil;
+if ((GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet)) or fastScrolling) and // we are scrolling now
+ ((Kind <> vgtCloud) and (not Critical)) then
+ exit;
+
+if ((cReducedQuality and rqAntiBoom) <> 0) and
+ (not Critical) and
+ (not (Kind in
+ [vgtTeamHealthSorter,
+ vgtSmallDamageTag,
+ vgtSpeechBubble,
+ vgtHealthTag,
+ vgtExplosion,
+ vgtSmokeTrace,
+ vgtEvilTrace,
+ vgtNote,
+ vgtSmoothWindBar])) then
+
+ exit;
+
+inc(VGCounter);
+New(gear);
+FillChar(gear^, sizeof(TVisualGear), 0);
+gear^.X:= real(X);
+gear^.Y:= real(Y);
+gear^.Kind := Kind;
+gear^.doStep:= doStepHandlers[Kind];
+gear^.State:= 0;
+gear^.Tint:= $FFFFFFFF;
+gear^.uid:= VGCounter;
+gear^.Layer:= 0;
+
+with gear^ do
+ case Kind of
+ vgtFlake:
+ begin
+ Timer:= 0;
+ tdX:= 0;
+ tdY:= 0;
+ Scale:= 1.0;
+ if SuddenDeathDmg then
+ begin
+ FrameTicks:= random(vobSDFrameTicks);
+ Frame:= random(vobSDFramesCount);
+ end
+ else
+ begin
+ FrameTicks:= random(vobFrameTicks);
+ Frame:= random(vobFramesCount);
+ end;
+ Angle:= random(360);
+ dx:= 0.0000038654705 * random(10000);
+ dy:= 0.000003506096 * random(7000);
+ if random(2) = 0 then
+ dx := -dx;
+ if SuddenDeathDmg then
+ dAngle:= (random(2) * 2 - 1) * (vobSDVelocity + random(vobSDVelocity)) / 1000
+ else
+ dAngle:= (random(2) * 2 - 1) * (vobVelocity + random(vobVelocity)) / 1000
+ end;
+ vgtCloud:
+ begin
+ Frame:= random(4);
+ dx:= 0.5 + 0.1 * random(5); // how much the cloud will be affected by wind
+ timer:= random(4096);
+ Scale:= 1.0
+ end;
+ vgtExplPart,
+ vgtExplPart2:
+ begin
+ t:= random(1024);
+ sp:= 0.001 * (random(95) + 70);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp;
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ Frame:= 7 - random(3);
+ FrameTicks:= cExplFrameTicks
+ end;
+ vgtFire:
+ begin
+ t:= random(1024);
+ sp:= 0.001 * (random(85) + 95);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp;
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= 650 + random(250);
+ Frame:= random(8)
+ end;
+ vgtEgg:
+ begin
+ t:= random(1024);
+ sp:= 0.001 * (random(85) + 95);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp;
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= 650 + random(250);
+ Frame:= 1
+ end;
+ vgtShell: FrameTicks:= 500;
+ vgtSmallDamageTag:
+ begin
+ gear^.FrameTicks:= 1100
+ end;
+ vgtBubble:
+ begin
+ dx:= 0.0000038654705 * random(10000);
+ dy:= 0;
+ if random(2) = 0 then
+ dx := -dx;
+ FrameTicks:= 250 + random(1751);
+ Frame:= random(5)
+ end;
+ vgtSteam:
+ begin
+ dx:= 0.0000038654705 * random(10000);
+ dy:= 0.001 * (random(85) + 95);
+ if random(2) = 0 then
+ dx := -dx;
+ Frame:= 7 - random(3);
+ FrameTicks:= cExplFrameTicks * 2;
+ end;
+ vgtAmmo:
+ begin
+ alpha:= 1.0;
+ scale:= 1.0
+ end;
+ vgtSmokeWhite,
+ vgtSmoke:
+ begin
+ Scale:= 1.0;
+ dx:= 0.0002 * (random(45) + 10);
+ dy:= 0.0002 * (random(45) + 10);
+ if random(2) = 0 then
+ dx := -dx;
+ Frame:= 7 - random(2);
+ FrameTicks:= cExplFrameTicks * 2;
+ end;
+ vgtDust:
+ begin
+ dx:= 0.005 * (random(15) + 10);
+ dy:= 0.001 * (random(40) + 20);
+ if random(2) = 0 then dx := -dx;
+ if random(2) = 0 then Tag:= 1
+ else Tag:= -1;
+ Frame:= 7 - random(2);
+ FrameTicks:= random(20) + 15;
+ end;
+ vgtSplash:
+ begin
+ dx:= 0;
+ dy:= 0;
+ FrameTicks:= 740;
+ Frame:= 19;
+ Scale:= 0.75;
+ Timer:= 1;
+ end;
+ vgtDroplet:
+ begin
+ dx:= 0.001 * (random(180) - 90);
+ dy:= -0.001 * (random(160) + 40);
+ FrameTicks:= 250 + random(1751);
+ Frame:= random(3)
+ end;
+ vgtBeeTrace:
+ begin
+ FrameTicks:= 1000;
+ Frame:= random(16);
+ end;
+ vgtSmokeRing:
+ begin
+ dx:= 0;
+ dy:= 0;
+ FrameTicks:= 600;
+ Timer:= 0;
+ Frame:= 0;
+ scale:= 0.6;
+ alpha:= 1;
+ angle:= random(360);
+ end;
+ vgtFeather:
+ begin
+ t:= random(1024);
+ sp:= 0.001 * (random(85) + 95);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp;
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= 650 + random(250);
+ Frame:= 1
+ end;
+ vgtHealthTag:
+ begin
+ Frame:= 0;
+ Timer:= 1500;
+ dY:= -0.08;
+ dX:= 0;
+ //gear^.Z:= 2002;
+ end;
+ vgtSmokeTrace,
+ vgtEvilTrace:
+ begin
+ gear^.X:= gear^.X - 16;
+ gear^.Y:= gear^.Y - 16;
+ gear^.State:= 8;
+ //gear^.Z:= cSmokeZ
+ end;
+vgtBigExplosion:
+ begin
+ gear^.Angle:= random(360);
+ end;
+ vgtChunk:
+ begin
+ gear^.Frame:= random(4);
+ t:= random(1024);
+ sp:= 0.001 * (random(85) + 47);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp * -2;
+ if random(2) = 0 then
+ dx := -dx;
+ end;
+ vgtNote:
+ begin
+ dx:= 0.005 * (random(15) + 10);
+ dy:= -0.001 * (random(40) + 20);
+ if random(2) = 0 then
+ dx := -dx;
+ Frame:= random(4);
+ FrameTicks:= random(2000) + 1500;
+ end;
+ vgtBulletHit:
+ begin
+ dx:= 0;
+ dy:= 0;
+ FrameTicks:= 350;
+ Frame:= 7;
+ Angle:= 0;
+ end;
+vgtSmoothWindBar:
+ begin
+ 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
+ Tag:= hwRound(cWindSpeed * 72 / cMaxWindSpeed);
+ end;
+ vgtStraightShot:
+ begin
+ Angle:= 0;
+ Scale:= 1.0;
+ dx:= 0.001 * random(45);
+ dy:= 0.001 * (random(20) + 25);
+ State:= ord(sprHealth);
+ if random(2) = 0 then
+ dx := -dx;
+ Frame:= 0;
+ FrameTicks:= random(750) + 1250;
+ State:= ord(sprSnowDust);
+ end;
+ end;
+
+if State <> 0 then
+ gear^.State:= State;
+
+case Gear^.Kind of
+ vgtFlake: if cFlattenFlakes then
+ gear^.Layer:= 0
+ else if random(3) = 0 then
+ begin
+ gear^.Scale:= 0.5;
+ gear^.Layer:= 0 // 33% - far back
+ end
+ else if random(3) = 0 then
+ begin
+ gear^.Scale:= 0.8;
+ gear^.Layer:= 4 // 22% - mid-distance
+ end
+ else if random(3) <> 0 then
+ gear^.Layer:= 5 // 30% - just behind land
+ else if random(2) = 0 then
+ gear^.Layer:= 6 // 7% - just in front of land
+ else
+ begin
+ gear^.Scale:= 1.5;
+ gear^.Layer:= 2; // 7% - close up
+ end;
+
+ vgtCloud: if cFlattenClouds then gear^.Layer:= 5
+ else if random(3) = 0 then
+ begin
+ gear^.Scale:= 0.25;
+ gear^.Layer:= 0
+ end
+ else if random(2) = 0 then
+ gear^.Layer:= 5
+ else
+ begin
+ gear^.Scale:= 0.4;
+ gear^.Layer:= 4
+ end;
+
+ // 0: this layer is very distant in the background when in stereo
+ vgtTeamHealthSorter,
+ vgtSmoothWindBar: gear^.Layer:= 0;
+
+
+ // 1: this layer is on the land level (which is close but behind the screen plane) when stereo
+ vgtSmokeTrace,
+ vgtEvilTrace,
+ vgtLineTrail,
+ vgtSmoke,
+ vgtSmokeWhite,
+ vgtDust,
+ vgtFire,
+ vgtSplash,
+ vgtDroplet,
+ vgtBubble: gear^.Layer:= 1;
+
+ // 3: this layer is on the screen plane (depth = 0) when stereo
+ vgtSpeechBubble,
+ vgtSmallDamageTag,
+ vgtHealthTag,
+ vgtStraightShot,
+ vgtChunk: gear^.Layer:= 3;
+
+ // 2: this layer is outside the screen when stereo
+ vgtExplosion,
+ vgtBigExplosion,
+ vgtExplPart,
+ vgtExplPart2,
+ vgtSteam,
+ vgtAmmo,
+ vgtShell,
+ vgtFeather,
+ vgtEgg,
+ vgtBeeTrace,
+ vgtSmokeRing,
+ vgtNote,
+ vgtBulletHit,
+ 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;
+
+procedure DeleteVisualGear(Gear: PVisualGear);
+begin
+ FreeTexture(Gear^.Tex);
+ Gear^.Tex:= nil;
+
+ if Gear^.NextGear <> nil then
+ Gear^.NextGear^.PrevGear:= Gear^.PrevGear;
+ if Gear^.PrevGear <> nil then
+ Gear^.PrevGear^.NextGear:= Gear^.NextGear
+ else
+ VisualGearLayers[Gear^.Layer]:= Gear^.NextGear;
+
+ if lastVisualGearByUID = Gear then
+ lastVisualGearByUID:= nil;
+
+ Dispose(Gear);
+end;
+
+function VisualGearByUID(uid : Longword) : PVisualGear;
+var vg: PVisualGear;
+ i: LongWord;
+begin
+VisualGearByUID:= nil;
+if uid = 0 then
+ exit;
+if (lastVisualGearByUID <> nil) and (lastVisualGearByUID^.uid = uid) then
+ begin
+ VisualGearByUID:= lastVisualGearByUID;
+ exit
+ end;
+// 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
+ vg:= VisualGearLayers[i mod 4];
+ while vg <> nil do
+ begin
+ if vg^.uid = uid then
+ begin
+ lastVisualGearByUID:= vg;
+ VisualGearByUID:= vg;
+ exit
+ end;
+ vg:= vg^.NextGear
+ end
+ end
+end;
+
+
+end.