1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
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.
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.
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.
23 * Declares EffectQueue class holding and processing all spell effects
25 * @author The GemRB Project
42 /** Maximum number of different Effect opcodes */
43 #define MAX_EFFECTS 512
45 ///** if the effect returns this, stop adding any other effect */
47 /** these effects don't stick around if used as permanent,
48 * in that case they modify a base stat like charisma modifier */
49 #define FX_PERMANENT 2
50 /** these effects never stick around, use them for instant effects like damage */
51 #define FX_NOT_APPLIED 3
52 /** these effects always stick around when applied as permanent or duration */
54 ///** insert the effect instead of push back */
57 //remove level effects flags
58 #define RL_DISPELLABLE 1 //only dispellables
59 #define RL_MATCHSCHOOL 2 //match school
60 #define RL_MATCHSECTYPE 4 //match secondary type
61 #define RL_REMOVEFIRST 8 //remove only one spell (could be more effects)
64 #define BNC_PROJECTILE 1
68 #define BNC_SECTYPE 0x10
69 #define BNC_RESOURCE 0x20
70 #define BNC_PROJECTILE_DEC 0x100
71 #define BNC_OPCODE_DEC 0x200
72 #define BNC_LEVEL_DEC 0x400
73 #define BNC_SCHOOL_DEC 0x800
74 #define BNC_SECTYPE_DEC 0x1000
75 #define BNC_RESOURCE_DEC 0x2000
78 #define IMM_PROJECTILE 1
82 #define IMM_SECTYPE 16
83 #define IMM_RESOURCE 32
84 #define IMM_PROJECTILE_DEC 0x100
85 #define IMM_OPCODE_DEC 0x200
86 #define IMM_LEVEL_DEC 0x400
87 #define IMM_SCHOOL_DEC 0x800
88 #define IMM_SECTYPE_DEC 0x1000
89 #define IMM_RESOURCE_DEC 0x2000
91 // FIXME: Dice roll should be probably done just once, e.g. when equipping
92 // the item, not each time the fx are applied
93 // <avenger> the dice values are actually level limits, except in 3 hp modifier functions
94 // the damage function is an instant (the other 2 functions might be tricky with random values)
95 //#define DICE_ROLL(max_val) ((fx->DiceThrown && fx->DiceSides) ? ((max_val >=0) ? (MIN( core->Roll( fx->DiceThrown, fx->DiceSides, 0 ), max_val )) : (MAX( core->Roll( fx->DiceThrown, fx->DiceSides, 0 ), max_val ))) : max_val)
97 //sometimes damage doesn't comply with the calculated value
98 #define DICE_ROLL(adjustment) (core->Roll( fx->DiceThrown, fx->DiceSides, adjustment) )
100 // You will need to get GameTime somehow to use this macro
101 #define PrepareDuration(fx) fx->Duration = (fx->Duration*AI_UPDATE_TIME + GameTime)
103 // often used stat modifications, usually Parameter2 types 0, 1 and 2
104 //these macros should work differently in permanent mode (modify base too)
105 #define STAT_GET(stat) (target->Modified[ stat ])
106 #define STAT_ADD(stat, mod) target->SetStat( stat, STAT_GET( stat ) + ( mod ), 0 )
107 #define STAT_SUB(stat, mod) target->SetStat( stat, STAT_GET( stat ) - ( mod ), 0 )
108 #define STAT_BIT_OR(stat, mod) target->SetStat( stat, STAT_GET( stat ) | ( mod ), 0 )
109 #define STAT_SET(stat, mod) target->SetStat( stat, ( mod ), 0 )
110 #define STAT_SET_PCF(stat, mod) target->SetStat( stat, ( mod ), 1 )
111 #define STAT_BIT_OR_PCF(stat, mod) target->SetStat( stat, STAT_GET( stat ) | ( mod ), 1 )
112 #define STAT_MUL(stat, mod) target->SetStat( stat, STAT_GET(stat) * ( mod ) / 100, 0 )
113 //if an effect sticks around
114 #define STATE_CURE( mod ) target->Modified[ IE_STATE_ID ] &= ~(ieDword) ( mod )
115 #define STATE_SET( mod ) target->Modified[ IE_STATE_ID ] |= (ieDword) ( mod )
116 #define EXTSTATE_SET( mod ) target->Modified[ IE_EXTSTATE_ID ] |= (ieDword) ( mod )
117 #define STATE_GET( mod ) (target->Modified[ IE_STATE_ID ] & (ieDword) ( mod ) )
118 #define EXTSTATE_GET( mod ) (target->Modified[ IE_EXTSTATE_ID ] & (ieDword) ( mod ) )
119 #define STAT_MOD( stat ) target->NewStat(stat, fx->Parameter1, fx->Parameter2)
120 #define STAT_MOD_VAR( stat, mod ) target->NewStat(stat, ( mod ) , fx->Parameter2 )
121 #define BASE_GET(stat) (target->BaseStats[ stat ])
122 #define BASE_SET(stat, mod) target->SetBase( stat, ( mod ) )
123 #define BASE_ADD(stat, mod) target->SetBase( stat, BASE_GET(stat)+ ( mod ) )
124 #define BASE_SUB(stat, mod) target->SetBase( stat, BASE_GET(stat)- ( mod ) )
125 #define BASE_MUL(stat, mod) target->SetBase( stat, BASE_GET(stat)* ( mod ) / 100 )
126 #define BASE_MOD(stat) target->NewBase( stat, fx->Parameter1, fx->Parameter2)
127 #define BASE_MOD_VAR(stat, mod) target->NewBase( stat, (mod), fx->Parameter2 )
128 //if an effect doesn't stick (and has permanent until cured effect) then
129 //it has to modify the base stat (which is saved)
130 //also use this one if the effect starts a cure effect automatically
131 #define BASE_STATE_SET( mod ) target->SetBaseBit( IE_STATE_ID, ( mod ), true )
132 #define BASE_STATE_CURE( mod ) target->SetBaseBit( IE_STATE_ID, ( mod ), false )
134 /** Prototype of a function implementing a particular Effect opcode */
135 typedef int (* EffectFunction
)(Scriptable
*, Actor
*, Effect
*);
138 /** Links Effect name to a function implementing the effect */
141 EffectFunction Function
;
145 /** Initializes table of available spell Effects used by all the queues. */
146 /** The available effects should already be registered by the effect plugins */
147 bool Init_EffectQueue();
149 /** Registers opcodes implemented by an effect plugin */
150 void EffectQueue_RegisterOpcodes(int count
, const EffectRef
*opcodes
);
152 /** release effect list when Interface is destroyed */
153 void EffectQueue_ReleaseMemory();
155 /** Check if opcode is for an effect that takes a color slot as parameter. */
156 bool IsColorslotEffect(int opcode
);
160 * Class holding and processing spell Effects on a single Actor
163 class GEM_EXPORT EffectQueue
{
165 /** List of Effects applied on the Actor */
166 std::list
< Effect
* > effects
;
167 /** Actor which is target of the Effects */
172 virtual ~EffectQueue();
174 /** Sets Actor which is affected by these effects */
175 void SetOwner(Scriptable
* act
) { Owner
= act
; }
176 /** Returns Actor affected by these effects */
177 Scriptable
* GetOwner() const { return Owner
; }
179 /** adds an effect to the queue, it could also insert it if flagged so
180 * fx should be freed by the caller
182 void AddEffect(Effect
* fx
, bool insert
=false);
183 /** Adds an Effect to the queue, subject to level and other checks.
184 * Returns FX_ABORT is unsuccessful. fx is just a reference, AddEffect()
185 * will malloc its own copy */
186 int AddEffect(Effect
* fx
, Scriptable
* self
, Actor
* pretarget
, const Point
&dest
) const;
187 /** Removes first Effect matching fx from the queue.
188 * Effects are matched based on their contents */
189 bool RemoveEffect(Effect
* fx
);
191 int AddAllEffects(Actor
* target
, const Point
&dest
) const;
192 void ApplyAllEffects(Actor
* target
) const;
193 /** remove effects marked for removal */
196 /* directly removes effects with specified opcode, use effect_reference when you can */
197 void RemoveAllEffects(ieDword opcode
) const;
198 void RemoveAllEffectsWithResource(ieDword opcode
, const ieResRef resource
) const;
200 /* removes any effects (delayed or not) which were using projectile */
201 void RemoveAllEffectsWithProjectile(ieDword projectile
) const;
203 /* removes equipping effects with specified inventory slot code */
204 void RemoveEquippingEffects(ieDwordSigned slotcode
) const;
206 /* removes all effects of a given spell */
207 void RemoveAllEffects(const ieResRef Removed
) const;
208 void RemoveAllEffects(const ieResRef Removed
, ieByte timing
) const;
209 /* removes all effects of type */
210 void RemoveAllEffects(EffectRef
&effect_reference
) const;
211 /* removes expired or to be expired effects */
212 void RemoveExpiredEffects(ieDword futuretime
) const;
213 /* removes all effects except timing mode 9 */
214 void RemoveAllNonPermanentEffects() const;
215 void RemoveAllDetrimentalEffects(EffectRef
&effect_reference
, ieDword current
) const;
216 void RemoveAllEffectsWithParam(EffectRef
&effect_reference
, ieDword param2
) const;
217 void RemoveAllEffectsWithResource(EffectRef
&effect_reference
, const ieResRef resource
) const;
218 void RemoveLevelEffects(ieDword level
, ieDword flags
, ieDword match
) const;
220 /* returns true if the timing method supports simplified duration */
221 static bool HasDuration(Effect
*fx
);
222 /* returns true if the effect should be saved */
223 static bool Persistent(Effect
* fx
);
224 /* returns next saved effect, increases index */
225 std::list
< Effect
* >::const_iterator
GetFirstEffect() const
227 return effects
.begin();
229 const Effect
*GetNextSavedEffect(std::list
< Effect
* >::const_iterator
&f
) const;
230 Effect
*GetNextEffect(std::list
< Effect
* >::const_iterator
&f
) const;
231 ieDword
CountEffects(EffectRef
&effect_reference
, ieDword param1
, ieDword param2
, const char *ResRef
) const;
232 void ModifyEffectPoint(EffectRef
&effect_reference
, ieDword x
, ieDword y
) const;
233 /* returns the number of saved effects */
234 ieDword
GetSavedEffectsCount() const;
235 size_t GetEffectsCount() const { return effects
.size(); }
236 /* this method hacks the offhand weapon color effects */
237 static void HackColorEffects(Actor
*Owner
, Effect
*fx
);
238 static Effect
*CreateEffect(EffectRef
&effect_reference
, ieDword param1
, ieDword param2
, ieWord timing
);
239 EffectQueue
*CopySelf() const;
240 static Effect
*CreateEffectCopy(Effect
*oldfx
, EffectRef
&effect_reference
, ieDword param1
, ieDword param2
);
241 static Effect
*CreateUnsummonEffect(Effect
*fx
);
243 Effect
*HasEffect(EffectRef
&effect_reference
) const;
244 Effect
*HasEffectWithParam(EffectRef
&effect_reference
, ieDword param2
) const;
245 Effect
*HasEffectWithParamPair(EffectRef
&effect_reference
, ieDword param1
, ieDword param2
) const;
246 Effect
*HasEffectWithResource(EffectRef
&effect_reference
, const ieResRef resource
) const;
247 Effect
*HasEffectWithSource(EffectRef
&effect_reference
, const ieResRef source
) const;
248 void DecreaseParam1OfEffect(EffectRef
&effect_reference
, ieDword amount
) const;
249 int SpecificDamageBonus(ieDword damage_type
) const;
250 bool HasAnyDispellableEffect() const;
251 //transforming timing modes
252 static void TransformToDelay(ieByte
&TimingMode
);
253 //getting summarised effects
254 int BonusAgainstCreature(EffectRef
&effect_reference
, Actor
*actor
) const;
255 //getting weapon immunity flag
256 bool WeaponImmunity(int enchantment
, ieDword weapontype
) const;
257 // checks if spells of type "types" are disabled (usually by armor)
258 // returns a bitfield of disabled spelltypes
259 int DisabledSpellcasting(int types
) const;
261 // returns -1 if bounced, 0 if resisted, 1 if accepted spell
262 int CheckImmunity(Actor
*target
) const;
263 // apply this effectqueue on all actors matching ids targeting
264 // from pos, in range (no cone size yet)
265 void AffectAllInRange(Map
*map
, const Point
&pos
, int idstype
, int idsvalue
, unsigned int range
, Actor
*except
);
266 /** Lists contents of the queue on a terminal for debugging */
269 static int ResolveEffect(EffectRef
&effect_reference
);
270 static bool match_ids(Actor
*target
, int table
, ieDword value
);
271 /** returns true if the process should abort applying a stack of effects */
272 int ApplyEffect(Actor
* target
, Effect
* fx
, ieDword first_apply
) const;
274 /** counts effects of specific opcode, parameters and resource */
275 ieDword
CountEffects(ieDword opcode
, ieDword param1
, ieDword param2
, const char *ResRef
) const;
276 void ModifyEffectPoint(ieDword opcode
, ieDword x
, ieDword y
) const;
277 //use the effect reference style calls from outside
278 static Effect
*CreateEffect(ieDword opcode
, ieDword param1
, ieDword param2
, ieWord timing
);
279 static Effect
*CreateEffectCopy(Effect
*oldfx
, ieDword opcode
, ieDword param1
, ieDword param2
);
280 void RemoveAllDetrimentalEffects(ieDword opcode
, ieDword current
) const;
281 void RemoveAllEffectsWithParam(ieDword opcode
, ieDword param2
) const;
282 Effect
*HasOpcode(ieDword opcode
) const;
283 Effect
*HasOpcodeWithParam(ieDword opcode
, ieDword param2
) const;
284 Effect
*HasOpcodeWithParamPair(ieDword opcode
, ieDword param1
, ieDword param2
) const;
285 Effect
*HasOpcodeWithResource(ieDword opcode
, const ieResRef resource
) const;
286 Effect
*HasOpcodeWithSource(ieDword opcode
, const ieResRef source
) const;
287 void DecreaseParam1OfEffect(ieDword opcode
, ieDword amount
) const;
288 int SpecificDamageBonus(ieDword opcode
, ieDword param2
) const;
289 int BonusAgainstCreature(ieDword opcode
, Actor
*actor
) const;
290 bool WeaponImmunity(ieDword opcode
, int enchantment
, ieDword weapontype
) const;
293 #endif // ! EFFECTQUEUE_H