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