January 26, 2018

Ability Lua Tutorial 4: Troll Warlord's Fervor

Views: 273 Elfansoer

Troll Warlord's Fervor


a stack neverflow

Overview


There's not much to discuss for Fervor's base.txt and main lua. As a passive, Fervor does not require targetting filter and other important values, so the base.txt is pretty much similar to Spell Shield. There is one difference, however, that it states "SpellDispellable" as no. This is optional, since it only affects the tooltip.
The ability file is also as simple as Spell Shield. A copy-paste, in fact, since the ability is not required to do anything other than spawning the modifier.

The actual actions happened at modifier instead, so let's focus on that one.

Modifier: Characteristics


This modifier should appear at buff bar, hence we need to show it. Since it is not on the background anymore, its characteristics should be specified, such as:
  • Is it hidden?
  • Is it a debuff? (Otherwise is a buff)
  • Is it can be purged?
  • Is it removed on death?

So far, Spell Shield uses default values, but now they will be specified clearly. On the top, let's write:
modifier_troll_warlord_fervor_lua.lua

Those functions are pretty self-explanatory, I think. You can always omit these functions, and the answers should fall back to its default value.

Modifier: Stack


As always, let's start with gathering information. The obvious would be the attack speed bonus per stack, and stack limit.
Another function to call at the start of modifier's creation is to set its stack count.

A stack in a modifier does not mean anything; not even the number of that modifier exist on the parent. It simply an integer storage. If not specified, it has default value of 0, and is not displayed.

Since it is a storage, the value may be set, retrieved and modified as needed. Once set, the modifier icon will display its value (if it is shown at all).
Let's set its stack.
modifier_troll_warlord_fervor_lua.lua

When leveling up, Troll should not lose his stack, so just leave it as is on refresh.

Modifier: Dynamic Property


Like Spell Shield, Fervor will modify a property, which is attack speed. The twist is that the attack speed depends on the number of stacks.
A simple algebra would be "stack_count" times "stack multiplier".
Another twist for the ability is that when Troll's passive is disabled (break), the modifier should not give bonus. To check whether the parent has break applied, call PassivesDisabled().
No bonus means 0, what's easier than setting return to zero than multiplying it with zero?

Now, we declare its function, then implements the function as described:
modifier_troll_warlord_fervor_lua.lua


Modifier: Event Listener


This is a new concept, but I think you know what it means. The modifier listens to an event, and should respond accordingly.

Declare Listener


In the same manner as modifying property, we declare which event should it listen.
Fervor needs to track the attack's target, and should change its stack when Troll has just finished his attack point. Therefore, we'll use this one:
modifier_troll_warlord_fervor_lua.lua


Listener's params


See that "params" over there? It is there for a reason. The "params" table gives information about what happened during the event.
You can use Lua's print() to know all possible key-values it holds (see P.S.), but mostly you'll want:
  • params.attacker: returns unit table of the attacker.
  • params.target: returns unit table of the target.
  • params.damage: attack damage value that the attacker threw.

IsServer()


Valve made a twist that each modifier is run separately between client and server. Generally, game logic should be done on server, and visual effects should be done on client. What we're gonna do is game logic, so we'll use IsServer() to keep any game logic done in server.

Global Listener


When a listener is declared, the modifier will listen to anything. This means that for any unit in-game which has finished their attack, this function will be called. We don't want that. We only want the modifier to listen only when its parent is attacking.
In order to specify it, a filter is needed.

A standard way is to check whether the attacker is this modifier's parent:
modifier_troll_warlord_fervor_lua.lua

Now the events have been filtered, it's now about the action.

Logic: Custom Variables and Functions


Storing Custom Variables


Fervor's logic wants to compare if the currently attacked target is the same as previous target.
How do we know? We don't know. But if you store this current target into a variable, next time this function is called, we know the previous target.
Storing as "self.var_name" means that the variable will be available as long as the modifier is alive.
Our code now should be:
modifier_troll_warlord_fervor_lua.lua

An important thing though, the very first time this function is called, "self.currentTarget" is a nil value, and Lua may yell at you if you try to compare with a nil. A good way is to initialize it when created:
modifier_troll_warlord_fervor_lua.lua


Creating Custom Functions


The piece of code above lacks something: increasing the stack. But it may get crowded if we just fill all logic there. A separate custom function may help, and here's how to define it:
Code:
function <modifier_name>:functionName( some, parameters, here, if, any ) end

In my case, I want a separate (helper) function for increasing the stack, and another function to reset.
The code changed into:
modifier_troll_warlord_fervor_lua.lua

Try to understand by yourself why the helper function is written that way, ok?

Finally, here's the complete code.

Conclusion


I hope that this part will give you insights about variables, event listener, and defining a response when an event occured.
Next time, we'll get into more action, using Ogre Magi's Fireblast; a unit-targeted ability. Stay tuned!

Questions, Comments, and Critics are always welcomed.

References

P.S. forp print()


If you're not sure what a table (such as "params" above) contains, you can use this piece of code as the logic:
code