1 /* GemRB - Infinity Engine Emulator
2  * Copyright (C) 2006 The GemRB Project
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  *
19  */
20 
21 /**
22  * @file Projectile.h
23  * Declares Projectile, class for supporting functionality of spell/item projectiles
24  * @author The GemRB Project
25  */
26 
27 
28 #ifndef PROJECTILE_H
29 #define PROJECTILE_H
30 
31 #include "exports.h"
32 #include "ie_types.h"
33 
34 #include "CharAnimations.h" //contains MAX_ORIENT
35 #include "EffectQueue.h"
36 #include "Map.h"
37 #include "Palette.h"
38 #include "PathFinder.h"
39 #include "Audio.h"
40 #include "Video.h"
41 
42 namespace GemRB {
43 
44 //this is the height of the projectile when Spark Flag Fly = 1
45 #define FLY_HEIGHT 50
46 //this is supposed to move the projectile to the background
47 #define BACK_DEPTH 50
48 
49 //projectile phases
50 #define P_UNINITED  -1
51 #define P_TRAVEL     0   //projectile moves to target
52 #define P_TRAVEL2    1   //projectile hit target
53 #define P_TRIGGER    2   //projectile hovers over target, waits for trigger
54 #define P_EXPLODING1 3   //projectile explosion spreads
55 #define P_EXPLODING2 4   //projectile explosion repeats
56 #define P_EXPLODED   5   //projectile spread over area
57 #define P_EXPIRED   99   //projectile scheduled for removal (existing parts are still drawn)
58 
59 //projectile spark flags
60 #define PSF_SPARKS  1
61 #define PSF_FLYING  2
62 #define PSF_LOOPING 4         //looping sound
63 #define PSF_LOOPING2 8        //looping second sound
64 #define PSF_IGNORE_CENTER 16
65 #define PSF_BACKGROUND 32
66 //gemrb specific internal flag
67 #define PSF_SOUND2  0x80000000//already started sound2
68 
69 //projectile travel flags
70 #define PTF_COLOUR  1       //fake colours
71 #define PTF_SMOKE   2       //has smoke
72 // bg2: 4 smoke is false colored
73 #define PTF_TINT    8       //tint projectile
74 // bg2: 10 height
75 #define PTF_SHADOW  32      //has shadow bam
76 #define PTF_LIGHT   64      //has light shadow / glow
77 #define PTF_TRANS   128     // glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE);
78 #define PTF_BRIGHTEN 256    //brighten alpha; CPROJECTILEBAMFILEFORMAT_FLAGS_BRIGHTEST in bg2
79 #define PTF_BLEND	512		// glBlendFunc(GL_DST_COLOR, GL_ONE);
80 #define PTF_TRANS_BLEND (PTF_TRANS | PTF_BLEND) // glBlendFunc(GL_SRC_COLOR, GL_ONE); IWD only?
81 // 0x100 and 0x200: FLAGS_BRIGHTESTIFFAST BRIGHTEST3DONLYOFF
82 #define PTF_TIMELESS 0x4000 // GemRB extension to differentiate projectiles that ignore timestop
83 
84 //projectile extended travel flags (gemrb specific)
85 #define PEF_BOUNCE     1       //bounce from walls (lightning bolt)
86 #define PEF_CONTINUE   2       //continue as a travel projectile after trigger (lightning bolt)
87 //TODO: This can probably be replaced by an area projectile trigger (like skull trap, glyph)
88 #define PEF_FREEZE     4       //stay around (ice dagger)
89 #define PEF_NO_TRAVEL  8       //all instant projectiles (draw upon holy might, finger of death)
90 #define PEF_TRAIL      16      //trail bams facing value uses the same field as the travel projectile (otherwise it defaults to 9) (shout in iwd)
91 #define PEF_CURVE      32      //curved path (magic missile)
92 #define PEF_RANDOM     64      //random starting frame for animation (?)
93 #define PEF_PILLAR     128     //draw all cycles simultaneously on top of each other (call lightning, flamestrike)
94 #define PEF_HALFTRANS  256     //half-transparency (holy might)
95 #define PEF_TINT       512     //use palette gradient as tint
96 #define PEF_ITERATION  1024    //create another projectile of type-1 (magic missiles)
97 #define PEF_DEFSPELL   2048    //always apply the default spell on the caster
98 #define PEF_FALLING    4096    //projectile falls down vertically (cow)
99 #define PEF_INCOMING   8192    //projectile falls in on trajectory (comet)
100 #define PEF_LINE       16384   //solid line between source and target (agannazar's scorcher)
101 #define PEF_WALL       32768   //solid line in front of source, crossing target (wall of fire)
102 #define PEF_BACKGROUND 0x10000 //draw under target,overrides flying (dimension door)
103 #define PEF_POP        0x20000 //draw travel bam, then shadow, then travel bam backwards
104 #define PEF_UNPOP      0x40000 //draw shadow, then travel bam (this is an internal flag)
105 //TODO: The next flag is probably not needed, it is done by a separate area hit animation
106 #define PEF_FADE       0x80000 //gradually fade on spot if used with PEF_FREEZE (ice dagger)
107 #define PEF_TEXT       0x100000//display text during setup
108 #define PEF_WANDERING  0x200000//random movement (no real path)
109 #define PEF_CYCLE      0x400000//random cycle
110 #define PEF_RGB        0x800000//rgb pulse on hit
111 #define PEF_TOUCH      0x1000000//successful to hit roll needed
112 #define PEF_NOTIDS     0x2000000//negate IDS check
113 #define PEF_NOTIDS2    0x4000000//negate secondary IDS check
114 #define PEF_BOTH       0x8000000//both IDS check must succeed
115 #define PEF_DELAY      0x10000000//delay payload until travel projectile cycle ends
116 
117 //projectile area flags
118 #define PAF_VISIBLE    1      //the travel projectile is visible until explosion; CPROJECTILEAREAFILEFORMAT_FLAGS_CENTERBAM
119 #define PAF_INANIMATE  2      //target inanimates
120 #define PAF_TRIGGER    4      //explosion needs to be triggered
121 #define PAF_SYNC       8      //one explosion at a time
122 #define PAF_SECONDARY  16     //secondary projectiles at explosion
123 #define PAF_FRAGMENT   32     //fragments (charanimation) at explosion
124 #define PAF_ENEMY      64     //target party or not party
125 #define PAF_PARTY      128    //target party
126 #define PAF_TARGET     (64|128)
127 #define PAF_LEV_MAGE   256
128 #define PAF_LEV_CLERIC 512
129 #define PAF_VVC        1024   // played at center
130 #define PAF_CONE       2048   //enable cone shape
131 #define PAF_NO_WALL    0x1000 //pass through walls; CPROJECTILEAREAFILEFORMAT_FLAGS_IGNORELOS
132 #define PAF_TRIGGER_D  0x2000 //delayed trigger (only if animation is over 30); CPROJECTILEAREAFILEFORMAT_FLAGS_CENTERBAMWAIT
133 #define PAF_DELAY      0x4000 // CPROJECTILEAREAFILEFORMAT_FLAGS_FORCEINITIALDELAY
134 #define PAF_AFFECT_ONE 0x8000 // CPROJECTILEAREAFILEFORMAT_FLAGS_ONETARGETONLY
135 
136 //area projectile flags (in areapro.2da)
137 //this functionality was hardcoded in the original engine, so the bit flags are
138 //completely arbitrary (i assign them as need arises)
139 //child projectiles need to be tinted (example: stinking cloud, counter example: fireball)
140 #define APF_TINT      1
141 //child projectiles fill the whole area (example: stinking cloud, counter example: fireball)
142 #define APF_FILL      2
143 //child projectiles start in their destination (example: icestorm, counter example: fireball)
144 #define APF_SCATTER   4
145 //the explosion vvc has gradient (example: icestorm, counter example: fireball)
146 #define APF_VVCPAL    8
147 //there is an additional added scatter after the initial spreading ring
148 #define APF_SPREAD    16
149 //the spread projectile needs gradient colouring,not tint (example:web, counter example: stinking cloud)
150 #define APF_PALETTE   32
151 //use both animations in the spread
152 #define APF_BOTH      64
153 //more child projectiles
154 #define APF_MORE      128
155 //apply spell on caster if failed to find target
156 #define APF_SPELLFAIL 256
157 //multiple directions
158 #define APF_MULTIDIR  512
159 //target HD counting
160 #define APF_COUNT_HD  1024
161 //target flag enemy ally switched
162 #define APF_INVERT_TARGET 2048
163 //tiled AoE animation
164 #define APF_TILED 4096
165 #define APF_PLAYONCE 8192
166 
167 struct ProjectileExtension
168 {
169 	ieDword AFlags;
170 	ieWord TriggerRadius;
171 	ieWord ExplosionRadius;
172 	ieResRef SoundRes; //used for areapro.2da explosion sound
173 	ieWord Delay;
174 	ieWord FragAnimID;
175 	ieWord FragProjIdx;
176 	ieByte ExplosionCount;
177 	ieByte ExplType;
178 	ieWord ExplColor; // a byte in the original, followed by padding
179 	ieWord ExplProjIdx;
180 	ieResRef VVCRes;  //used for areapro.2da second resref (center animation)
181 	ieWord ConeWidth;
182 	//these are GemRB specific (from areapro.2da)
183 	ieDword APFlags;    //areapro.2da flags
184 	ieResRef Spread;    //areapro.2da first resref
185 	ieResRef Secondary; //areapro.2da third resref
186 	ieResRef AreaSound; //areapro.2da second sound resource
187 	//used for target or HD counting
188 	ieWord DiceCount;
189 	ieWord DiceSize;
190 	ieWord TileX;
191 	ieWord TileY;
192 };
193 
194 class GEM_EXPORT Projectile
195 {
196 public:
197 	Projectile();
198 	~Projectile();
199 	void InitExtension();
200 
201 	ieWord Speed;
202 	ieDword SFlags;
203 	ieResRef FiringSound;
204 	ieResRef ArrivalSound;
205 	ieResRef TravelVVC;
206 	ieDword SparkColor;
207 	ieDword ExtFlags;
208 	ieDword StrRef;
209 	Color RGB;
210 	ieWord ColorSpeed;
211 	ieWord Shake;
212 	ieWord IDSType;
213 	ieWord IDSValue;
214 	ieWord IDSType2;
215 	ieWord IDSValue2;
216 	ieResRef FailSpell;
217 	ieResRef SuccSpell;
218 	////// gap
219 	ieDword TFlags;
220 	ieResRef BAMRes1;
221 	ieResRef BAMRes2;
222 	ieByte Seq1, Seq2;
223 	ieWord LightX;
224 	ieWord LightY;
225 	ieWord LightZ;
226 	ieResRef PaletteRes;
227 	ieByte Gradients[7];
228 	ieByte SmokeSpeed;
229 	ieByte SmokeGrad[7];
230 	ieByte Aim; // original bg2: m_numDirections // list of {1, 5, 9}
231 	ieWord SmokeAnimID;
232 	ieResRef TrailBAM[3];
233 	ieWord TrailSpeed[3];
234 	unsigned int Range;
235 	//these are public but not in the .pro file
236 	ProjectileExtension* Extension;
237 	bool autofree;
238 	PaletteHolder palette;
239 	//internals
240 protected:
241 	ieResRef smokebam;
242 	ieDword timeStartStep;
243 	//attributes from moveable object
244 	unsigned char Orientation, NewOrientation;
245 	PathNode* path; //whole path
246 	PathNode* step; //actual step
247 	//similar to normal actors
248 	Map *area;
249 	Point Pos;
250 	int ZPos;
251 	Point Destination;
252 	Point Origin;
253 	ieDword Caster;    //the globalID of the caster actor
254 	int Level;         //the caster's level
255 	ieDword Target;    //the globalID of target actor
256 	ieDword FakeTarget; //a globalID for target that isn't followed
257 	int phase;
258 	//saved in area
259 	ieResRef name;
260 	ieWord type;
261 	//these come from the extension area
262 	int extension_delay;
263 	int extension_explosioncount;
264 	int extension_targetcount;
265 	Color tint;
266 
267 	//special (not using char animations)
268 	Animation* travel[MAX_ORIENT];
269 	Animation* shadow[MAX_ORIENT];
270 	Holder<Sprite2D> light;//this is just a round/halftrans sprite, has no animation
271 	EffectQueue* effects;
272 	Projectile **children;
273 	int child_size;
274 	int pathcounter;
275 	int bend;
276 	int drawSpark;
277 	Holder<SoundHandle> travel_handle;
278 public:
279 	void SetCaster(ieDword t, int level);
280 	ieDword GetCaster() const;
281 	bool FailedIDS(const Actor *target) const;
282 	void SetTarget(ieDword t, bool fake);
283 	void SetTarget(const Point &p);
284 	bool PointInRadius(const Point &p) const;
285 	int GetPhase() const;
286 	void Cleanup();
287 
GetDestination()288 	inline Point GetDestination() const { return Destination; }
GetName()289 	inline const char * GetName() const { return name; }
GetType()290 	inline ieWord GetType() const { return type; }
291 	//This assumes that the effect queue cannot be bigger than 65535
292 	//which is a sane expectation
GetEffects()293 	inline EffectQueue *GetEffects() const {
294 		return effects;
295 	}
296 
GetOrientation()297 	inline unsigned char GetOrientation() const {
298 		return Orientation;
299 	}
300 	//no idea if projectiles got height, using y
GetHeight()301 	inline int GetHeight() const {
302 		//if projectile is drawn absolutely on the ground
303 		if (SFlags&PSF_BACKGROUND) {
304 			return 0;
305 		}
306 		//if projectile is drawn behind target (not behind everyone)
307 		if (ExtFlags&PEF_BACKGROUND) {
308 			return Pos.y-BACK_DEPTH;
309 		}
310 
311 		//if projectile is flying
312 		if (SFlags&PSF_FLYING) {
313 			return Pos.y+FLY_HEIGHT;
314 		}
315 		return Pos.y;
316 	}
317 
318 	void SetIdentifiers(const char *name, ieWord type);
319 
320 	void SetEffectsCopy(const EffectQueue *eq, const Point &source);
321 
322 	//don't forget to set effects to NULL when the projectile discharges
323 	//unexploded projectiles are responsible to destruct their payload
324 
SetEffects(EffectQueue * fx)325 	inline void SetEffects(EffectQueue *fx) {
326 		effects = fx;
327 	}
328 
GetNextFace()329 	inline unsigned char GetNextFace() {
330 		//slow turning
331 		if (Orientation != NewOrientation) {
332 			if ( ( (NewOrientation-Orientation) & (MAX_ORIENT-1) ) <= MAX_ORIENT/2) {
333 				Orientation++;
334 			} else {
335 				Orientation--;
336 			}
337 			Orientation = Orientation&(MAX_ORIENT-1);
338 		}
339 
340 		return Orientation;
341 	}
342 
SetOrientation(int value,bool slow)343 	inline void SetOrientation(int value, bool slow) {
344 		//MAX_ORIENT == 16, so we can do this
345 		NewOrientation = (unsigned char) (value&(MAX_ORIENT-1));
346 		if (!slow) {
347 			Orientation = NewOrientation;
348 		}
349 	}
350 
351 	void Setup();
352 	//sets how long a created travel projectile will hover over a spot
353 	//before vanishing (without the need of area extension)
354 	void SetDelay(int delay);
355 	void MoveTo(Map *map, const Point &Des);
356 	void ClearPath();
357 	//handle phases, return 0 when expired
358 	int Update();
359 	//draw object
360 	void Draw(const Region &screen);
361 	void SetGradient(int gradient, bool tint);
362 	void StaticTint(const Color &newtint);
363 private:
364 	//creates a child projectile with current_projectile_id - 1
365 	void CreateIteration();
366 	void CreateAnimations(Animation **anims, const ieResRef bam, int Seq);
367 	//pillar type animations
368 	void CreateCompositeAnimation(Animation **anims, AnimationFactory *af, int Seq);
369 	//oriented animations (also simple ones)
370 	void CreateOrientedAnimations(Animation **anims, AnimationFactory *af, int Seq);
371 	void GetPaletteCopy(Animation *anim[], PaletteHolder &pal);
372 	void GetSmokeAnim();
373 	void SetBlend(int brighten);
374 	//apply spells and effects on the target, only in single travel mode
375 	//area effect projectiles call a separate single travel projectile for each affected target
376 	void Payload();
377 	//if there is an extension, convert to exploding or wait for trigger
378 	void EndTravel();
379 	//apply default spell
380 	void ApplyDefault();
381 	//stops the current sound
382 	void StopSound();
383 	//kickstarts the secondary sound
384 	void UpdateSound();
385 	//reached end of single travel missile, explode or expire now
386 	void ChangePhase();
387 	//drop a BAM or VVC on the trail path, return the length of the animation
388 	int AddTrail(const ieResRef BAM, const ieByte *pal) const;
389 	void DoStep(unsigned int walk_speed);
390 	void LineTarget() const;      //line projectiles (walls, scorchers)
391 	void LineTarget(const PathNode *beg, const PathNode *end) const;
392 	void SecondaryTarget(); //area projectiles (circles, cones)
393 	void CheckTrigger(unsigned int radius);
394 	//calculate target and destination points for a firewall
395 	void SetupWall();
396 	void DrawLine(const Region &screen, int face, BlitFlags flag);
397 	void DrawTravel(const Region &screen);
398 	bool DrawChildren(const Region &screen);
399 	void DrawExplosion(const Region &screen);
400 	void SpawnFragment(Point &pos);
401 	void DrawExploded(const Region &screen);
402 	int GetTravelPos(int face) const;
403 	int GetShadowPos(int face) const;
404 	void SetPos(int face, int frame1, int frame2);
405 	inline int GetZPos() const;
406 
407 	//logic to resolve target when single projectile hit destination
408 	int CalculateTargetFlag() const;
409 	//logic to resolve the explosion count (may be based on caster level)
410 	int CalculateExplosionCount();
411 
412 	Actor *GetTarget();
413 	void NextTarget(const Point &p);
414 	void SetupPalette(Animation *anim[], PaletteHolder &pal, const ieByte *gradients);
415 
416 private:
417 	void Draw(Holder<Sprite2D> spr, const Point& p,
418 			  BlitFlags flags, Color tint) const;
419 };
420 
421 }
422 
423 #endif // PROJECTILE_H
424