# HG changeset patch # User unc0rr # Date 1372333710 -14400 # Node ID bb9ad6a5f625d03910e64aab8723301500451312 # Parent 8e8b908970c23f42b8bf805ebfc5d9cc5ce043c8 oops, forgot this file diff -r 8e8b908970c2 -r bb9ad6a5f625 hedgewars/uVisualGearsList.pas --- /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 + * + * 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.