Lua Abilities and Modifiers:ru

From Valve Developer Community
< Dota 2 Workshop Tools:ru
Revision as of 12:57, 23 March 2016 by Yunten (talk | contribs) (Created page with "Теперь у вас есть возможность создавать способности и модификаторы полностью используя Lua; Это...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Теперь у вас есть возможность создавать способности и модификаторы полностью используя Lua; Это позволяет создавать способности/модификаторы с необычными эффектами и продвинутой логикой скриптов.Lua-derived abilities and modifiers behave similarly to their in-game counterparts, calling out to certain virtual functions at certain times. As an author of a Lua ability or modifier, you have the choice of overriding those functions in your script.

Lua Способности

Для того чтобы создать Lua Способность, вам понадобится совершить несколько шагов :

В папке вашего аддона откройте scripts\npc\npc_abilities_custom.txt:

//=================================================================================================================
// Test My Ability
//=================================================================================================================
"test_lua_ability"
{
	// General
	//-------------------------------------------------------------------------------------------------------------
	"BaseClass"						"ability_lua"
	"ScriptFile"					        "test_lua_ability"


Для начала работы вашей Lua способности этого кода будет достаточно.


Далее в папке scripts\vscripts , вам необходимо создать файл с таким же именем которое вы указали в графе "ScriptFile" вашего npc_abilities_custom.txt . В нашем примере , название файла будет test_lua_ability.lua.


Открыв только что созданный файл, обозначьте новый Lua класс используя название вашей способности:

test_lua_ability = class ({})


Теперь у вас имеется основа для вашей Lua способности.Для того чтобы она начала действовать необходимо создать функции, которые движок игры будет вызывать при определенных условиях(script_help2 позволяет найти все эти функции).Несколько примеров.


Events

Движок вызывает данные функции при определенном состоянии способности.Добавьте их в свой скрипт если ваша способность должна функционировать при данном действии.

* OnSpellStart() -- Вызывается, когда закончилось время каста способности, ресурсы(мана) были потрачены - большинство способностей начинают свои действия здесь. Нет параметров.
* OnAbilityPhaseStart() -- Вызывается, когда начинается время каста способности W, ресурсы не были потрачены. Здесь могут быть условия при которых каст может быть успешном или безуспешным (Например враг слишком низкого уровня).Для этого добавьте в функцию return true или return false .
* OnAbilityPhaseInterrupted() -- Вызывается, когда способность была остановлена во время каста.
* OnProjectileThink( vLocation ) -- Если способность создала "projectile"((снаряд)стрела POTM,стан Леорика), данная функция будет вызываться до тех пор, пока снаряд движется, vLocation текущая позиция снаряда.
* OnProjectileHit( hTarget, vLocation ) -- Вызывается когда снаряд достиг цели, либо достиг максимальной дистанции. Если hTarget имеет значение null, это значит что снаряд исчез.Для того чтобы уничтожить снаряд добавьте в функцию  return true , для продолжения движения добавьте return false ( это применимо к линейным снарядам которые могут задеть множество юнитов, как Dragon Slave. Если снаряд достиг своей границы , он исчезнет даже если вы прописали return false ) 
* GetIntrinsicModifierName() -- Return возвращает название модификатора который пассивно добавляется способностью (например return "modifier_nevermore_necromastery" ).
* OnChannelFinish( bInterrupted ) -- Вызывается, когда применение способности было окончено(Lion's Mana Drain), параметр bInterrupted было применение успешным или оно было прервано.
* OnUpgrade() -- Вызывается, когда способность была улучшена.

Поведение при Использование

Как и обычные способности, ability_lua используют данные из npc_abilities_custom.txt для определения своих свойств, таких как кто может быть целью, mana cost, флаги(Например можно ли использовать на неуязвимых юнитов), какая команда может быть целью, а также поведение. Если ваша способность имеет разный эффект при различных условиях, вы можете данные из npc_abilities_custom.txt в вашем скрипте.

* GetBehavior() -- Определяет тип применения способности для изменения используйте  return DOTA_ABILITY_BEHAVIOR_UNIT_TARGET , а также другие значения с DOTA_ABILITY_BEHAVIOR.
* GetCooldown( nLevel ) -- Определяет cooldown способности. nLevel - уровень способности. Пример: return 37.0 .
* GetCastRange( vLocation, hTarget ) -- Определяет дальность применения. Пример: return 475 .
* GetChannelTime() -- Определяет время применения. Пример: return 5.0 .


Используя функция выше, вам скорее всего будет нужно возвращать стандартные данные при определенных условиях. Примером выступит Vengeful Spirit's Nether Swap; данная способность будет использовать измененную часть GetCooldown() если владелец имеет Aghanim's Scepter. В таких случаях, вы можете вызвать "BaseClass" для выполнения стандартной операции которая не использует ваши изменения в скрипте.

	if self:GetCaster():HasScepter() then
		return self:GetSpecialValueFor( "nether_swap_cooldown_scepter" )
	end

	return self.BaseClass.GetCooldown( self, nLevel )


Некоторые способности хотят использовать более красочные ошибки при использовании чем обычные. Для этого используется CastFilter. Основываясь на способе применения способности , вам надо выбрать нужную пару функцмий:

CastFilterResultTarget( hTarget ) -- hTarget юнит на которого использована способность.
GetCustomCastErrorTarget( hTarget) -- hTarget юнит на которого использована способность. 

CastFilterResultLocation( vLocation ) -- vLocation вектор куда использована способность.
GetCustomCastErrorLocation( vLocation ) -- vLocation вектор куда использована способность.

CastFilterResult() -- Если способность не имеет цели(DOTA_ABILITY_BEHAVIOR_NO_TARGET)
GetCustomCastError() -- Если способность не имеет цели(DOTA_ABILITY_BEHAVIOR_NO_TARGET)

Все функции CastFilterResult должны возвращать UnitFilterResult ( например UF_SUCCESS, UF_FAIL_CUSTOM ). Return UF_SUCCESS продолжает выполнять способность, а return UF_FAIL_CUSTOM выдает соответствующую ошибку используя GetCustomCastError.
Все функции GetCustomCastError должны возвращать строку(string) ( ведущую к соответствующей локализации в файле addon_english.txt )


Here is an example of a CastFilter from Vengeful Spirit's Nether Swap. Nether Swap's casting behavior allows creeps, but only if the caster has Aghanim's Scepter. Nether Swap also cannot be cast on Vengeful herself. Note that CastFilterResult and GetCustomCastError are shared functions, meaning they run on both server and client.

--------------------------------------------------------------------------------

function vengefulspirit_nether_swap_lua:CastFilterResultTarget( hTarget )
	if self:GetCaster() == hTarget then
		return UF_FAIL_CUSTOM
	end

	if ( hTarget:IsCreep() and ( not self:GetCaster():HasScepter() ) ) or hTarget:IsAncient() then
		return UF_FAIL_CUSTOM
	end

	local nResult = UnitFilter( hTarget, DOTA_UNIT_TARGET_TEAM_BOTH, DOTA_UNIT_TARGET_HERO + DOTA_UNIT_TARGET_CREEP, DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, self:GetCaster():GetTeamNumber() )
	if nResult ~= UF_SUCCESS then
		return nResult
	end

	return UF_SUCCESS
end

--------------------------------------------------------------------------------

function vengefulspirit_nether_swap_lua:GetCustomCastErrorTarget( hTarget )
	if self:GetCaster() == hTarget then
		return "#dota_hud_error_cant_cast_on_self"
	end

	if hTarget:IsAncient() then
		return "#dota_hud_error_cant_cast_on_ancient"
	end

	if hTarget:IsCreep() and ( not self:GetCaster():HasScepter() ) then
		return "#dota_hud_error_cant_cast_on_creep"
	end

	return ""
end

Properties

There are also several properties abilities have that are not exposed in npc_abilities_custom.txt. In general, you only want to override these functions if your ability wants special behavior different from the default. Some examples:

* IsStealable() -- Return true if Rubick can steal this spell.
* ProcsMagicStick() -- Return true if enemy heroes gain magic stick charges when this spell is cast.
* IsRefreshable() -- Return true if this spell can be refreshed.
* GetPlaybackRateOverride() -- Return the rate (float value) at which the cast animation should be played


Example

Here is the full script for a lua version of Vengeful Spirit's Nether Swap.

vengefulspirit_nether_swap_lua = class({})

--------------------------------------------------------------------------------

function vengefulspirit_nether_swap_lua:GetAOERadius()
	return self:GetSpecialValueFor( "radius" )
end

--------------------------------------------------------------------------------

function vengefulspirit_nether_swap_lua:CastFilterResultTarget( hTarget )
	if self:GetCaster() == hTarget then
		return UF_FAIL_CUSTOM
	end

	if ( hTarget:IsCreep() and ( not self:GetCaster():HasScepter() ) ) or hTarget:IsAncient() then
		return UF_FAIL_CUSTOM
	end

	local nResult = UnitFilter( hTarget, DOTA_UNIT_TARGET_TEAM_BOTH, DOTA_UNIT_TARGET_HERO + DOTA_UNIT_TARGET_CREEP, DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, self:GetCaster():GetTeamNumber() )
	if nResult ~= UF_SUCCESS then
		return nResult
	end

	return UF_SUCCESS
end

--------------------------------------------------------------------------------

function vengefulspirit_nether_swap_lua:GetCustomCastErrorTarget( hTarget )
	if self:GetCaster() == hTarget then
		return "#dota_hud_error_cant_cast_on_self"
	end

	if hTarget:IsAncient() then
		return "#dota_hud_error_cant_cast_on_ancient"
	end

	if hTarget:IsCreep() and ( not self:GetCaster():HasScepter() ) then
		return "#dota_hud_error_cant_cast_on_creep"
	end

	return ""
end

--------------------------------------------------------------------------------

function vengefulspirit_nether_swap_lua:GetCooldown( nLevel )
	if self:GetCaster():HasScepter() then
		return self:GetSpecialValueFor( "nether_swap_cooldown_scepter" )
	end

	return self.BaseClass.GetCooldown( self, nLevel )
end

--------------------------------------------------------------------------------

function vengefulspirit_nether_swap_lua:OnSpellStart()
	local hCaster = self:GetCaster()
	local hTarget = self:GetCursorTarget()

	if hCaster == nil or hTarget == nil or hTarget:TriggerSpellAbsorb( this ) then
		return
	end

	local vPos1 = hCaster:GetOrigin()
	local vPos2 = hTarget:GetOrigin()

	GridNav:DestroyTreesAroundPoint( vPos1, 300, false )
	GridNav:DestroyTreesAroundPoint( vPos2, 300, false )

	hCaster:SetOrigin( vPos2 )
	hTarget:SetOrigin( vPos1 )

	FindClearSpaceForUnit( hCaster, vPos2, true )
	FindClearSpaceForUnit( hTarget, vPos1, true )
	
	hTarget:Interrupt()

	local nCasterFX = ParticleManager:CreateParticle( "particles/units/heroes/hero_vengeful/vengeful_nether_swap.vpcf", PATTACH_ABSORIGIN_FOLLOW, hCaster )
	ParticleManager:SetParticleControlEnt( nCasterFX, 1, hTarget, PATTACH_ABSORIGIN_FOLLOW, nil, hTarget:GetOrigin(), false )
	ParticleManager:ReleaseParticleIndex( nCasterFX )

	local nTargetFX = ParticleManager:CreateParticle( "particles/units/heroes/hero_vengeful/vengeful_nether_swap_target.vpcf", PATTACH_ABSORIGIN_FOLLOW, hTarget )
	ParticleManager:SetParticleControlEnt( nTargetFX, 1, hCaster, PATTACH_ABSORIGIN_FOLLOW, nil, hCaster:GetOrigin(), false )
	ParticleManager:ReleaseParticleIndex( nTargetFX )

	EmitSoundOn( "Hero_VengefulSpirit.NetherSwap", hCaster )
	EmitSoundOn( "Hero_VengefulSpirit.NetherSwap", hTarget )

	hCaster:StartGesture( ACT_DOTA_CHANNEL_END_ABILITY_4 )
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

Lua Modifiers

Modifiers work much in the same way as the Lua Abilities, but the setup is slightly different. Similar to the Lua Abilities, start with a .lua file named appropriate to the name. Here is an example from Sven's Warcry. At the top of that file, create a class with the same name as the file. In this case, modifier_sven_warcry_lua .

modifier_sven_warcry_lua = class({})
--------------------------------------------------------------------------------


There is an additional step that is unique to lua modifiers; you must register their use with the engine before creating them. A good place to do this is in the related ability file. Typically, modifiers are created by abilities, but not always; if that is the case, you can call them in your base game mode script. The only requirement is that it is called before any instances of the modifier are created. Because modifier_sven_warcry_lua is related to the Warcry ability, it can be registered there. Note that this is found in the "sven_warcry_lua.lua" file, which is different than the file the modifier is defined in.

sven_warcry_lua = class({})
LinkLuaModifier( "modifier_sven_warcry_lua", LUA_MODIFIER_MOTION_NONE )

--------------------------------------------------------------------------------


The first parameter is the name (also the script file name) of the modifier you're registering; the second parameter is an enum type LuaModifierType, which is used to establish which, if any, motion controller type the modifier will apply on its parent. The different types are as follows:

* LUA_MODIFIER_MOTION_NONE - No motion controllers
* LUA_MODIFIER_MOTION_HORIZONTAL - Horizontal Motion Controller
* LUA_MODIFIER_MOTION_VERTICAL - Vertical Motion Controller
* LUA_MODIFIER_MOTION_BOTH - Both Horizontal and Vertical Motion


The modifier is now setup and can be added via the normal methods of adding modifiers. Note that new in this update, Modifiers (CDOTA_Buff) is an understood type in Lua, so you can create locals from them and call functions on them (see script_help2 for a full list), which is useful when defining your own modifier. Much like Abilities, the lua Modifier is overriding function calls from the engine. Many modifiers call a similar set of functions that are unrelated to their specific function and useful for basic setup and declaring variables. Here are some examples:

* OnCreated( kv ) -- Called when the modifier is created, with a table of values in "kv". Client/Server. No return type.
* OnRefresh( kv ) -- Called when the modifier is refreshed (created when already existing ). Client/Server, No return type.
* IsHidden() -- Return true if this modifier should not appear on the buff bar. Client/Server, boolean return type.
* IsDebuff() -- Return true if this modifier should appear as a debuff on the buff bar. Client/Server, boolean return type.
* IsPurgable() -- Return true if this modifier can be purged. Client/Server, boolean return type.
* GetEffectName() -- Return the name of the particle effect that is applied on the parent when this buff is active. Client/Server, string return type.


Note that these functions will be called separately on the client and the server. In general, it is best to perform game logic only on the server. Client functionality on modifiers is typically only used for tooltip reasons (so that bonuses show correctly in the HUD). If you are getting Lua errors when creating your modifier in the game, but the modifier still performs its game logic correctly, this is usually a sign of trying to do game logic on the client.


Modifier Functions

A function many lua modifiers want to use is DeclareFunctions(). This function should return a table of events and properties that your modifier wants to affect. The full list of the enum and function values is quite extensive, and can be seen by typing script_help2 in the game. Here is an example from Sven's Warcry modifier. This modifier wants to affect its parent's armor and movement speed, so in DeclareFunctions it must return the related enum values.

function modifier_sven_warcry_lua:DeclareFunctions()
	local funcs = {
		MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE,
		MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS,
		MODIFIER_PROPERTY_TRANSLATE_ACTIVITY_MODIFIERS,
	}

	return funcs
end


The second step in affecting the above properties is to override their associated functions. Each property expects a specific function name.

--------------------------------------------------------------------------------

function modifier_sven_warcry_lua:GetActivityTranslationModifiers( params )
	if self:GetParent() == self:GetCaster() then
		return "sven_warcry"
	end

	return 0
end

--------------------------------------------------------------------------------

function modifier_sven_warcry_lua:GetModifierMoveSpeedBonus_Percentage( params )
	return self.warcry_movespeed
end

--------------------------------------------------------------------------------

function modifier_sven_warcry_lua:GetModifierPhysicalArmorBonus( params )
	return self.warcry_armor
end

--------------------------------------------------------------------------------


The params parameter is common to all property and event related functions. It is a table loaded with contents that are specific to the event happening at the time. Using a loop and Msg() function, you can print the contents of the table. Warcry's property functions are quite simple, so here is an example from Sven's Great Cleave where this is used. Note that property functions are Client and Server, so gameplay logic is only being performed on the Server.

--------------------------------------------------------------------------------

function modifier_sven_great_cleave_lua:DeclareFunctions()
	local funcs = {
		MODIFIER_EVENT_ON_ATTACK_LANDED,
	}

	return funcs
end

--------------------------------------------------------------------------------

function modifier_sven_great_cleave_lua:OnAttackLanded( params )
	if IsServer() then
		if params.attacker == self:GetParent() and ( not self:GetParent():IsIllusion() ) then
			if self:GetParent():PassivesDisabled() then
				return 0
			end

			local target = params.target
			if target ~= nil and target:GetTeamNumber() ~= self:GetParent():GetTeamNumber() then
				local cleaveDamage = ( self.great_cleave_damage * params.damage ) / 100.0
				DoCleaveAttack( self:GetParent(), target, self:GetAbility(), cleaveDamage, self.great_cleave_radius, "particles/units/heroes/hero_sven/sven_spell_great_cleave.vpcf" )
			end
		end
	end
	
	return 0
end


OnIntervalThink

Some modifiers want to perform gameplay logic on certain intervals. You can do this by calling StartIntervalThink() on the modifier. Once the interval has been started, the engine will look for the function OnIntervalThink(), which will be called each time the think interval happens. The think can be stopped by calling StartIntervalThink() with -1 as the parameter. Lina's Fiery Soul makes use of these functions, here is an example:

--------------------------------------------------------------------------------

function modifier_lina_fiery_soul_lua:OnIntervalThink()
	if IsServer() then
		self:StartIntervalThink( -1 )
		self:SetStackCount( 0 )
	end
end

--------------------------------------------------------------------------------

function modifier_lina_fiery_soul_lua:OnAbilityExecuted( params )
	if IsServer() then
		if params.unit == self:GetParent() then
			if self:GetParent():PassivesDisabled() then
				return 0
			end

			local hAbility = params.ability 
			if hAbility ~= nil and ( not hAbility:IsItem() ) and ( not hAbility:IsToggle() ) then
				if self:GetStackCount() < self.fiery_soul_max_stacks then
					self:IncrementStackCount()
				else
					self:SetStackCount( self:GetStackCount() )
					self:ForceRefresh()
				end

				self:SetDuration( self.duration_tooltip, true )
				self:StartIntervalThink( self.duration_tooltip )
			end
		end
	end

	return 0
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


Thinkers

Sometimes modifiers want to do their gameplay effects around a location instead of around an NPC. In this situation you want to use a "thinker." Thinker modifiers are effectively invisible, invulnerable units with a modifier. Their structure is no different on the modifier side, but the creation is slightly different. Lina's Light Strike Array creates a delayed effect on an area, so a modifier thinker is used in this situation. Here's the example of how it is created:

--------------------------------------------------------------------------------

function lina_light_strike_array_lua:OnSpellStart()
	self.light_strike_array_aoe = self:GetSpecialValueFor( "light_strike_array_aoe" )
	self.light_strike_array_delay_time = self:GetSpecialValueFor( "light_strike_array_delay_time" )

	local kv = {}
	CreateModifierThinker( self:GetCaster(), self, "modifier_lina_light_strike_array_thinker_lua", kv, self:GetCursorPosition(), self:GetCaster():GetTeamNumber(), false )
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

One thing to remember with a thinker is that it is important to remove the dummy unit once the Thinker has expired. UTIL_Remove( self:GetParent() ) is a good way to do this. Doing this will also remove the modifier.

--------------------------------------------------------------------------------

function modifier_lina_light_strike_array_thinker_lua:OnIntervalThink()
	if IsServer() then
		GridNav:DestroyTreesAroundPoint( self:GetParent():GetOrigin(), self.light_strike_array_aoe, false )
		local enemies = FindUnitsInRadius( self:GetParent():GetTeamNumber(), self:GetParent():GetOrigin(), self:GetParent(), self.light_strike_array_aoe, DOTA_UNIT_TARGET_TEAM_ENEMY, DOTA_UNIT_TARGET_HERO + DOTA_UNIT_TARGET_BASIC, 0, 0, false )
		if #enemies > 0 then
			for _,enemy in pairs(enemies) do
				if enemy ~= nil and ( not enemy:IsMagicImmune() ) and ( not enemy:IsInvulnerable() ) then

					local damage = {
						victim = enemy,
						attacker = self:GetCaster(),
						damage = self.light_strike_array_damage,
						damage_type = DAMAGE_TYPE_MAGICAL,
						ability = self:GetAbility()
					}

					ApplyDamage( damage )
					enemy:AddNewModifier( self:GetCaster(), self:GetAbility(), "modifier_lina_light_strike_array_lua", { duration = self.light_strike_array_stun_duration } )
				end
			end
		end

		local nFXIndex = ParticleManager:CreateParticle( "particles/units/heroes/hero_lina/lina_spell_light_strike_array.vpcf", PATTACH_WORLDORIGIN, nil )
		ParticleManager:SetParticleControl( nFXIndex, 0, self:GetParent():GetOrigin() )
		ParticleManager:SetParticleControl( nFXIndex, 1, Vector( self.light_strike_array_aoe, 1, 1 ) )
		ParticleManager:ReleaseParticleIndex( nFXIndex )

		EmitSoundOnLocationWithCaster( self:GetParent():GetOrigin(), "Ability.LightStrikeArray", self:GetCaster() )

		UTIL_Remove( self:GetParent() )
	end
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


Modifier State

Separate from properties and events, modifiers can apply "state." Some examples of state include being stunned, being invisible, being phased, etc. The full list is detailed in script_help2 in the modifierstate enum. State is applied by adding the function CheckState() in your modifier. A common case is to apply a stun. Note that the syntax is slightly different from that of DeclareFunctions().

--------------------------------------------------------------------------------

function modifier_lina_light_strike_array_lua:CheckState()
	local state = {
	[MODIFIER_STATE_STUNNED] = true,
	}

	return state
end

Here is an example of the stun modifier that is applied from Light Strike Array.

modifier_lina_light_strike_array_lua = class({})

--------------------------------------------------------------------------------

function modifier_lina_light_strike_array_lua:IsDebuff()
	return true
end

--------------------------------------------------------------------------------

function modifier_lina_light_strike_array_lua:IsStunDebuff()
	return true
end

--------------------------------------------------------------------------------

function modifier_lina_light_strike_array_lua:GetEffectName()
	return "particles/generic_gameplay/generic_stunned.vpcf"
end

--------------------------------------------------------------------------------

function modifier_lina_light_strike_array_lua:GetEffectAttachType()
	return PATTACH_OVERHEAD_FOLLOW
end

--------------------------------------------------------------------------------

function modifier_lina_light_strike_array_lua:DeclareFunctions()
	local funcs = {
		MODIFIER_PROPERTY_OVERRIDE_ANIMATION,
	}

	return funcs
end

--------------------------------------------------------------------------------

function modifier_lina_light_strike_array_lua:GetOverrideAnimation( params )
	return ACT_DOTA_DISABLED
end

--------------------------------------------------------------------------------

function modifier_lina_light_strike_array_lua:CheckState()
	local state = {
	[MODIFIER_STATE_STUNNED] = true,
	}

	return state
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


Modifier Functions

--- Enum modifierfunction
MODIFIER_EVENT_ON_ABILITY_END_CHANNEL = 121 -- OnAbilityEndChannel
MODIFIER_EVENT_ON_ABILITY_EXECUTED = 118 -- OnAbilityExecuted
MODIFIER_EVENT_ON_ABILITY_FULLY_CAST = 119 -- OnAbilityFullyCast
MODIFIER_EVENT_ON_ABILITY_START = 117 -- OnAbilityStart
MODIFIER_EVENT_ON_ATTACK = 110 -- OnAttack
MODIFIER_EVENT_ON_ATTACKED = 127 -- OnAttacked
MODIFIER_EVENT_ON_ATTACK_ALLIED = 113 -- OnAttackAllied
MODIFIER_EVENT_ON_ATTACK_FAIL = 112 -- OnAttackFail
MODIFIER_EVENT_ON_ATTACK_LANDED = 111 -- OnAttackLanded
MODIFIER_EVENT_ON_ATTACK_RECORD = 108 -- OnAttackRecord
MODIFIER_EVENT_ON_ATTACK_START = 109 -- OnAttackStart
MODIFIER_EVENT_ON_BREAK_INVISIBILITY = 120 -- OnBreakInvisibility
MODIFIER_EVENT_ON_BUILDING_KILLED = 139 -- OnBuildingKilled
MODIFIER_EVENT_ON_DEATH = 128 -- OnDeath
MODIFIER_EVENT_ON_DOMINATED = 155 -- OnDominated
MODIFIER_EVENT_ON_HEALTH_GAINED = 134 -- OnHealthGained
MODIFIER_EVENT_ON_HEAL_RECEIVED = 138 -- OnHealReceived
MODIFIER_EVENT_ON_HERO_KILLED = 137 -- OnHeroKilled
MODIFIER_EVENT_ON_MANA_GAINED = 135 -- OnManaGained
MODIFIER_EVENT_ON_MODEL_CHANGED = 140 -- OnModelChanged
MODIFIER_EVENT_ON_ORB_EFFECT = 126
MODIFIER_EVENT_ON_ORDER = 115 -- OnOrder
MODIFIER_EVENT_ON_PROCESS_UPGRADE = 122
MODIFIER_EVENT_ON_PROJECTILE_DODGE = 114 -- OnProjectileDodge
MODIFIER_EVENT_ON_REFRESH = 123
MODIFIER_EVENT_ON_RESPAWN = 129 -- OnRespawn
MODIFIER_EVENT_ON_SET_LOCATION = 133 -- OnSetLocation
MODIFIER_EVENT_ON_SPELL_TARGET_READY = 107 -- OnSpellTargetReady
MODIFIER_EVENT_ON_SPENT_MANA = 130 -- OnSpentMana
MODIFIER_EVENT_ON_STATE_CHANGED = 125 -- OnStateChanged
MODIFIER_EVENT_ON_TAKEDAMAGE = 124 -- OnTakeDamage
MODIFIER_EVENT_ON_TAKEDAMAGE_KILLCREDIT = 136 -- OnTakeDamageKillCredit
MODIFIER_EVENT_ON_TELEPORTED = 132 -- OnTeleported
MODIFIER_EVENT_ON_TELEPORTING = 131 -- OnTeleporting
MODIFIER_EVENT_ON_UNIT_MOVED = 116 -- OnUnitMoved
MODIFIER_FUNCTION_INVALID = 255
MODIFIER_FUNCTION_LAST = 158
MODIFIER_PROPERTY_ABILITY_LAYOUT = 154 -- GetModifierAbilityLayout
MODIFIER_PROPERTY_ABSOLUTE_NO_DAMAGE_MAGICAL = 95 -- GetAbsoluteNoDamageMagical
MODIFIER_PROPERTY_ABSOLUTE_NO_DAMAGE_PHYSICAL = 94 -- GetAbsoluteNoDamagePhysical
MODIFIER_PROPERTY_ABSOLUTE_NO_DAMAGE_PURE = 96 -- GetAbsoluteNoDamagePure
MODIFIER_PROPERTY_ABSORB_SPELL = 84 -- GetAbsorbSpell
MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT = 19 -- GetModifierAttackSpeedBonus_Constant
MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT_POWER_TREADS = 20 -- GetModifierAttackSpeedBonus_Constant_PowerTreads
MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT_SECONDARY = 21 -- GetModifierAttackSpeedBonus_Constant_Secondary
MODIFIER_PROPERTY_ATTACK_POINT_CONSTANT = 24 -- GetModifierAttackPointConstant
MODIFIER_PROPERTY_ATTACK_RANGE_BONUS = 64 -- GetModifierAttackRangeBonus
MODIFIER_PROPERTY_ATTACK_RANGE_BONUS_UNIQUE = 65 -- GetModifierAttackRangeBonusUnique
MODIFIER_PROPERTY_AVOID_DAMAGE = 37 -- GetModifierAvoidDamage
MODIFIER_PROPERTY_AVOID_SPELL = 38 -- GetModifierAvoidSpell
MODIFIER_PROPERTY_BASEATTACK_BONUSDAMAGE = 2 -- GetModifierBaseAttack_BonusDamage
MODIFIER_PROPERTY_BASEDAMAGEOUTGOING_PERCENTAGE = 29 -- GetModifierBaseDamageOutgoing_Percentage
MODIFIER_PROPERTY_BASEDAMAGEOUTGOING_PERCENTAGE_UNIQUE = 30 -- GetModifierBaseDamageOutgoing_PercentageUnique
MODIFIER_PROPERTY_BASE_ATTACK_TIME_CONSTANT = 23 -- GetModifierBaseAttackTimeConstant
MODIFIER_PROPERTY_BASE_MANA_REGEN = 47 -- GetModifierBaseRegen
MODIFIER_PROPERTY_BONUS_DAY_VISION = 87 -- GetBonusDayVision
MODIFIER_PROPERTY_BONUS_NIGHT_VISION = 88 -- GetBonusNightVision
MODIFIER_PROPERTY_BONUS_NIGHT_VISION_UNIQUE = 89 -- GetBonusNightVisionUnique
MODIFIER_PROPERTY_BONUS_VISION_PERCENTAGE = 90 -- GetBonusVisionPercentage
MODIFIER_PROPERTY_BOUNTY_CREEP_MULTIPLIER = 105 -- GetModifierBountyCreepMultiplier
MODIFIER_PROPERTY_BOUNTY_OTHER_MULTIPLIER = 106 -- GetModifierBountyOtherMultiplier
MODIFIER_PROPERTY_CASTTIME_PERCENTAGE = 74 -- GetModifierPercentageCasttime
MODIFIER_PROPERTY_CAST_RANGE_BONUS = 63 -- GetModifierCastRangeBonus
MODIFIER_PROPERTY_CHANGE_ABILITY_VALUE = 153 -- GetModifierChangeAbilityValue
MODIFIER_PROPERTY_COOLDOWN_PERCENTAGE = 72 -- GetModifierPercentageCooldown
MODIFIER_PROPERTY_COOLDOWN_PERCENTAGE_STACKING = 73 -- GetModifierPercentageCooldownStacking
MODIFIER_PROPERTY_COOLDOWN_REDUCTION_CONSTANT = 22 -- GetModifierCooldownReduction_Constant
MODIFIER_PROPERTY_DAMAGEOUTGOING_PERCENTAGE = 25 -- GetModifierDamageOutgoing_Percentage
MODIFIER_PROPERTY_DAMAGEOUTGOING_PERCENTAGE_ILLUSION = 26 -- GetModifierDamageOutgoing_Percentage_Illusion
MODIFIER_PROPERTY_DEATHGOLDCOST = 76 -- GetModifierConstantDeathGoldCost
MODIFIER_PROPERTY_DISABLE_AUTOATTACK = 86 -- GetDisableAutoAttack
MODIFIER_PROPERTY_DISABLE_HEALING = 102 -- GetDisableHealing
MODIFIER_PROPERTY_DISABLE_TURNING = 151 -- GetModifierDisableTurning
MODIFIER_PROPERTY_EVASION_CONSTANT = 35 -- GetModifierEvasion_Constant
MODIFIER_PROPERTY_EXTRA_HEALTH_BONUS = 57 -- GetModifierExtraHealthBonus
MODIFIER_PROPERTY_EXTRA_HEALTH_PERCENTAGE = 59 -- GetModifierExtraHealthPercentage
MODIFIER_PROPERTY_EXTRA_MANA_BONUS = 58 -- GetModifierExtraManaBonus
MODIFIER_PROPERTY_EXTRA_STRENGTH_BONUS = 56 -- GetModifierExtraStrengthBonus
MODIFIER_PROPERTY_FIXED_DAY_VISION = 91 -- GetFixedDayVision
MODIFIER_PROPERTY_FIXED_NIGHT_VISION = 92 -- GetFixedNightVision
MODIFIER_PROPERTY_FORCE_DRAW_MINIMAP = 150 -- GetForceDrawOnMinimap
MODIFIER_PROPERTY_HEALTH_BONUS = 54 -- GetModifierHealthBonus
MODIFIER_PROPERTY_HEALTH_REGEN_CONSTANT = 52 -- GetModifierConstantHealthRegen
MODIFIER_PROPERTY_HEALTH_REGEN_PERCENTAGE = 53 -- GetModifierHealthRegenPercentage
MODIFIER_PROPERTY_IGNORE_CAST_ANGLE = 152 -- GetModifierIgnoreCastAngle
MODIFIER_PROPERTY_ILLUSION_LABEL = 98 -- GetModifierIllusionLabel
MODIFIER_PROPERTY_INCOMING_DAMAGE_PERCENTAGE = 31 -- GetModifierIncomingDamage_Percentage
MODIFIER_PROPERTY_INCOMING_PHYSICAL_DAMAGE_CONSTANT = 33 -- GetModifierIncomingPhysicalDamageConstant
MODIFIER_PROPERTY_INCOMING_PHYSICAL_DAMAGE_PERCENTAGE = 32 -- GetModifierIncomingPhysicalDamage_Percentage
MODIFIER_PROPERTY_INCOMING_SPELL_DAMAGE_CONSTANT = 34 -- GetModifierIncomingSpellDamageConstant
MODIFIER_PROPERTY_INVISIBILITY_LEVEL = 8 -- GetModifierInvisibilityLevel
MODIFIER_PROPERTY_IS_ILLUSION = 97 -- GetIsIllusion
MODIFIER_PROPERTY_IS_SCEPTER = 144 -- GetModifierScepter
MODIFIER_PROPERTY_LIFETIME_FRACTION = 147 -- GetUnitLifetimeFraction
MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS = 44 -- GetModifierMagicalResistanceBonus
MODIFIER_PROPERTY_MAGICAL_RESISTANCE_DECREPIFY_UNIQUE = 46 -- GetModifierMagicalResistanceDecrepifyUnique
MODIFIER_PROPERTY_MAGICAL_RESISTANCE_ITEM_UNIQUE = 45 -- GetModifierMagicalResistanceItemUnique
MODIFIER_PROPERTY_MAGICDAMAGEOUTGOING_PERCENTAGE = 28 -- GetModifierMagicDamageOutgoing_Percentage
MODIFIER_PROPERTY_MANACOST_PERCENTAGE = 75 -- GetModifierPercentageManacost
MODIFIER_PROPERTY_MANA_BONUS = 55 -- GetModifierManaBonus
MODIFIER_PROPERTY_MANA_REGEN_CONSTANT = 48 -- GetModifierConstantManaRegen
MODIFIER_PROPERTY_MANA_REGEN_CONSTANT_UNIQUE = 49 -- GetModifierConstantManaRegenUnique
MODIFIER_PROPERTY_MANA_REGEN_PERCENTAGE = 50 -- GetModifierPercentageManaRegen
MODIFIER_PROPERTY_MANA_REGEN_TOTAL_PERCENTAGE = 51 -- GetModifierTotalPercentageManaRegen
MODIFIER_PROPERTY_MAX_ATTACK_RANGE = 66 -- GetModifierMaxAttackRange
MODIFIER_PROPERTY_MIN_HEALTH = 93 -- GetMinHealth
MODIFIER_PROPERTY_MISS_PERCENTAGE = 39 -- GetModifierMiss_Percentage
MODIFIER_PROPERTY_MODEL_CHANGE = 142 -- GetModifierModelChange
MODIFIER_PROPERTY_MODEL_SCALE = 143 -- GetModifierModelScale
MODIFIER_PROPERTY_MOVESPEED_ABSOLUTE = 15 -- GetModifierMoveSpeed_Absolute
MODIFIER_PROPERTY_MOVESPEED_ABSOLUTE_MIN = 16 -- GetModifierMoveSpeed_AbsoluteMin
MODIFIER_PROPERTY_MOVESPEED_BASE_OVERRIDE = 11 -- GetModifierMoveSpeedOverride
MODIFIER_PROPERTY_MOVESPEED_BONUS_CONSTANT = 10 -- GetModifierMoveSpeedBonus_Constant
MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE = 12 -- GetModifierMoveSpeedBonus_Percentage
MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE_UNIQUE = 13 -- GetModifierMoveSpeedBonus_Percentage_Unique
MODIFIER_PROPERTY_MOVESPEED_BONUS_UNIQUE = 14 -- GetModifierMoveSpeedBonus_Special_Boots
MODIFIER_PROPERTY_MOVESPEED_LIMIT = 17 -- GetModifierMoveSpeed_Limit
MODIFIER_PROPERTY_MOVESPEED_MAX = 18 -- GetModifierMoveSpeed_Max
MODIFIER_PROPERTY_NEGATIVE_EVASION_CONSTANT = 36 -- GetModifierNegativeEvasion_Constant
MODIFIER_PROPERTY_OVERRIDE_ANIMATION = 81 -- GetOverrideAnimation
MODIFIER_PROPERTY_OVERRIDE_ANIMATION_RATE = 83 -- GetOverrideAnimationRate
MODIFIER_PROPERTY_OVERRIDE_ANIMATION_WEIGHT = 82 -- GetOverrideAnimationWeight
MODIFIER_PROPERTY_OVERRIDE_ATTACK_MAGICAL = 103 -- GetOverrideAttackMagical
MODIFIER_PROPERTY_PERSISTENT_INVISIBILITY = 9 -- GetModifierPersistentInvisibility
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS = 40 -- GetModifierPhysicalArmorBonus
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS_ILLUSIONS = 41 -- GetModifierPhysicalArmorBonusIllusions
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS_UNIQUE = 42 -- GetModifierPhysicalArmorBonusUnique
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS_UNIQUE_ACTIVE = 43 -- GetModifierPhysicalArmorBonusUniqueActive
MODIFIER_PROPERTY_PHYSICAL_CONSTANT_BLOCK = 78 -- GetModifierPhysical_ConstantBlock
MODIFIER_PROPERTY_PREATTACK_BONUS_DAMAGE = 0 -- GetModifierPreAttack_BonusDamage
MODIFIER_PROPERTY_PREATTACK_BONUS_DAMAGE_POST_CRIT = 1 -- GetModifierPreAttack_BonusDamagePostCrit
MODIFIER_PROPERTY_PREATTACK_CRITICALSTRIKE = 77 -- GetModifierPreAttack_CriticalStrike
MODIFIER_PROPERTY_PRESERVE_PARTICLES_ON_MODEL_CHANGE = 157 -- PreserveParticlesOnModelChanged
MODIFIER_PROPERTY_PRE_ATTACK = 7 -- GetModifierPreAttack
MODIFIER_PROPERTY_PROCATTACK_BONUS_DAMAGE_MAGICAL = 4 -- GetModifierProcAttack_BonusDamage_Magical
MODIFIER_PROPERTY_PROCATTACK_BONUS_DAMAGE_PHYSICAL = 3 -- GetModifierProcAttack_BonusDamage_Physical
MODIFIER_PROPERTY_PROCATTACK_BONUS_DAMAGE_PURE = 5 -- GetModifierProcAttack_BonusDamage_Pure
MODIFIER_PROPERTY_PROCATTACK_FEEDBACK = 6 -- GetModifierProcAttack_Feedback
MODIFIER_PROPERTY_PROJECTILE_SPEED_BONUS = 67 -- GetModifierProjectileSpeedBonus
MODIFIER_PROPERTY_PROVIDES_FOW_POSITION = 148 -- GetModifierProvidesFOWVision
MODIFIER_PROPERTY_REFLECT_SPELL = 85 -- GetReflectSpell
MODIFIER_PROPERTY_REINCARNATION = 68 -- ReincarnateTime
MODIFIER_PROPERTY_RESPAWNTIME = 69 -- GetModifierConstantRespawnTime
MODIFIER_PROPERTY_RESPAWNTIME_PERCENTAGE = 70 -- GetModifierPercentageRespawnTime
MODIFIER_PROPERTY_RESPAWNTIME_STACKING = 71 -- GetModifierStackingRespawnTime
MODIFIER_PROPERTY_SPELLS_REQUIRE_HP = 149 -- GetModifierSpellsRequireHP
MODIFIER_PROPERTY_STATS_AGILITY_BONUS = 61 -- GetModifierBonusStats_Agility
MODIFIER_PROPERTY_STATS_INTELLECT_BONUS = 62 -- GetModifierBonusStats_Intellect
MODIFIER_PROPERTY_STATS_STRENGTH_BONUS = 60 -- GetModifierBonusStats_Strength
MODIFIER_PROPERTY_SUPER_ILLUSION = 99 -- GetModifierSuperIllusion
MODIFIER_PROPERTY_SUPER_ILLUSION_WITH_ULTIMATE = 100 -- GetModifierSuperIllusionWithUltimate
MODIFIER_PROPERTY_TEMPEST_DOUBLE = 156 -- GetModifierTempestDouble
MODIFIER_PROPERTY_TOOLTIP = 141 -- OnTooltip
MODIFIER_PROPERTY_TOTALDAMAGEOUTGOING_PERCENTAGE = 27 -- GetModifierTotalDamageOutgoing_Percentage
MODIFIER_PROPERTY_TOTAL_CONSTANT_BLOCK = 80 -- GetModifierTotal_ConstantBlock
MODIFIER_PROPERTY_TOTAL_CONSTANT_BLOCK_UNAVOIDABLE_PRE_ARMOR = 79 -- GetModifierPhysical_ConstantBlockUnavoidablePreArmor
MODIFIER_PROPERTY_TRANSLATE_ACTIVITY_MODIFIERS = 145 -- GetActivityTranslationModifiers
MODIFIER_PROPERTY_TRANSLATE_ATTACK_SOUND = 146 -- GetAttackSound
MODIFIER_PROPERTY_TURN_RATE_PERCENTAGE = 101 -- GetModifierTurnRate_Percentage
MODIFIER_PROPERTY_UNIT_STATS_NEEDS_REFRESH = 104 -- GetModifierUnitStatsNeedsRefresh