January 29, 2018

Ability Lua Tutorial 5: Ogre Magi's Fireblast

Views: 1848 Elfansoer

Ogre Magi's Fireblast


Straight to the action

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

Previously we've been dealt with passive abilities, which tends to do their action on their modifiers. Now, this unit-targetted ability will have actions that is defined in the main lua instead; modifier will be a simple tag without action.

Ability Form (.txt file)


The base .txt filled with things that have been covered in the first tutorial. Fireblast is a unit-targeted ability which target enemies that may be heroes or creeps, and deals magical damage that may be dispelled by strong dispel but cannot pierce spell immunity.

A question may be raised as to why the damage section is empty even though Fireblast do damages its target. The thing is, it does not have considerable impact as long as your code follows this form. If the form has "AbilityDamage" value, the code may call "Ability:GetAbilityDamage()" to retrieve it. If the form uses "AbilitySpecial" instead, then the code should use "Ability:GetSpecialValueFor("damage_key")" to obtain damage value(s). It's a matter of choice.

Introducing: Ability


Looking back at Tutorial 3, there was a point where a question is raised,
"What does this ability do?"

Back then, Spell Shield simply spawns a modifier and that's it. It's job is over. In contrast, Fireblast is an active ability; therefore it needs some action.

Looking at reference, there are several function which defines different phases of an active ability:
  • CastFilterResult()
  • OnAbilityPhaseStart()
  • OnAbilityPhaseInterrupted()
  • OnSpellStart()
  • OnChannelThink()
  • OnChannelFinish( bInterrupted )
The function itself is pretty self-explanatory; further explanations available in the reference.

In general, CastFilter is called when a player tries to cast it. PhaseStart defines the ability has just being cast with target has been selected (if any). PhaseInterrupted governs what happens if ability is stopped before its cast point (imagine when Shadow Fiend stopped his dance). SpellStart will do its actions right after ability finishes its cast point, mana is spent, and ability goes into cooldown. ChannelThink is called continuously during channeling until the channel is stopped by any reason, which then ChannelFinish will be called. If it is stopped by stun or other interruptions, bInterrupted is "true", "false" otherwise.

Ability: OnSpellStart


When Fireblast is fully cast, it deals damage to target and stunning them. All of these action happened after the spell started. Hence, we'll use this one:
ogre_magi_fireblast_lua.lua


Logic: Target Reference


Find all information required. Retrieve damage and stun values, but don't forget the target. When you want to do something on a target, you must know the target. A unit reference for this ability's target can be retrieved by calling "self:GetCursorTarget()". Don't forget to store them.
ogre_magi_fireblast_lua.lua


Logic: Apply Damage


I don't know if the original Fireblast applies its stun first or deal its damage first. I arbitrarily pick damage first. A damage instance can be dealt by calling this piece of code:
ApplyDamage

The main function is ApplyDamage( table ), though it requires a table as its parameter; therefore a temporary table "damageTable" is created before calling it.
See reference for damage type and flags values. Ability parameter is optional; when a modifier listen to "OnTakeDamage", this parameter will be shown in its "params".

Our code now looks like:
ogre_magi_fireblast_lua.lua

I don't have to elaborate on self:GetCaster(), right?

Logic: Add New Modifier


This is a bridge between abilities and modifiers; abilities creates modifiers to do some of its work for a certain unit. A modifier normally sticks to a unit, so this function should be invoked on unit references:
AddNewModifier


A little explanation here:
  • Source unit: A unit who is responsible in giving this modifier to target unit. Generally "self:GetCaster()"
  • Source ability: Same as above, ability version. Usually "self".
  • Modifier name: a string containing the modifier's technical name.
  • KV table: A table which will be passed as parameter to modifier's "OnCreated(kv)". Cannot contain tables as values. Set "duration" key into an integer/float value to determine modifier's duration.

Therefore, our ability file now should be:
ogre_magi_fireblast_lua.lua


Modifier: State


Onto the modifier. There are 4 main functions on a modifier. We have discussed on Modify Property and Event Listener in previous tutorial.
This is the third main function of a modifier: apply a state on its parent.

All possible state can be seen here, and modifying a parent's state has different invocation than previous two:
State

Think of this function as a switch: The parent will be stunned when its state is changed to true. As long as this modifier stays on that unit, it will be stunned.

Well, that's it. This modifier is a passive one, and no further action is needed. Here's the complete code for the modifier:
ogre_magi_fireblast_lua.lua

Oh, if you wonder about "IsStunDebuff()", it determines whether it should be dispelled by basic or strong dispel.

Conclusion


I hope this gives insights on creating a simple unit-targeted ability. Next time, let's add randomness using Chaos Knight's Chaos Bolt.
Sadly, when I said "next time" it won't be anytime soon; I have an upcoming test this week. So instead I'll say: To Be Continued.

References