Skip to content

Commit f1154f6

Browse files
FunZone513Perryvw
andauthored
New Lua Modifiers Page (#150)
* Create 5.md I did a thing mum * fix clientside not having barrier * Update 5.md Added Persistence to the barrier * Update sidebars.json Add to new modifier page sidebar * Update 5.md Changed the code block to a pastebin link * Update 5.md I'm a dumbass that can't spell * Update _articles/abilities/lua-modifiers/5.md Co-authored-by: Perry van Wesel <[email protected]> * Update sidebars.json oops * Update 5.md <br> broke it, removed * Update 5.md Shouldn't be cringe anymore, it worked locally too --------- Co-authored-by: Perry van Wesel <[email protected]>
1 parent 82ba593 commit f1154f6

File tree

2 files changed

+227
-1
lines changed

2 files changed

+227
-1
lines changed
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
---
2+
title: Generic Barrier Base Class
3+
author: Cykada
4+
steamId: '76561198066443130'
5+
date: 09.04.2024
6+
---
7+
8+
## Rundown
9+
10+
Barriers are a classic case of something dota has had introduced without being fully exposed to the modding API, so I've taken it upon myself to create a generic modifier class that can be inherited from in order to streamline barrier creation, and add some extra functionality to barriers in general.
11+
12+
Unfortunately, this won't add any functionality to any native barriers (Aphotic Shield, Shield Rune, Pipe of Insight, the cheese upgrade no-one cared about a week after the update, etc) since this is for custom barriers.
13+
14+
*Also uses the [Timers](https://github.com/ModDota/TypeScriptAddonTemplate/blob/master/src/vscripts/lib/timers.lua) library to avoid using the modifier's `OnIntervalThink()` function.*
15+
:::info
16+
[Link to the code](https://pastebin.com/M1E2zjku)
17+
:::
18+
19+
### Important Info
20+
:::caution
21+
The base class uses some of the default modifier functions, so it's important to use the replacement functions instead!
22+
:::
23+
- `OnCreated()``OnBarrierCreated()`
24+
- `OnRefresh()``OnBarrierRefresh()`
25+
- `DeclareFunctions()``DeclareBonusFunctions()`
26+
- `AddCustomTransmitterData()``AddBonusCustomTransmitterData()`
27+
28+
**These 4 functions behave the same as their respective default counterpart, but *must* be used instead, otherwise it will overwrite the base class version.**
29+
30+
There's also some properties that are used in the barrier class that shouldn't be overwritten, but they use `__name` naming so unless you plan on using that, it shouldn't be a problem.
31+
32+
Also worth noting;
33+
Because there are 3 types of barrier, each one corresponds to a specific damage type.
34+
- `DAMAGE_TYPE_PHYSICAL` is used for physical damage barriers (the red one)
35+
- `DAMAGE_TYPE_MAGICAL` is used for magical damage barriers (the blue one)
36+
- `DAMAGE_TYPE_PURE` is used for all damage barriers (the gold one)
37+
38+
When you set a damage barrier's damage type, make sure to use this list as a reference so you don't declare it incorrectly.
39+
40+
With that out of the way; Here's where the fun stuff begins.
41+
42+
43+
## Added Functions
44+
| Function | Return | Description |
45+
|-------|-------|-------|
46+
| SetBarrierType( [DAMAGE_TYPES](https://moddota.com/api/#!/vscripts/DAMAGE_TYPES) ) | *nil* | Set the barrier to block the specified type of damage. |
47+
| GetBarrierType() | [DAMAGE_TYPES](https://moddota.com/api/#!/vscripts/DAMAGE_TYPES) | Declare / Get what kind of damage the barrier blocks. Physical, Magical, or Pure (all damage). |
48+
| SetBarrierMaxHealth( int ) | *nil* | Set the max health of the barrier. |
49+
| GetBarrierMaxHealth() | int | Declare / Get the max health of the barrier. |
50+
| SetBarrierHealth( int ) | *nil* | Set the current health of the barrier. |
51+
| GetBarrierHealth() | int | Get the current health of the barrier. |
52+
| GetBarrierInitialHealth() | int | Declare / Get the initial health of the barrier. Defaults to `GetBarrierMaxHealth()`. |
53+
| IsBarrier() | bool | Returns true if this modifier is a barrier. |
54+
| IsBarrierFor( [DAMAGE_TYPES](https://moddota.com/api/#!/vscripts/DAMAGE_TYPES) ) | bool | Checks whether the barrier will block the specified type of damage. If you're checking the damage block type, use this function. If you're changing the damage block type, use `SetBarrierType()`. If you're declaring the damage block type, use `GetBarrierType()`. |
55+
| OnBarrierDamagedFilter( event ) | bool | A filter for damage to the barrier. Return false if you want the unit to be damaged instead. Set the `event.damage` to `0` if you want no damage to be done at all. (Only called on server) |
56+
| IsPersistent() | bool | Whether the barrier modifier will persist when the health reaches 0. False by default. |
57+
| ShowOnZeroHP() | bool | Whether the barrier bar is visible at 0 hp. If this is false and the barrier is at 0 hp, `IsBarrier()` will return false. |
58+
| BarrierUpdate() | *nil* | Updates the barrier. Not recommended to be called manually since it should update itself, but if you find a situation where there is a discrepancy then try this. |
59+
60+
61+
62+
## Okay but how do I use it?
63+
64+
I'm glad you asked.
65+
1. To start off, [grab the code](https://pastebin.com/M1E2zjku) then paste it into a lua file you've put somewhere in your vscripts folder. That is your `modifier_generic_barrier` class file. It's important to remember where you put it, because you'll need to know what the path is.
66+
2. When you create a new modifier you want to be a barrier, make sure to `require("path/modifier_generic_barrier")` so that you have access to the modifier class. You only need to do this once per file, so if you have multiple barrier modifiers in one file then you don't need to require it for each one!
67+
3. Make sure your new modifier inherits the base class by using `modifier_name = class(modifier_generic_barrier)`
68+
4. Declare the barrier's type using `GetBarrierType()`, and it's max health using `GetBarrierMaxHealth()`
69+
5. Enjoy your barrier!
70+
71+
72+
## Indepth example
73+
That's all well and good, but here is a little more indepth example of how to implement it.
74+
75+
Say we're creating a new modifier that we want to be a barrier, at the top of the file we'll have this:
76+
```lua
77+
require("modifier_generic_barrier") -- assuming the file is called 'modifier_generic_barrier' and is just inside the vscripts folder
78+
modifier_new_barrier = class(modifier_generic_barrier) -- our new modifier now inherits from the modifier_generic_barrier class
79+
```
80+
81+
We need to tell the barrier what type of damage it will block, so after that we'll put:
82+
```lua
83+
function modifier_new_barrier:GetBarrierType()
84+
return DAMAGE_TYPE_PHYSICAL -- barrier will block physical damage
85+
end
86+
```
87+
88+
And now we need to tell it how much health the barrier will have:
89+
```lua
90+
function modifier_new_barrier:GetBarrierMaxHealth()
91+
return self.barrier_hp -- how much health the barrier has
92+
end
93+
```
94+
95+
But wait a second, we used `self.barrier_hp` which isn't declared yet. So let's quickly do that:
96+
```lua
97+
function modifier_new_barrier:OnBarrierCreated() -- Use the new function!
98+
self.barrier_hp = self:GetAbility():GetSpecialValueFor("barrier_health")
99+
end
100+
```
101+
Take note of the fact that we used `OnBarrierCreated()` instead of `OnCreated()`, since we didn't want to overwrite the base class' `OnCreated()` function.
102+
103+
Now let's say we want the parent to have some bonus health regen while the barrier is active, so lets declare that real quick;
104+
```lua
105+
function modifier_new_barrier:OnBarrierCreated()
106+
self.barrier_hp = self:GetAbility():GetSpecialValueFor("barrier_health")
107+
108+
self.health_regen = self:GetAbility():GetSpecialValueFor("health_regen") -- We can declare properties as usual
109+
end
110+
111+
function modifier_new_barrier:DeclareBonusFunctions() -- Use the new function!
112+
return {
113+
MODIFIER_PROPERTY_HEALTH_REGEN_CONSTANT
114+
}
115+
end
116+
117+
function modifier_new_barrier:GetModifierConstantHealthRegen()
118+
return self.health_regen
119+
end
120+
```
121+
122+
So now we have health regen and a barrier, very convenient. But what if we add something else spicy to the mix... what if we want to regenerate mana based on the amount of damage blocked by the barrier? Is that possible? Yes!
123+
124+
Using the `OnBarrierDamageFilter()` function, we can handle any barrier damage instances we want, just as we would normally, and since it's called after the damage is checked but before it goes through, we don't need to do any checks of our own. We just need to add the ratio of damage to mana we want in our created function and we can then use it as we please.
125+
```lua
126+
function modifier_new_barrier:OnBarrierCreated()
127+
self.barrier_hp = self:GetAbility():GetSpecialValueFor("barrier_health")
128+
self.health_regen = self:GetAbility():GetSpecialValueFor("health_regen")
129+
130+
if IsServer() then -- we only need this on the server since our damage filter is server side only
131+
self.barrier_to_mana = self:GetAbility():GetSpecialValueFor("barrier_to_mana_percent")/100
132+
end
133+
end
134+
135+
function modifier_new_barrier:OnBarrierDamageFilter( event )
136+
local mana = event.damage
137+
138+
-- we need to make sure we don't gain more mana than we should if the damage will overkill the barrier
139+
local current_barrier = self:GetBarrierHealth()
140+
if current_barrier < event.damage then
141+
mana = event.damage - (event.damage - current_barrier)
142+
end
143+
144+
mana = mana * self.barrier_to_mana
145+
146+
self:GetParent():GiveMana( mana )
147+
148+
SendOverheadEventMessage(
149+
nil, -- sendToPlayer
150+
OVERHEAD_ALERT_MANA_ADD, -- messageType
151+
self:GetParent(), -- targetEntity
152+
mana, -- value
153+
nil -- sourcePlayer
154+
)
155+
156+
return true -- Make sure to return true!
157+
end
158+
```
159+
160+
Now we have a physical damage barrier that gives us health regen, and grants us mana based on the damage we take.
161+
In all, our new modifier file should look something like this:
162+
```lua
163+
require("modifier_generic_barrier")
164+
modifier_new_barrier = class(modifier_generic_barrier)
165+
166+
function modifier_new_barrier:GetBarrierType()
167+
return DAMAGE_TYPE_PHYSICAL
168+
end
169+
170+
function modifier_new_barrier:GetBarrierMaxHealth()
171+
return self.barrier_hp
172+
end
173+
174+
function modifier_new_barrier:OnBarrierCreated()
175+
self.barrier_hp = self:GetAbility():GetSpecialValueFor("barrier_health")
176+
self.health_regen = self:GetAbility():GetSpecialValueFor("health_regen")
177+
178+
if IsServer() then
179+
self.barrier_to_mana = self:GetAbility():GetSpecialValueFor("barrier_to_mana_percent")/100
180+
end
181+
end
182+
183+
function modifier_new_barrier:DeclareBonusFunctions()
184+
return {
185+
MODIFIER_PROPERTY_HEALTH_REGEN_CONSTANT
186+
}
187+
end
188+
189+
function modifier_new_barrier:GetModifierConstantHealthRegen()
190+
return self.health_regen
191+
end
192+
193+
function modifier_new_barrier:OnBarrierDamageFilter( event )
194+
local mana = event.damage
195+
196+
local current_barrier = self:GetBarrierHealth()
197+
if current_barrier < event.damage then
198+
mana = event.damage - (event.damage - current_barrier)
199+
end
200+
201+
mana = mana * self.barrier_to_mana
202+
203+
self:GetParent():GiveMana( mana )
204+
205+
SendOverheadEventMessage(
206+
nil, -- sendToPlayer
207+
OVERHEAD_ALERT_MANA_ADD, -- messageType
208+
self:GetParent(), -- targetEntity
209+
mana, -- value
210+
nil -- sourcePlayer
211+
)
212+
213+
return true
214+
end
215+
```
216+
217+
There we have it! A completely new barrier modifier using the base class. Pretty simple right? I hope so, that's the whole point of using the base class after all.
218+
219+
:::note
220+
There's a few functions I didn't go over in this guide, but the code has small descriptions for the major ones, and any function that doesn't have a description can be understood from its name.
221+
:::
222+
223+
:::info
224+
[Here's the code again](https://pastebin.com/M1E2zjku)
225+
:::

sidebars.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
"abilities/lua-modifiers/1",
4141
"abilities/lua-modifiers/2",
4242
"abilities/lua-modifiers/3",
43-
"abilities/lua-modifiers/4"
43+
"abilities/lua-modifiers/4",
44+
"abilities/lua-modifiers/5"
4445
]
4546
},
4647
"abilities/reutilizing-built-in-modifiers",

0 commit comments

Comments
 (0)