Spell system

How do spells work?

Behavior of each spell is defined in 3 places: database, spell scripts, and spell system code interpreting that database. Mortals should care mostly about first two which are discussed in this article.

Database

The database part includes data extracted from client loaded from dbc files: 

Spell.dbc, ...

As this data is extracted from client. It doesn't contain spells needed only serverside, those need to be added inside supplementary db tables in core which are emulating dbcs and have the same structure: 

spell_dbc Note: Not longer used since Warlords of Draenor Expansion (see Hotfixes, at least spell, spell_misc & spell_effect) 

spelldifficulty_dbc

Data stored in dbcs is extracted from client, ergo it may not be interpreted by TC properly, so it's meaning is a subject of changes and fixing, as dbcs contain most of the data needed by spell system to work.

Data not needed by client for all spells is stored in following tables of world db:

conditions 

-CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET - allows you to define requirements for implicit area targets of the spell, only matching targets will be added to spell target list

-CONDITION_SOURCE_TYPE_SPELL - allows you to define requirements for caster/explicit target of the spell, if not met cast will fail

-CONDITION_SOURCE_TYPE_SPELL_PROC - allows you to define requirements for actor and actionTarget, if not met proc will fail

-CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT

-CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE

-CONDITION_SOURCE_TYPE_VEHICLE_SPELL

spell_area - defines if aura should be applied to an object in given area

spell_enchant_proc_data - defines behavior of item enchant procs

spell_group_stack_rules - defines stacking rules for each group

spell_group - allows grouping spells for convenient handling

spell_learn_spell - defines that learning a given spell should learn you other spell, if not provided in dbcs

spell_linked_spell - allows simple triggering spell casts on certain spell events

spell_pet_auras - defines if a certain aura on pet owner should be linked to other aura on pet

spell_proc_event - defines a requirement which needs to be passed for proc event to occur

spell_proc - same as spell_proc_event, table in development

spell_required - defines requirements for learning a spell

spell_ranks - implements a concept of spell rank ingame

spell_script_names - binds spells to their spell scripts

spell_target_position - allows setting target location for certain spells

spell_threat - contains threat data for spells

Developers are expected to fill those tables correctly to make spells work correctly. Please follow links for more details about each table.

Spell scripts

Spell scripts are a way to provide a means of implementing more complicated behavior, which couldn't be placed in db.

Generic structure

As you see, there are 2 kinds of scripts: SpellScript and AuraScript. You may define both or just one of them in a single script.

Binding your script to a spell/spells

To make sure your script is executed you have to do two things (these are c++ requirements, I wish this was simpler).

  • create spell_script_names entry - As you've seen above each SpellScript/AuraScript is put inside of SpellScriptLoader class. Constructor of that class contains single parameter, that parameter is the value of ScriptName column inside spell_script_names table. The table consists of pairs (spellIdToWhichYouBindTheScript, "spell_script_you_re_binding"). You can bind one script to many spells or many scripts to one spell. The latter is needed for example when you want to logically separate scripts of a spell when spell is affected by different talents.
  • properly override AuraScript* GetAuraScript() const or SpellScript* GetSpellScript() const to create objects of your script
  • make sure SpellScriptLoader of your script is created - add a call in AddSC_XXXXX function. For more details on that, see CustomScript


Validation tests

Overriding validate function allows you to check if data you're using in your script is present on core load. It's often used to check if spell used in script is still in database, as spells are often removed from client database when client version changes.

When this function will return false, a "Spell `%u` did not pass Validate() function of script `%s` - script will be not added to the spell" error will appear in log.

You don't need to check for presence of effects you bind hooks to - it's checked automatically and reported on startup by core for your convenience.

Example - checks for existence of spells the script is using later:


Optional loading

Sometimes you may decide that you want your script only be present in some cases, bool Load() provides you a way to do so. When the function returns false your script will not be loaded to the object (Aura or Spell) - it will have no effect

Example - we want to script only player casts:

AuraScript hooks

TODO(smile)

SpellScript hooks

TODO(smile)

Good practices:

-always use Validate(SpellInfo const*) function to check all data you use in script for presence

-check for runtime errors, they often signal bad script behaviors

-put full spell name in comment before the script - this helps finding the script by spell name

Practical example on spell scripts

Going through line to line:

TODO(smile)