Filters in general
This tutorial explains the use of the different filter functions currentlly in the API, and illustrates this using a small example in the order filter.
There are currently 9 filters available in the lua API, namely:
- AbilityTuningFilter - Filters abilities and all values they use on cast.
- BountyRunePickupFilter - Filters bounty rune pickups.
- DamageFilter - Filters damage events.
- ExecuteOrderFilter - Filters orders (usually given by players).
- ModifierGainedFilter - Filters modifiers events when they are first applied to a unit.
- ModifyExperienceFilter - Filters modifications of experience.
- ModifyGoldFilter - Filters modifications of gold.
- RuneSpawnFilter - Filters rune spawns.
- TrackingProjectileFilter - Filters tracking projectile launches.
These filters are set using functions like
CDOTABaseGameMode:SetExecuteOrderFilter(function, context), check the API declarations for the exact function name for each function. The filters can then be cleared again using functions like
CDOTABaseGameMode:ClearExecuteOrderFilter() and similar functions - again, see the API declarations .
The general idea
(This is the most important section of this entire tutorial)
The Source 2 engine listens for events, either generated by players or units in the game. The engine has a lot of handlers that determine what to do when a certain event is received. Filters get to look at these events before they reach the engine and have the opportunity to decide not to deliver the event, or maybe to deliver a modified version of the event.
An analogy to explain this is that of a company receiving mail. The regular situation would be the company(the engine) receiving mail (events) and reading them as usual. Now imagine a new secretary is hired(the filter) that reads every letter received and decides if the letter is important enough to be handled or not. This system is illustrated in the following picture:
Filters in Lua
So now we know how filters work, how do we use them. This explanation will use the
ExecuteOrderFilter, keep in mind that all filters use the same basic idea.
The first step is to set the filter using the
CDOTABaseGameMode:SetExecuteOrderFilter(function, context) API call. Let’s analyze what this function expects. There are two parameters:
Parameter: function - The filter function. This function is your actual filter. It is called every time the event you are filtering is called (in this case when an order arrives). The filter function receives two parameters: self and event. The self parameter is just the context of the function (and is hidden if you use Dynamic_Wrap and the : operator). The really interesting parameter is the event parameter. This parameter contains all the data of the event. Your filter function should look at this function and make a decision. There are three possible outcomes:
- You want to do nothing and accept the event, you
- You want to reject the event, it will be like this event never happened,
- You want to accept the event with some changes, all you have to do modify the event table and
Parameter: context - This parameter is what is passed into the filter function as self.
Example 1: Disabling glyph
Time to put into practice what we just used. We know the glyph is an order given by a player, so we should use the order filter to disable it. All we have to do is find any glyph orders and return false. Of course you can add any restriction you want based on the contents of the event parameter. Just
DeepPrintTable( event ) to see what data is available to you.
To check which order types there are, look at the wiki.
Note that in this example the : operator on
GameMode:OrderFilter hides the first (
--First set the filter to start catching events, usually this is in your init GameRules:GetGameModeEntity():SetExecuteOrderFilter(Dynamic_Wrap(GameMode, "OrderFilter"), self) --...................... --Add the order filter to your game mode entity function GameMode:OrderFilter(event) --Check if the order is the glyph type if event.order_type == DOTA_UNIT_ORDER_GLYPH then return false end --Return true by default to keep all other orders the same return true end
Example 2: Order modification
This example mimics a sort of ‘drunk’ state of a unit by adding a random offset to any movement orders. The code is pretty easy, all you have to do is modify the incoming order and return true.
--First set the filter to start catching events, usually this is in your init GameRules:GetGameModeEntity():SetExecuteOrderFilter(Dynamic_Wrap(GameMode, "OrderFilter"), self) --...................... --Add the order filter to your game mode entity function GameMode:OrderFilter(event) --Check if the order is the glyph type if event.order_type == DOTA_UNIT_ORDER_MOVE_TO_POSITION then local offsetVector = RandomVector(100) event.position_x = event.position_x + offsetVector.x event.position_y = event.position_y + offsetVector.y return true end --Return true by default to keep all other orders the same return true end