API:Spells
From WCell Wiki
This article is related to development using the WCell API.
Contents |
Example Code
- Can be found in the DefaultAddon:
- Spell fixes
How to start
- If you are interested into working with Spells, it is strongly recommended to start by creating and considering the Spell Dump
- Spell-customizations require to be done in the second Initialization pass which means that you will need a public static method like this:
[Initialization(InitializationPass.Second)]
public static void InitMySpells()
{
// do something here
}
- All Spells are comprised of up to over 100 fields and are defined in DBC Files.
- Every spell in the Spell Dump will look a little something like this:
Spell: ClassSkill Fireball Rank 1 (Id: 133) [ClassSkillFireballRank1] Line: MageFireball Next Rank: ClassSkill Fireball Rank 2 (Id: 143) Attributes: NotWhileShapeshifted FacingFlags: RequiresInFront StartTime: 1500 InterruptFlags: OnSilence, OnSleep, OnStunned, OnMovement ProcChance: 101 MaxLevel: 5 BaseLevel: 1 Level: 1 Duration: 4000 - 4000 (0) Visual: 67 PowerCostPercentage: 8 Range: 0 - 35 ProjectileSpeed: 24 Priority: 50 StartRecoveryCategory: 1500 StartRecoveryTime: 133 SpellClassSet: Mage SpellClassMask: 000000010000000000000008 DefenseType: Magic PreventionType: Magic SchoolMask: Fire Desc: Hurls a fiery ball that causes $s1 Fire damage and an additional $o2 Fire damage over $d. Skill: Fire (Levels: 0, 0, 0) Effect: SchoolDamage ImplicitTargetA: SingleEnemy BasePoints: 13 DiceSides: 9 RealPointsPerLevel: 0.6 Effect: ApplyAura (PeriodicDamage) ImplicitTargetA: SingleEnemy DiceSides: 1 Amplitude: 2000
- The value in [brackets] in the first line behind the Id is the official unique name, as to be found in the SpellId enum.
- The Line value is the id of the SpellLine, to be found in the SpellLineId enum.
Customizing values
- You can find out where and how certain fields are being used, by selecting the corresponding field of the Spell class in your IDE and then using the "Lookup references" feature
- Spell-related values are sometimes wrong by default and require correction
- You can override values of single spells:
var spell = SpellHandler.Get(SpellId.ClassSkillFireballRank1); spell.StartTime = 2000;
- Or apply changes to more than one Spell at a time, using SpellHandler.Apply or SpellLineId.Apply (applies the specified changes to all given Spells or the entire SpellLine (contains all ranks of a Spell)):
SpellLineId.MageConeOfCold.Apply(spell =>
{
spell.Range.MaxDist = 10;
});
SpellEffects
- Every Spell usually has 0-3 Effects (but more can be added)
- You can add and remove SpellEffects, using Spell.AddEffect, Spell.AddAuraEffect, Spell.RemoveEffect etc...
- There are over 100 types of Effects:
- Every SpellEffectType has its own SpellEffectHandler class and defines the effect's behavior when a Spell is casted
- During a SpellCast there will be a new SpellEffectHandler-instance created for every SpellEffect of the Spell being casted
- All default SpellEffectHandlers are defined in Spells/Effects/
- All non-default or missing Effects -including Dummy and anything with Script in it's name-, will need to be replaced or overridden
- The target for every SpellEffect might be different
- The way in which Targets are selected can be changed, the way the client selects the target, however, can *NOT* be changed (ie. you cannot change whether to target an area or your current selection etc)
- Targets will be determined, based on the ImplicitTargetA and ImplicitTargetB fields of the effects
- You can create a custom SpellEffectHandler for effects by setting the SpellEffectHandlerCreator field.
Auras
- All Spells with at least one SpellEffect that applies an Aura (eg. ApplyAura), are considered Auras that will be applied to the corresponding target
- There are more than 200 different kinds of Effects for Auras: See AuraType.cs
- AuraEffects with the same ImplicitTargets are grouped into one Aura (for example, one Spell can be beneficial to your own party and harmful to enemies at the same time - All aura effects that have ImplicitTarget = SomePartyTargetType will be applied to party members; whereas all aura effects that are against your foes will be grouped into a different kind of aura and applied to them)
- Every AuraEffect has its own AuraEffectHandler to be found in Spells/Auras/
- You can create a custom AuraEffectHandler for every effect by setting the AuraEffectHandlerCreator field (see Deserter example)
Aura Duration
- Auras might have a duration:
- Auras with a duration: Definitely cease to exist after the 'Duration' of the Spell in milliseconds
- Auras without duration: Never timeout
- -> Both types can still be cancelled if certain other conditions apply (eg. when attacked, charges run out etc), depending on how the Spell is defined
Periodic and non-periodic Auras
AuraEffects are said to be periodic if their Amplitude > 0:
- Periodic AuraEffects are applied repeatedly
- They "tick" (apply their effects) every Amplitude milliseconds
- One Aura can only have one Amplitude; for that it uses the first AuraEffect with a positive Amplitude
- -> Make sure that all periodic effects of an Aura have the same Amplitude (if that is not desired, split the Aura into two Spells)
- EXAMPLES:
- Periodically apply damage to a target
- Continuously remove more and more speed with every tick
- The non-periodic effects of an Aura are applied when the Aura is added to its target
- These effects apply an effect that will stay unmodified while the Aura is applied
- EXAMPLES:
- Increase or decrease stats on a target
- Change regeneration
- Talents that improve other spells
NOTE: Remove is only called once for both types of effects
Examples
Fireball
- The above mentioned Fireball has two default effects: SchoolDamage and ApplyAura (PeriodicDamage)
- Both effects are negative and will only be applied on your currently selected target, if it is hostile
- SchoolDamage will simply apply its EffectValue as damage of the given school to the enemy, on impact
- The Periodic Damage Aura will periodically damage the enemy every <Amplitude> milliseconds over a total of the Spell's Duration
Deserter (Id: 26013)
- Deserters are not allowed in Battlegrounds for a small amount of time
- But the Deserter spell only left a visible Aura and did nothing
- Here is how we fixed it, step by step:
1. Look at the Spell definition
- According to the Spell Dump the Deserter spell is defined as follows:
Spell: Deserter (Id: 26013) [Deserter] Attributes: Attr_8_0x100, CastableWhileDead, CastableWhileMounted, Attr_26_0x4000000, CastableWhileSitting, UnaffectedByInvulnerability AttributesEx: AttrEx_3_0x8, RemainStealthed, Negative AttributesExB: AttrExB_0_0x1, AttrExB_2_0x4, AttrExB_14_0x4000, DoesNotNeedShapeshift AttributesExC: PersistsThroughDeath, AttrExC_28_0x10000000 AttributesExD: AttrExD_2_0x4 ProcChance: 101 Duration: 900000 - 900000 (0) Range: 0 - 100 SchoolMask: Arcane Effect: ApplyAura (Dummy) ImplicitTargetA: Duel
2. What is it supposed to do?
- It is supposed to flag its wearer as Deserter during its duration
3. What *does* it do?
- The spell only applies one dummy aura-effect (as we can see it in the Spell definition above)
- We know, we have to do something because by default dummy-effects don't do anything and need special attention
4. Consider your options
- We usually want to re-use already existing code, but there is no default Aura-type that we could replace the Dummy with
- The only remaining option is to create a custom AuraEffectHandler
5. Write the code
- First we create a custom AuraDeserterHandler class (which extends AuraEffectHandler):
public class AuraDeserterHandler : AuraEffectHandler
{
protected override void Apply()
{
var chr = Owner as Character;
if (chr != null)
{
chr.Battlegrounds.IsDeserter = true;
}
}
protected override void Remove(bool cancelled)
{
var chr = m_aura.Auras.Owner as Character;
if (chr != null)
{
chr.Battlegrounds.IsDeserter = false;
}
}
}
- Then we set the dummy-effect's AuraEffectHandlerCreator-field:
SpellHandler.Apply(spell => {
spell.Effects[0].AuraEffectHandlerCreator = () => new AuraDeserterHandler();
},
SpellId.Deserter);
6. A little bit of magic
- Most spells can be fixed very easily, some however need a little bit of work (in the core or addons) to support the feature
- As you can see, the AuraDeserterHandler above does nothing but toggling one single bool property: IsDeserter
- In order to actually make this thing work we had to write the logic for that property first:
public bool IsDeserter
{
get { return m_isDeserter; }
set
{
m_isDeserter = value;
if (m_isDeserter)
{
CancelAllRelations();
}
}
}
- The property sets a single boolean value which the Battleground code uses at some points to prevent deserters from doing anything BG-related
- Also when activating the deserter flag, it will cancel all existing Battleground relations (queues, invitations etc)
What this code exactly does goes beyond Spell-handling and is only interesting for people who are interested into Battleground-core development.
However, as you can see: Creating or modifying any kind of spell to do almost anything, is not hard at all!
