January 25, 2018

Ability Lua Tutorial 3: Antimage's Spell Shield

Views: 407 Elfansoer

Antimage: Spell Shield Lua


Let's get our hands dirty.

EDIT: Some links have been updated due to github repository change.

Ability Form Review


Take a brief look on the ability's .txt file. It's quite short, since it's a simple ability.
Notice that the ability has been renamed as "antimage_spell_shield_lua" in order to avoid collision with the real one.
It is a basic ability with a passive behavior, and nothing else. No need for cast points, unit targetting, spell immunity, etc etc. It also has just one ability specials, which defines the magic resistance bonus on each level.
In short, it's short.

Introducing: Main Lua File


Open up a text-editor, create new file and save it as "antimage_spell_shield_lua.lua", placed according to the .txt file. This will be the main script file, which defines what the ability does. Let's begin with the keypoints.

Class Identifier


You should generally want this particular line at the start of your lua files. This defines the start of a class for custom lua abilities.
So, at the first line of the file, write:
Code:
<technical_name> = class({})

in our case,
antimage_spell_shield_lua.lua


Modifier Linker


Since we're going to separate each class to their own files, they should be tagged here (in the main file), so the engine know that the ability need those extra files.
Spell Shield will have a file for its passive modifier named "modifier_antimage_spell_shield_lua" (more on this later), let's include it by calling:
Code:
LinkLuaModifier( string className, string fileName, int motionType ) where: className: name of the class that will be included fileName: path for the file (base path is "scripts/vscripts") motionType: Fill this with LUA_MODIFIER_MOTION_NONE for now

Now, the main file should looked like:
antimage_spell_shield_lua.lua


Ability Functions


This is the point where the great question finally asked,
"What does this ability do?"

You can read and try this tutorial if you want some real example, or this reference for a complete list of possible things a custom ability can do. If you decided to stick with me, then let's start with a simple passive.

To make the ability have a passive effect, create this function:
Code:
function <technical_name>:GetIntrinsicModifierName() return "modifier_name" end
By writing this, you override a base class function. Simply put, the engine asks the ability, "Do you have any passive modifier?"
Default answer is "no", but writing above code which returns the modifier name, (hang on, explanation is close) it answers, "yes, the name is <modifier_name>."

The Spell Shield ability should now be like:
antimage_spell_shield_lua.lua


Introducing: Modifier


Two main base class for Lua abilities are "CDOTA_Ability_Lua" and "CDOTA_Modifier_Lua". The first is for ability and the other is for modifier.

Ability is the thing that sticks with the hero; its code will be activated when the ability is used.
Modifier is the thing that sticks to a certain unit; a generalization of de/buff. Usually abilites create a modifier for a unit, and some time later the modifier may be destroyed, like a buff that expires. Once a modifier is created, its code will run as long as it exists in-game.

Generally, a modifier is created to:
  • Modify property of a unit
  • Change state of a unit
  • Listening events of a unit
  • Add forced movement to a unit
  • Do something that's independent from Caster (the one who casts ability)

Since Spell Shield is a passive ability, it simply applies a permanent modifier for the hero. Before that, however, the modifier should be defined.

Define a modifier


Create a blank file and save it as
"../lua_abilities/antimage_spell_shield_lua/modifier_antimage_spell_shield_lua.lua"

Inside, we do the same thing as the main file; Class Identifier:
modifier_antimage_spell_shield_lua.lua


Logic: Retrieving Information


We reach this point again, "What does this modifier do?". Here's the reference list of possible functions.

This is just a habit of mine that when a modifier is created, it should load information first. Hence, use this function:
Code:
function <modifier_name>:OnCreated( kv ) end function <modifier_name>:OnRefresh( kv ) end
I think they are pretty self-explanatory.

Spell Shield grants the caster 20%/30%/40%/50% bonus Magical Resistance; get the number first. They have been defined in base .txt file, and we'll gonna load that. Use:
Code:
self:GetAbility():GetSpecialValueFor("key_name")

Fancy? Quick explanation:
That function returns the value of the specified key according to the ability's level at the time it is called.
  • self: A reference to this modifier.
  • GetAbility(): A modifier function which gets the ability reference who created this modifier
  • GetSpecialValueFor(): An ability function which gets the value of the specified key
  • key_name: The key name in AbilitySpecial, from the base .txt file

When first learned, a modifier is created and the function above will return 20 as integer. Store this number in the modifier's table:
modifier_antimage_spell_shield_lua.lua


When Spell Shield is upgraded, the modifier will be refreshed (as per GetIntrinsicModifierName's definition), and we need to update its value
modifier_antimage_spell_shield_lua.lua


Modifier: Static Property


"Spell Shield grants bonus Magic Resistance". This falls into "Modifying Property" category. To modify a property, declare it using a function:
Code:
function modifier_antimage_spell_shield_lua:DeclareFunctions() local funcs = { MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS } return funcs end

Let's just write as is, or read this reference for other possible properties.

The above code is a declaration that "this modifier will give bonus magical resistance to the parent." (by the way, "parent" means the unit this modifier is attached to)

Once declared, it needs implementation. According to reference above, the appropriate function for MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS is "GetModifierMagicalResistanceBonus", so let's write it:
Code:
function modifier_antimage_spell_shield_lua:GetModifierMagicalResistanceBonus( params ) end

The reference says:
"Increases the magical resistance of the parent by a constant returned to it. Can return negative values."

Well, this is simple. It would be:
Code:
function modifier_antimage_spell_shield_lua:GetModifierMagicalResistanceBonus( params ) return self.bonus end

Now, the modifier is complete. Here's the full version:
modifier_antimage_spell_shield_lua.lua


Additional Bonus


What if the ability gives bonus magical resistance, but reducing its armor? Here:
modifier_antimage_spell_shield_lua.lua (altered)


Conclusion


I hope this may give insights in creating a modifier and specifying which property would be modified by modifier. Next on, we still create a passive ability, Troll Warlord's Fervor. This is a little more advance than Spell Shield, but it's still simple. See you later!

Questions, Comments, and Critics are always welcomed.

References