1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  *
22  * Based on the original sources
23  *   Faery Tale II -- The Halls of the Dead
24  *   (c) 1993-1996 The Wyrmkeep Entertainment Co.
25  */
26 
27 #ifndef SAGA2_EFFECTS_H
28 #define SAGA2_EFFECTS_H
29 
30 #include "saga2/dice.h"
31 
32 namespace Saga2 {
33 
34 class Actor;
35 class GameObject;
36 
37 // ------------------------------------------------------------------
38 // Effects of spells and other things
39 
40 //
41 // 1 Enchantments
42 //   A Object (non-Actor) Enchantments
43 //       Object : There aren't a lot of these
44 //   B Actor Enchantments
45 //       Attrib : affects attributes of actors
46 //       Resist : Enable resistance to various things
47 //       Immune : Enable immunity to various things
48 //       Others : Misc flags
49 //	 C Player Enchantments
50 //       Player : Flags that really only affect players
51 // 2 Effects
52 //   A General effects
53 //       Damage : does damage of various types
54 //   B Actor only effects
55 //       Drains : mana drains, money drains, food drains
56 //       Special : must be handled manually
57 //   C TAG effects : There aren't many of these
58 //   D Global Effects : Effects that have signifigant effect on the game engine
59 //
60 
61 enum effectTypes {
62 	effectNone          = 0, // no functional effect
63 	effectAttrib,            // (enchant) affects attributes of actors
64 	effectResist,            // (enchant) Enable resistance to various things
65 	effectImmune,            // (enchant) Enable immunity to various things
66 	effectOthers,            // (enchant) Enable immunity to various things
67 	effectNonActor,          // (enchant) change an object
68 	effectPoison,            // (enchant) change an object
69 //  Effect types greater than 8 cannot be enchantments
70 	effectDamage        = 8,   // does damage of various types
71 	effectDrains,            // mana drain, money drain
72 	effectTAG,               // mana drain, money drain
73 	effectLocation,          // mana drain, money drain
74 	effectSpecial,
75 	effectStrike            // weapon strike effect
76 };
77 
78 
79 //
80 // Resistance Effects - these correspond exactly to the Damage types
81 //   A separate enum is defined to permit differentiation between
82 //   damage, resistance, and immunity effects
83 //
84 
85 enum effectResistTypes {
86 	resistOther     = kDamageOther,
87 	// Combat resist
88 	resistImpact    = kDamageImpact,
89 	resistSlash     = kDamageSlash,
90 	resistProjectile = kDamageProjectile,
91 	// Magic resist
92 	resistFire      = kDamageFire,
93 	resistAcid      = kDamageAcid,
94 	resistHeat      = kDamageHeat,
95 	resistCold      = kDamageCold,
96 	resistLightning = kDamageLightning,
97 	resistPoison    = kDamagePoison,
98 	// Other magic resist
99 	resistMental    = kDamageMental,
100 	resistToUndead  = kDamageToUndead,
101 	resistDirMagic  = kDamageDirMagic,
102 	// Physiological Damage
103 	resistStarve    = kDamageStarve,
104 	// other
105 	resistEnergy    = kDamageEnergy
106 };
107 
108 //
109 // Immunity Effects - See the notes for resistance effects
110 //
111 
112 // Types of damage an effect can give immunity to
113 enum effectImmuneTypes {
114 	immuneOther     = resistOther,
115 	// Combat imm
116 	immuneImpact    = resistImpact,
117 	immuneSlash     = resistSlash,
118 	immuneProjectile = resistProjectile,
119 	// Magic immu
120 	immuneFire      = resistFire,
121 	immuneAcid      = resistAcid,
122 	immuneHeat      = resistHeat,
123 	immuneCold      = resistCold,
124 	immuneLightning = resistLightning,
125 	immunePoison    = resistPoison,
126 	// Other magimune
127 	immuneMental    = resistMental,
128 	immuneToUndead  = resistToUndead,
129 	immuneDirMagic  = resistDirMagic,
130 	// PhysiologiDamage
131 	immuneStarve    = resistStarve,
132 	// other
133 	immuneEnergy    = resistEnergy
134 };
135 
136 //
137 // Other Effects - general flags in the actor structure most of which
138 //   aren't hooked up to anything.
139 //
140 
141 enum effectOthersTypes {
142 	// Movement flags
143 	actorNoncorporeal   = 1,    // The creature can walk through things
144 	actorWaterBreathe   = 2,    // death spell
145 	actorSlowFall       = 3,    // the creature is not harmed by falling (but falls none the less)
146 	actorLevitate       = 4,    // flying with no height control ?
147 	actorFlying         = 5,    // the creature flys
148 	// speed flags
149 	actorFastMove       = 6,    //
150 	actorFastAttack     = 7,    //
151 	actorSlowAttack     = 8,    // come... back... here... lit... tle... bun... ny...
152 
153 	actorImmobile       = 9,    // I thought I told you to leave the piano at home
154 	// ill effects
155 	actorAsleep         = 10,   // Zzzzzzzzzzz
156 	actorParalyzed      = 11,   // the creature can't move an inch
157 	actorFear           = 12,   // run away! run away
158 	actorDiseased       = 13,   // cannot heal
159 	actorPoisoned       = 14,   // death spell
160 	// perception & perceivability flags
161 	actorBlind          = 15,   // can't see
162 	actorSeeInvis       = 16,   // can see invisible
163 	actorClairvoyant    = 17,  // unknown effects
164 	actorInvisible      = 18,   // is invisible
165 	actorUndetectable   = 19,   // can't be seen, smelled
166 	actorDetPoison      = 20,   // poison things glow green
167 	// flags preventing changes to other flags
168 	actorNoEnchant      = 21,   // no bad enchantments
169 	actorNoDrain        = 22,   // no mana / food drains
170 	// flags that make things run away
171 	actorRepelEvil      = 23,   // death spell
172 	actorRepelGood      = 24,   // death spell
173 	actorRepelUndead    = 25,   // death spell
174 	// miscellaneous
175 	actorNotDefenseless = 26,   // forgo defenselessness check
176 	actorDisappearOnDeath = 27, // gets deleted on death and spews inventory
177 	// dead or moved flags
178 	actorWaterWalk           // can walk on water (same as float ?)
179 };
180 
181 //
182 // Drains Effects - these correspond to values in the actor that are
183 //   drained & replenished
184 //
185 
186 enum effectDrainsTypes {
187 	// mana pools
188 	drainsManaRed       = 1,
189 	drainsManaOrange,
190 	drainsManaYellow,
191 	drainsManaGreen,
192 	drainsManaBlue,
193 	drainsManaViolet,
194 	drainsLifeLevel,
195 	drainsVitality,
196 	drainsMoney
197 };
198 
199 
200 //
201 // TAG Effects - effects that apply when a TAG is the target
202 //
203 
204 enum effectTAGTypes {
205 	settagLocked        = 1,
206 	settagOpen          = 2
207 };
208 
209 
210 //
211 // Location Effects - effects that apply when a Location is the target
212 //
213 
214 enum effectLocationTypes {
215 	locateDummy         = 1
216 };
217 
218 enum objectFlags {
219 	objectOpen          = (1 << 0),     // object is in the "open" state
220 	objectLocked        = (1 << 1),     // object cannot be opened
221 	objectImportant     = (1 << 2),     // object must be recycled when trashed
222 	objectGhosted       = (1 << 3),     // object drawn translucent
223 	objectInvisible     = (1 << 4),     // object cannot be seen
224 	objectObscured      = (1 << 5),     // object obscured by terrain
225 	objectMoving        = (1 << 6),     // object has attached motion task
226 	objectScavengable   = (1 << 7),     // object can be deleted
227 	objectFloating      = (1 << 8),     // object not affected by Gravity
228 	objectNoRecycle     = (1 << 9),     // object is referred to by script, don't delete
229 	objectActivated     = (1 << 10),    // object is activated
230 	objectAlias         = (1 << 11),    // object is not real, just a copy of another object
231 	objectTriggeringTAG = (1 << 12),    // object has triggerred TAG upon which it rests
232 	objectOnScreen      = (1 << 13),    // object is on display list
233 	objectSightedByCenter = (1 << 14)   // there is a line of sight to center actor
234 };
235 
236 
237 //
238 // Special Effects - these are spells that need to be handled manually
239 //
240 
241 enum effectSpecialTypes {
242 	specialDispellHelpfulEnch = 1,   // clears helpful enchantments
243 	specialDispellHarmfulEnch,       // clears harmful enchantments
244 	specialKill,                     // death spell
245 	specialRessurect,                // raise dead spell
246 	specialTeleport,                 // Teleportation
247 	specialCreateActor,              // Create an actor or wall
248 	specialSagaFunc,                 // calls a saga function
249 	specialCreateWWisp,              // calls a saga function
250 	specialCreateFWisp,              // calls a saga function
251 	specialCreateWraith,             // calls a saga function
252 	specialCreateFood,               // calls a saga function
253 	specialRejoin
254 };
255 
256 // ------------------------------------------------------------------
257 // ENCHANTMENT IDs
258 // It is necessary to combine all these possibilities into a 16 bit integer
259 // Here's how its mapped
260 //   3 bits - general effect type
261 //   5 bits - sub class enum value
262 //   8 bits - damage amount, boolean on/off etc.
263 //
264 
makeEnchantmentID(uint16 type,uint16 damtyp,int16 damamt)265 inline uint16 makeEnchantmentID(uint16 type, uint16 damtyp, int16 damamt) {
266 	assert(type < 8);
267 	assert(damtyp < 32);
268 	assert(damamt < 128 && damamt > -128);
269 	return ((type << 13) | (damtyp << 8)) + (damamt + 128);
270 }
271 
272 /* skill*  are now in the spellid enum ;AS;
273 inline uint16 makeEnchantmentID(effectAttribTypes atttyp, int16 damamt)
274     {   return (effectAttrib << 13) | (atttyp << 8) + (damamt+128); }
275 */
276 
makeEnchantmentID(effectResistTypes restyp,bool damamt)277 inline uint16 makeEnchantmentID(effectResistTypes restyp, bool damamt) {
278 	return ((effectResist << 13) | (restyp << 8)) + (damamt + 128);
279 }
280 
makeEnchantmentID(effectImmuneTypes immtyp,bool damamt)281 inline uint16 makeEnchantmentID(effectImmuneTypes immtyp, bool damamt) {
282 	return ((effectImmune << 13) | (immtyp << 8)) + (damamt + 128);
283 }
284 
makeEnchantmentID(effectOthersTypes othtyp,bool damamt)285 inline uint16 makeEnchantmentID(effectOthersTypes othtyp, bool damamt) {
286 	return ((effectOthers << 13) | (othtyp << 8)) + (damamt + 128);
287 }
288 
makeEnchantmentID(objectFlags othtyp,bool damamt)289 inline uint16 makeEnchantmentID(objectFlags othtyp, bool damamt) {
290 	return ((effectNonActor << 13) | (othtyp << 8)) + (damamt + 128);
291 }
292 
makeEnchantmentID(uint8 damamt)293 inline uint16 makeEnchantmentID(uint8 damamt) {
294 	return ((effectPoison << 13) | (0 << 8)) + damamt;
295 }
296 
getEnchantmentType(uint16 eID)297 inline effectTypes getEnchantmentType(uint16 eID) {
298 	return (effectTypes)(eID >> 13);
299 }
300 
getEnchantmentSubType(uint16 eID)301 inline uint16 getEnchantmentSubType(uint16 eID) {
302 	return (eID >> 8) & 0x1F;
303 }
304 
getEnchantmentAmount(uint16 eID)305 inline int16 getEnchantmentAmount(uint16 eID) {
306 	return (eID & 0xFF) - 128;
307 }
308 
309 // ------------------------------------------------------------------
310 // Determine whether an enchantment is harmful
311 
isHarmful(uint16 enchID)312 inline bool isHarmful(uint16 enchID) {
313 	int16 typ = getEnchantmentType(enchID);
314 	int16 sub = getEnchantmentSubType(enchID);
315 	int16 amt = getEnchantmentAmount(enchID);
316 	if (typ == effectAttrib)  return amt < 0;
317 	if (typ == effectOthers)
318 		return (sub >= actorSlowAttack && sub <= actorBlind);
319 	return false;
320 }
321 
322 // ------------------------------------------------------------------
323 // Determine whether an enchantment can fail
324 
isSaveable(uint16 enchID)325 inline bool isSaveable(uint16 enchID) {
326 	int16 typ = getEnchantmentType(enchID);
327 	return (typ == effectOthers && isHarmful(enchID));
328 }
329 
330 // ------------------------------------------------------------------
331 //  Determine whether a damage type is magical
332 
isMagicDamage(effectDamageTypes t)333 inline bool isMagicDamage(effectDamageTypes t) {
334 	return t >= kDamageFire && t <= kDamageDirMagic;
335 }
336 
337 #define Forever (255)
338 
339 class SpellTarget;
340 
341 //-------------------------------------------------------------------
342 // ProtoEffects
343 
344 //   This is the base class of several spell effect prototype classes
345 //     The implement routine carries out the instantiation of a
346 //     particular effect on a given target (doing damage or whatever)
347 
348 
349 class ProtoEffect {
350 	//protected:
351 	//int imp;                // enchant or immediate
352 
353 public:
354 	ProtoEffect *next;                      // pointer to additional effects
355 
ProtoEffect()356 	ProtoEffect() {
357 		next = NULL;
358 	}
~ProtoEffect()359 	virtual ~ProtoEffect() {
360 		if (next) delete next;
361 		next = NULL;
362 	}
363 	//int implementation( void ) { return imp; }
applicable(SpellTarget &)364 	virtual bool applicable(SpellTarget &) {
365 		return false;
366 	}
367 	virtual void implement(GameObject *, SpellTarget *, int8 = 0) {}
368 };
369 
370 
371 //-------------------------------------------------------------------
372 // ProtoDamage
373 //   This class of effects does a range of damage to the target
374 
375 class ProtoDamage: public ProtoEffect {
376 	effectDamageTypes   type;               // damage type
377 	int8                dice,               // # of dice to roll
378 	                    sides,              // # of sides on dice
379 	                    skillDice,          // multiply by spellcraft to get additional dice
380 	                    base,               // absolute damage amount
381 	                    skillBase;               // absolute damage amount
382 	int8                self;               // casts at self
383 
384 public:
385 
386 	ProtoDamage(int8 d, int8 s, int8 sd, int8 b, effectDamageTypes t, int, bool afSelf = false, int8 sb = 0) {
387 		type = t;
388 		dice = d;
389 		sides = s;
390 		skillDice = sd;
391 		base = b;
392 		self = afSelf;
393 		skillBase = sb;
394 	}
395 
396 	bool applicable(SpellTarget &trg);
397 
398 	void implement(GameObject *cst, SpellTarget *trg, int8 deltaDamage = 0);
399 
400 	static int16 getRelevantStat(effectDamageTypes dt, Actor *a);
401 };
402 
403 //-------------------------------------------------------------------
404 // ProtoDrainage
405 //   This class of effects does a range of damage to the target's
406 //   mana, money or food supply
407 
408 class ProtoDrainage: public ProtoEffect {
409 	effectDrainsTypes   type;               // damage type
410 	int8                dice,               // # of dice to roll
411 	                    sides,              // # of sides on dice
412 	                    skillDice,          // multiply by spellcraft to get additional dice
413 	                    base;               // absolute damage amount
414 	int8                self;               // casts at self
415 
416 public:
417 
418 	ProtoDrainage(int8 d, int8 s, int8 sd, int8 b, effectDrainsTypes t, int, bool afSelf = false) {
419 		type = t;
420 		dice = d;
421 		sides = s;
422 		skillDice = sd;
423 		base = b;
424 		self = afSelf;
425 	}
426 
427 	bool applicable(SpellTarget &trg);
428 
429 	void implement(GameObject *cst, SpellTarget *trg, int8 deltaDamage = 0);
430 
431 	static int16 currentLevel(Actor *a, effectDrainsTypes edt);
432 	static void drainLevel(GameObject *cst, Actor *a, effectDrainsTypes edt, int16 amt);
433 };
434 
435 //-------------------------------------------------------------------
436 // ProtoEnchantment
437 //   This can be any of several types of enchantments (see EFFECTS.H)
438 //
439 
440 class ProtoEnchantment: public ProtoEffect {
441 	uint16              enchID;
442 	uint32              minEnch;
443 	RandomDice          dice;               // enchantment time
444 
445 public:
ProtoEnchantment(uint16 e,uint32 loTime,uint32 hiTime)446 	ProtoEnchantment(uint16 e, uint32 loTime, uint32 hiTime) {
447 		enchID = e;
448 		dice = RandomDice(1, hiTime - loTime);
449 		minEnch = loTime;
450 	}
451 
452 	bool applicable(SpellTarget &trg);
453 
454 	void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
455 
canFail(void)456 	bool canFail(void) {
457 		return isSaveable(enchID);
458 	}
459 
460 	static bool realSavingThrow(Actor *a);
461 };
462 
463 //-------------------------------------------------------------------
464 // ProtoTAGEffect
465 //   this type of spell sets up spells that are used to alter tags
466 
467 class ProtoTAGEffect: public ProtoEffect {
468 	effectTAGTypes      affectBit;
469 	int16               onOff;       // lock/unlock or trigger ID
470 	ObjectID            trigger;
471 
472 public:
ProtoTAGEffect(effectTAGTypes ett,int16 v,ObjectID t)473 	ProtoTAGEffect(effectTAGTypes ett, int16 v, ObjectID t) {
474 		affectBit = ett;
475 		onOff = v;
476 		trigger = t;
477 	}
478 
479 	bool applicable(SpellTarget &trg);
480 
481 	void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
482 };
483 
484 //-------------------------------------------------------------------
485 // ProtoObjectEffect
486 //   These effects are used only on non-actor objects.
487 
488 class ProtoObjectEffect: public ProtoEffect {
489 	uint16              affectBit;
490 	int16               onOff;
491 	RandomDice          dice;               // enchantment time
492 
493 public:
ProtoObjectEffect(uint16 e,int16 v,uint32 loT,uint32 hiT)494 	ProtoObjectEffect(uint16 e, int16 v, uint32 loT, uint32 hiT) {
495 		affectBit = e;
496 		onOff = v;
497 		dice = RandomDice(loT, hiT);
498 	}
499 
500 	bool applicable(SpellTarget &trg);
501 
502 	void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
503 };
504 
505 //-------------------------------------------------------------------
506 // If spells ever need to do things to Locations this
507 // is where they'll be
508 
509 class ProtoLocationEffect: public ProtoEffect {
510 	effectLocationTypes affectBit;
511 	int16               value;
512 
513 public:
ProtoLocationEffect(effectLocationTypes elt,int16 v)514 	ProtoLocationEffect(effectLocationTypes elt, int16 v) {
515 		affectBit = elt;
516 		value = v;
517 	}
518 
applicable(SpellTarget &)519 	bool applicable(SpellTarget &)  {
520 		return (true);
521 	}
522 
523 	void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
524 };
525 
526 //-------------------------------------------------------------------
527 // ProtoSpecialEffects
528 //   As always there are spells that just don't fit any of the other
529 //   molds. These protoEffects allow customized spell handlers to be
530 //   implemented.
531 //
532 
533 typedef void SPELLIMPLEMENTATION(GameObject *, SpellTarget *);
534 
535 #define SPECIALSPELL(name) void name(GameObject *cst, SpellTarget *trg)
536 
537 class ProtoSpecialEffect: public ProtoEffect {
538 	int16 routineID;
539 	SPELLIMPLEMENTATION *handler;
540 
541 public:
542 	ProtoSpecialEffect(SPELLIMPLEMENTATION *newHandler, int16 callID = 0) {
543 		handler = newHandler;
544 		routineID = callID;
545 	}
546 
applicable(SpellTarget &)547 	bool applicable(SpellTarget &) {
548 		return true;
549 		//return (trg.getType()==SpellTarget::spellTargetObject ||
550 		//       trg.getType()==SpellTarget::spellTargetObjectPoint) &&
551 		//     isActor(trg.getObject());
552 	}
553 
554 	void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
555 };
556 
557 } // end of namespace Saga2
558 
559 #endif
560