Ability Lua Tutorial 3: Anti Mage's Spell Shield - Elfansoer/dota-2-lua-abilities GitHub Wiki
Let's get our hands dirty.
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.
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.
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:
technical_name = class({})
in our case,
-- antimage_spell_shield_lua.lua
antimage_spell_shield_lua = class({})
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:
LinkLuaModifier( string className, string fileName, int motionType )
where:
-
className
: name of the class that will be included -
fileName
: path for the file (base path isscripts/vscripts
) -
motionType
: Fill this withLUA_MODIFIER_MOTION_NONE
for now
Now, the main file should looked like:
-- antimage_spell_shield_lua.lua
antimage_spell_shield_lua = class({})
LinkLuaModifier( "modifier_antimage_spell_shield_lua", "lua_abilities/antimage_spell_shield_lua/modifier_antimage_spell_shield_lua", LUA_MODIFIER_MOTION_NONE )
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:
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
antimage_spell_shield_lua = class({})
LinkLuaModifier( "modifier_antimage_spell_shield_lua", "lua_abilities/antimage_spell_shield_lua/modifier_antimage_spell_shield_lua", LUA_MODIFIER_MOTION_NONE )
function antimage_spell_shield_lua:GetIntrinsicModifierName()
return "modifier_antimage_spell_shield_lua"
end
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.
Err, Whats dis? For those who don't know about classes, let's say that there are 2 types of file: ability and 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.
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
modifier_antimage_spell_shield_lua = class({})
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:
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:
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 inAbilitySpecial
, 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
function modifier_antimage_spell_shield_lua:OnCreated( kv )
self.bonus = self:GetAbility():GetSpecialValueFor("bonus_resist_pct")
end
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
function modifier_antimage_spell_shield_lua:OnCreated( kv )
self.bonus = self:GetAbility():GetSpecialValueFor("bonus_resist_pct")
end
function modifier_antimage_spell_shield_lua:OnRefresh( kv )
self.bonus = self:GetAbility():GetSpecialValueFor("bonus_resist_pct")
end
Spell Shield grants bonus Magic Resistance. This falls into Modifying Property category. To modify a property, declare it using a function:
-- modifier_antimage_spell_shield_lua.lua
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:
-- modifier_antimage_spell_shield_lua.lua
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:
-- modifier_antimage_spell_shield_lua.lua
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
modifier_antimage_spell_shield_lua = class({})
function modifier_antimage_spell_shield_lua:OnCreated( kv )
self.bonus = self:GetAbility():GetSpecialValueFor("bonus_resist_pct")
end
function modifier_antimage_spell_shield_lua:OnRefresh( kv )
self.bonus = self:GetAbility():GetSpecialValueFor("bonus_resist_pct")
end
function modifier_antimage_spell_shield_lua:DeclareFunctions()
local funcs = {
MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS
}
return funcs
end
function modifier_antimage_spell_shield_lua:GetModifierMagicalResistanceBonus( params )
return self.bonus
end
What if the ability gives bonus magical resistance, but reducing its armor? Here:
-- modifier_antimage_spell_shield_lua_altered.lua
modifier_antimage_spell_shield_lua = class({})
function modifier_antimage_spell_shield_lua:OnCreated( kv )
self.bonus = self:GetAbility():GetSpecialValueFor("bonus_resist_pct")
self.armor = -7 --(bad practice here, write in base.txt instead)
end
function modifier_antimage_spell_shield_lua:OnRefresh( kv )
self.bonus = self:GetAbility():GetSpecialValueFor("bonus_resist_pct")
-- self.armor = -7 (no need to change constants)
end
function modifier_antimage_spell_shield_lua:DeclareFunctions()
local funcs = {
MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS,
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS,
}
return funcs
end
function modifier_antimage_spell_shield_lua:GetModifierMagicalResistanceBonus( params )
return self.bonus
end
function modifier_antimage_spell_shield_lua:GetModifierPhysicalArmorBonus( params )
return self.armor
end
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!