mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-07 10:21:31 +00:00
559 lines
17 KiB
C++
559 lines
17 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* 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, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*
|
|
* Based on the original sources
|
|
* Faery Tale II -- The Halls of the Dead
|
|
* (c) 1993-1996 The Wyrmkeep Entertainment Co.
|
|
*/
|
|
|
|
#ifndef SAGA2_EFFECTS_H
|
|
#define SAGA2_EFFECTS_H
|
|
|
|
#include "saga2/dice.h"
|
|
|
|
namespace Saga2 {
|
|
|
|
class Actor;
|
|
class GameObject;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Effects of spells and other things
|
|
|
|
//
|
|
// 1 Enchantments
|
|
// A Object (non-Actor) Enchantments
|
|
// Object : There aren't a lot of these
|
|
// B Actor Enchantments
|
|
// Attrib : affects attributes of actors
|
|
// Resist : Enable resistance to various things
|
|
// Immune : Enable immunity to various things
|
|
// Others : Misc flags
|
|
// C Player Enchantments
|
|
// Player : Flags that really only affect players
|
|
// 2 Effects
|
|
// A General effects
|
|
// Damage : does damage of various types
|
|
// B Actor only effects
|
|
// Drains : mana drains, money drains, food drains
|
|
// Special : must be handled manually
|
|
// C TAG effects : There aren't many of these
|
|
// D Global Effects : Effects that have signifigant effect on the game engine
|
|
//
|
|
|
|
enum effectTypes {
|
|
kEffectNone = 0, // no functional effect
|
|
kEffectAttrib, // (enchant) affects attributes of actors
|
|
kEffectResist, // (enchant) Enable resistance to various things
|
|
kEffectImmune, // (enchant) Enable immunity to various things
|
|
kEffectOthers, // (enchant) Enable immunity to various things
|
|
kEffectNonActor, // (enchant) change an object
|
|
kEffectPoison, // (enchant) change an object
|
|
// Effect types greater than 8 cannot be enchantments
|
|
kEffectDamage = 8, // does damage of various types
|
|
kEffectDrains, // mana drain, money drain
|
|
kEffectTAG, // mana drain, money drain
|
|
kEffectLocation, // mana drain, money drain
|
|
kEffectSpecial,
|
|
kEffectStrike // weapon strike effect
|
|
};
|
|
|
|
|
|
//
|
|
// Resistance Effects - these correspond exactly to the Damage types
|
|
// A separate enum is defined to permit differentiation between
|
|
// damage, resistance, and immunity effects
|
|
//
|
|
|
|
enum effectResistTypes {
|
|
kResistOther = kDamageOther,
|
|
// Combat resist
|
|
kResistImpact = kDamageImpact,
|
|
kResistSlash = kDamageSlash,
|
|
kResistProjectile = kDamageProjectile,
|
|
// Magic resist
|
|
kResistFire = kDamageFire,
|
|
kResistAcid = kDamageAcid,
|
|
kResistHeat = kDamageHeat,
|
|
kResistCold = kDamageCold,
|
|
kResistLightning = kDamageLightning,
|
|
kResistPoison = kDamagePoison,
|
|
// Other magic resist
|
|
kResistMental = kDamageMental,
|
|
kResistToUndead = kDamageToUndead,
|
|
kResistDirMagic = kDamageDirMagic,
|
|
// Physiological Damage
|
|
kResistStarve = kDamageStarve,
|
|
// other
|
|
kResistEnergy = kDamageEnergy
|
|
};
|
|
|
|
//
|
|
// Immunity Effects - See the notes for resistance effects
|
|
//
|
|
|
|
// Types of damage an effect can give immunity to
|
|
enum effectImmuneTypes {
|
|
kImmuneOther = kResistOther,
|
|
// Combat imm
|
|
kImmuneImpact = kResistImpact,
|
|
kImmuneSlash = kResistSlash,
|
|
kImmuneProjectile = kResistProjectile,
|
|
// Magic immu
|
|
kImmuneFire = kResistFire,
|
|
kImmuneAcid = kResistAcid,
|
|
kImmuneHeat = kResistHeat,
|
|
kImmuneCold = kResistCold,
|
|
kImmuneLightning = kResistLightning,
|
|
kImmunePoison = kResistPoison,
|
|
// Other magimune
|
|
kImmuneMental = kResistMental,
|
|
kImmuneToUndead = kResistToUndead,
|
|
kImmuneDirMagic = kResistDirMagic,
|
|
// PhysiologiDamage
|
|
kImmuneStarve = kResistStarve,
|
|
// other
|
|
kImmuneEnergy = kResistEnergy
|
|
};
|
|
|
|
//
|
|
// Other Effects - general flags in the actor structure most of which
|
|
// aren't hooked up to anything.
|
|
//
|
|
|
|
enum effectOthersTypes {
|
|
// Movement flags
|
|
kActorNoncorporeal = 1, // The creature can walk through things
|
|
kActorWaterBreathe = 2, // death spell
|
|
kActorSlowFall = 3, // the creature is not harmed by falling (but falls none the less)
|
|
kActorLevitate = 4, // flying with no height control ?
|
|
kActorFlying = 5, // the creature flys
|
|
// speed flags
|
|
kActorFastMove = 6, //
|
|
kActorFastAttack = 7, //
|
|
kActorSlowAttack = 8, // come... back... here... lit... tle... bun... ny...
|
|
|
|
kActorImmobile = 9, // I thought I told you to leave the piano at home
|
|
// ill effects
|
|
kActorAsleep = 10, // Zzzzzzzzzzz
|
|
kActorParalyzed = 11, // the creature can't move an inch
|
|
kActorFear = 12, // run away! run away
|
|
kActorDiseased = 13, // cannot heal
|
|
kActorPoisoned = 14, // death spell
|
|
// perception & perceivability flags
|
|
kActorBlind = 15, // can't see
|
|
kActorSeeInvis = 16, // can see invisible
|
|
kActorClairvoyant = 17, // unknown effects
|
|
kActorInvisible = 18, // is invisible
|
|
kActorUndetectable = 19, // can't be seen, smelled
|
|
kActorDetPoison = 20, // poison things glow green
|
|
// flags preventing changes to other flags
|
|
kActorNoEnchant = 21, // no bad enchantments
|
|
kActorNoDrain = 22, // no mana / food drains
|
|
// flags that make things run away
|
|
kActorRepelEvil = 23, // death spell
|
|
kActorRepelGood = 24, // death spell
|
|
kActorRepelUndead = 25, // death spell
|
|
// miscellaneous
|
|
kActorNotDefenseless = 26, // forgo defenselessness check
|
|
kActorDisappearOnDeath = 27, // gets deleted on death and spews inventory
|
|
// dead or moved flags
|
|
kActorWaterWalk // can walk on water (same as float ?)
|
|
};
|
|
|
|
//
|
|
// Drains Effects - these correspond to values in the actor that are
|
|
// drained & replenished
|
|
//
|
|
|
|
enum effectDrainsTypes {
|
|
// mana pools
|
|
kDrainsManaRed = 1,
|
|
kDrainsManaOrange,
|
|
kDrainsManaYellow,
|
|
kDrainsManaGreen,
|
|
kDrainsManaBlue,
|
|
kDrainsManaViolet,
|
|
kDrainsLifeLevel,
|
|
kDrainsVitality,
|
|
kDrainsMoney
|
|
};
|
|
|
|
|
|
//
|
|
// TAG Effects - effects that apply when a TAG is the target
|
|
//
|
|
|
|
enum effectTAGTypes {
|
|
kSettagLocked = 1,
|
|
kSettagOpen = 2
|
|
};
|
|
|
|
|
|
//
|
|
// Location Effects - effects that apply when a Location is the target
|
|
//
|
|
|
|
enum kEffectLocationTypes {
|
|
kLocateDummy = 1
|
|
};
|
|
|
|
enum objectFlags {
|
|
kObjectOpen = (1 << 0), // object is in the "open" state
|
|
kObjectLocked = (1 << 1), // object cannot be opened
|
|
kObjectImportant = (1 << 2), // object must be recycled when trashed
|
|
kObjectGhosted = (1 << 3), // object drawn translucent
|
|
kObjectInvisible = (1 << 4), // object cannot be seen
|
|
kObjectObscured = (1 << 5), // object obscured by terrain
|
|
kObjectMoving = (1 << 6), // object has attached motion task
|
|
kObjectScavengable = (1 << 7), // object can be deleted
|
|
kObjectFloating = (1 << 8), // object not affected by Gravity
|
|
kObjectNoRecycle = (1 << 9), // object is referred to by script, don't delete
|
|
kObjectActivated = (1 << 10), // object is activated
|
|
kObjectAlias = (1 << 11), // object is not real, just a copy of another object
|
|
kObjectTriggeringTAG = (1 << 12), // object has triggerred TAG upon which it rests
|
|
kObjectOnScreen = (1 << 13), // object is on display list
|
|
kObjectSightedByCenter = (1 << 14) // there is a line of sight to center actor
|
|
};
|
|
|
|
|
|
//
|
|
// Special Effects - these are spells that need to be handled manually
|
|
//
|
|
|
|
enum effectSpecialTypes {
|
|
kSpecialDispellHelpfulEnch = 1, // clears helpful enchantments
|
|
kSpecialDispellHarmfulEnch, // clears harmful enchantments
|
|
kSpecialKill, // death spell
|
|
kSpecialRessurect, // raise dead spell
|
|
kSpecialTeleport, // Teleportation
|
|
kSpecialCreateActor, // Create an actor or wall
|
|
kSpecialSagaFunc, // calls a saga function
|
|
kSpecialCreateWWisp, // calls a saga function
|
|
kSpecialCreateFWisp, // calls a saga function
|
|
kSpecialCreateWraith, // calls a saga function
|
|
kSpecialCreateFood, // calls a saga function
|
|
kSpecialRejoin
|
|
};
|
|
|
|
// ------------------------------------------------------------------
|
|
// ENCHANTMENT IDs
|
|
// It is necessary to combine all these possibilities into a 16 bit integer
|
|
// Here's how its mapped
|
|
// 3 bits - general effect type
|
|
// 5 bits - sub class enum value
|
|
// 8 bits - damage amount, boolean on/off etc.
|
|
//
|
|
|
|
inline uint16 makeEnchantmentID(uint16 type, uint16 damtyp, int16 damamt) {
|
|
assert(type < 8);
|
|
assert(damtyp < 32);
|
|
assert(damamt < 128 && damamt > -128);
|
|
return ((type << 13) | (damtyp << 8)) + (damamt + 128);
|
|
}
|
|
|
|
/* skill* are now in the spellid enum ;AS;
|
|
inline uint16 makeEnchantmentID(effectAttribTypes atttyp, int16 damamt)
|
|
{ return (kEffectAttrib << 13) | (atttyp << 8) + (damamt+128); }
|
|
*/
|
|
|
|
inline uint16 makeEnchantmentID(effectResistTypes restyp, bool damamt) {
|
|
return ((kEffectResist << 13) | (restyp << 8)) + (damamt + 128);
|
|
}
|
|
|
|
inline uint16 makeEnchantmentID(effectImmuneTypes immtyp, bool damamt) {
|
|
return ((kEffectImmune << 13) | (immtyp << 8)) + (damamt + 128);
|
|
}
|
|
|
|
inline uint16 makeEnchantmentID(effectOthersTypes othtyp, bool damamt) {
|
|
return ((kEffectOthers << 13) | (othtyp << 8)) + (damamt + 128);
|
|
}
|
|
|
|
inline uint16 makeEnchantmentID(objectFlags othtyp, bool damamt) {
|
|
return ((kEffectNonActor << 13) | (othtyp << 8)) + (damamt + 128);
|
|
}
|
|
|
|
inline uint16 makeEnchantmentID(uint8 damamt) {
|
|
return ((kEffectPoison << 13) | (0 << 8)) + damamt;
|
|
}
|
|
|
|
inline effectTypes getEnchantmentType(uint16 eID) {
|
|
return (effectTypes)(eID >> 13);
|
|
}
|
|
|
|
inline uint16 getEnchantmentSubType(uint16 eID) {
|
|
return (eID >> 8) & 0x1F;
|
|
}
|
|
|
|
inline int16 getEnchantmentAmount(uint16 eID) {
|
|
return (eID & 0xFF) - 128;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Determine whether an enchantment is harmful
|
|
|
|
inline bool isHarmful(uint16 enchID) {
|
|
int16 typ = getEnchantmentType(enchID);
|
|
int16 sub = getEnchantmentSubType(enchID);
|
|
int16 amt = getEnchantmentAmount(enchID);
|
|
if (typ == kEffectAttrib) return amt < 0;
|
|
if (typ == kEffectOthers)
|
|
return (sub >= kActorSlowAttack && sub <= kActorBlind);
|
|
return false;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Determine whether an enchantment can fail
|
|
|
|
inline bool isSaveable(uint16 enchID) {
|
|
int16 typ = getEnchantmentType(enchID);
|
|
return (typ == kEffectOthers && isHarmful(enchID));
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Determine whether a damage type is magical
|
|
|
|
inline bool isMagicDamage(effectDamageTypes t) {
|
|
return t >= kDamageFire && t <= kDamageDirMagic;
|
|
}
|
|
|
|
#define Forever (255)
|
|
|
|
class SpellTarget;
|
|
|
|
//-------------------------------------------------------------------
|
|
// ProtoEffects
|
|
|
|
// This is the base class of several spell effect prototype classes
|
|
// The implement routine carries out the instantiation of a
|
|
// particular effect on a given target (doing damage or whatever)
|
|
|
|
|
|
class ProtoEffect {
|
|
//protected:
|
|
//int imp; // enchant or immediate
|
|
|
|
public:
|
|
ProtoEffect *_next; // pointer to additional effects
|
|
|
|
ProtoEffect() {
|
|
_next = NULL;
|
|
}
|
|
virtual ~ProtoEffect() {
|
|
if (_next) delete _next;
|
|
_next = NULL;
|
|
}
|
|
//int implementation( void ) { return imp; }
|
|
virtual bool applicable(SpellTarget &) {
|
|
return false;
|
|
}
|
|
virtual void implement(GameObject *, SpellTarget *, int8 = 0) {}
|
|
};
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
// ProtoDamage
|
|
// This class of effects does a range of damage to the target
|
|
|
|
class ProtoDamage: public ProtoEffect {
|
|
effectDamageTypes _type; // damage type
|
|
int8 _dice, // # of dice to roll
|
|
_sides, // # of sides on dice
|
|
_skillDice, // multiply by spellcraft to get additional dice
|
|
_base, // absolute damage amount
|
|
_skillBase; // absolute damage amount
|
|
int8 _self; // casts at self
|
|
|
|
public:
|
|
|
|
ProtoDamage(int8 d, int8 s, int8 sd, int8 b, effectDamageTypes t, int, bool afSelf = false, int8 sb = 0) {
|
|
_type = t;
|
|
_dice = d;
|
|
_sides = s;
|
|
_skillDice = sd;
|
|
_base = b;
|
|
_self = afSelf;
|
|
_skillBase = sb;
|
|
}
|
|
|
|
bool applicable(SpellTarget &trg);
|
|
|
|
void implement(GameObject *cst, SpellTarget *trg, int8 deltaDamage = 0);
|
|
|
|
static int16 getRelevantStat(effectDamageTypes dt, Actor *a);
|
|
};
|
|
|
|
//-------------------------------------------------------------------
|
|
// ProtoDrainage
|
|
// This class of effects does a range of damage to the target's
|
|
// mana, money or food supply
|
|
|
|
class ProtoDrainage: public ProtoEffect {
|
|
effectDrainsTypes _type; // damage type
|
|
int8 _dice, // # of dice to roll
|
|
_sides, // # of sides on dice
|
|
_skillDice, // multiply by spellcraft to get additional dice
|
|
_base; // absolute damage amount
|
|
int8 _self; // casts at self
|
|
|
|
public:
|
|
|
|
ProtoDrainage(int8 d, int8 s, int8 sd, int8 b, effectDrainsTypes t, int, bool afSelf = false) {
|
|
_type = t;
|
|
_dice = d;
|
|
_sides = s;
|
|
_skillDice = sd;
|
|
_base = b;
|
|
_self = afSelf;
|
|
}
|
|
|
|
bool applicable(SpellTarget &trg);
|
|
|
|
void implement(GameObject *cst, SpellTarget *trg, int8 deltaDamage = 0);
|
|
|
|
static int16 currentLevel(Actor *a, effectDrainsTypes edt);
|
|
static void drainLevel(GameObject *cst, Actor *a, effectDrainsTypes edt, int16 amt);
|
|
};
|
|
|
|
//-------------------------------------------------------------------
|
|
// ProtoEnchantment
|
|
// This can be any of several types of enchantments (see EFFECTS.H)
|
|
//
|
|
|
|
class ProtoEnchantment: public ProtoEffect {
|
|
uint16 _enchID;
|
|
uint32 _minEnch;
|
|
RandomDice _dice; // enchantment time
|
|
|
|
public:
|
|
ProtoEnchantment(uint16 e, uint32 loTime, uint32 hiTime) {
|
|
_enchID = e;
|
|
_dice = RandomDice(1, hiTime - loTime);
|
|
_minEnch = loTime;
|
|
}
|
|
|
|
bool applicable(SpellTarget &trg);
|
|
|
|
void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
|
|
|
|
bool canFail() {
|
|
return isSaveable(_enchID);
|
|
}
|
|
|
|
static bool realSavingThrow(Actor *a);
|
|
};
|
|
|
|
//-------------------------------------------------------------------
|
|
// ProtoTAGEffect
|
|
// this type of spell sets up spells that are used to alter tags
|
|
|
|
class ProtoTAGEffect: public ProtoEffect {
|
|
effectTAGTypes _affectBit;
|
|
int16 _onOff; // lock/unlock or trigger ID
|
|
ObjectID _trigger;
|
|
|
|
public:
|
|
ProtoTAGEffect(effectTAGTypes ett, int16 v, ObjectID t) {
|
|
_affectBit = ett;
|
|
_onOff = v;
|
|
_trigger = t;
|
|
}
|
|
|
|
bool applicable(SpellTarget &trg);
|
|
|
|
void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
|
|
};
|
|
|
|
//-------------------------------------------------------------------
|
|
// ProtoObjectEffect
|
|
// These effects are used only on non-actor objects.
|
|
|
|
class ProtoObjectEffect: public ProtoEffect {
|
|
uint16 _affectBit;
|
|
int16 _onOff;
|
|
RandomDice _dice; // enchantment time
|
|
|
|
public:
|
|
ProtoObjectEffect(uint16 e, int16 v, uint32 loT, uint32 hiT) {
|
|
_affectBit = e;
|
|
_onOff = v;
|
|
_dice = RandomDice(loT, hiT);
|
|
}
|
|
|
|
bool applicable(SpellTarget &trg);
|
|
|
|
void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
|
|
};
|
|
|
|
//-------------------------------------------------------------------
|
|
// If spells ever need to do things to Locations this
|
|
// is where they'll be
|
|
|
|
class ProtoLocationEffect: public ProtoEffect {
|
|
kEffectLocationTypes _affectBit;
|
|
int16 _value;
|
|
|
|
public:
|
|
ProtoLocationEffect(kEffectLocationTypes elt, int16 v) {
|
|
_affectBit = elt;
|
|
_value = v;
|
|
}
|
|
|
|
bool applicable(SpellTarget &) {
|
|
return (true);
|
|
}
|
|
|
|
void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
|
|
};
|
|
|
|
//-------------------------------------------------------------------
|
|
// ProtoSpecialEffects
|
|
// As always there are spells that just don't fit any of the other
|
|
// molds. These protoEffects allow customized spell handlers to be
|
|
// implemented.
|
|
//
|
|
|
|
typedef void SPELLIMPLEMENTATION(GameObject *, SpellTarget *);
|
|
|
|
#define SPECIALSPELL(name) void name(GameObject *cst, SpellTarget *trg)
|
|
|
|
class ProtoSpecialEffect: public ProtoEffect {
|
|
int16 _routineID;
|
|
SPELLIMPLEMENTATION *_handler;
|
|
|
|
public:
|
|
ProtoSpecialEffect(SPELLIMPLEMENTATION *newHandler, int16 callID = 0) {
|
|
_handler = newHandler;
|
|
_routineID = callID;
|
|
}
|
|
|
|
bool applicable(SpellTarget &) {
|
|
return true;
|
|
//return (trg.getType()==SpellTarget::spellTargetObject ||
|
|
// trg.getType()==SpellTarget::spellTargetObjectPoint) &&
|
|
// isActor(trg.getObject());
|
|
}
|
|
|
|
void implement(GameObject *, SpellTarget *trg, int8 deltaDamage = 0);
|
|
};
|
|
|
|
} // end of namespace Saga2
|
|
|
|
#endif
|