Lua技能和修改器

From Valve Developer Community
Jump to: navigation, search
English

Lua现在能完全重新指定Lua中的技能和修改器,如果你熟悉Lua以及技能/修改器,并且想做出更高级的逻辑和特效的话,这是十分合适的。Lua驱动的技能和修改器与其游戏中的版本相似它们会在某时调用某些虚函数。作为Lua的技能或者修改器的作者,你有机会在你的脚本中重写这些函数。

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 目录,以在npc_abilities_custom.txt文件中的"ScriptFile" 入口点建立同名文件。在本例子中,名字就是test_lua_ability.lua


在新建文件的顶行,用你刚才使用的名字声明一个新Lua类。

test_lua_ability = class ({})


现在你已正确地设置了一个基于Lua的技能函数。为使它发挥功能,需要以重写暴露在Ability_Lua类中的函数(你可以用script_help2来看到整个列表)为开始。因为这些函数与引擎交互,它们期望得到某些返回类型和参数。以下是一些例子。


事件

引擎会在技能中的某个时刻调用以下函数。如果你想让你的技能在这些时刻中发挥功能,请在你的脚本中加上它们。

* OnSpellStart() -- 当施法时间结束,资源已被消耗时 – 大多数技能在这个函数中发挥功能。无返回类型,无参数。
* OnAbilityPhaseStart() -- 当施法时间开始,资源未被消耗时。成功施法返回true,失败则返回false,无参数。
* OnAbilityPhaseInterrupted() -- 当施法时间由于任何原因取消时。无返回类型,无参数。
* OnProjectileThink( vLocation ) -- 如果该技能创建了一个发射物,此函数会在发射物飞行时多次被调用。vLocation是发射物当前位置。无返回类型。
* OnProjectileHit( hTarget, vLocation ) -- 当发射物飞行至它的最远距离,或者击中了与目标类型相符的NPC时。若hTarget为空,则意味着发射物已经失效。返回true来摧毁粒子,返回false则发射物继续飞行(应用于可以击中多个NPC的线性发射物,比如龙破斩。如果发射物已经到达终点,即使传入false也依然会失效)。
* GetIntrinsicModifierName() -- 返回由该技能被动添加的修改器的"modifier_name"。
* OnChannelFinish( bInterrupted ) -- 当持续施法结束时,bInterrupted参数指明持续施法是否被打断。无返回类型。
* OnUpgrade() -- 当技能升级时。无参数,无返回类型。

施法行为

就像普通技能。ability_lua会读取npc_abilities_custom.txt来决定许多属性,比如目标类型、魔法消耗、标志、队伍以及行为。如果你有个技能需要在不同条件下完成不同的操作,你可以在脚本中添加特定函数来重写默认行为。

* GetBehavior() -- 通过光标来判定目标行为的类型,从DOTA_ABILITY_BEHAVIOR枚举中返回期望值(如DOTA_ABILITY_BEHAVIOR_UNIT_TARGET, DOTA_ABILITY_BEHAVIOR_POINT)。
* GetCooldown( nLevel ) -- 当法术被释放后判定冷却开始。返回浮点值。
* GetCastRange( vLocation, hTarget ) -- 判定施法范围。返回整数值。
* GetChannelTime() -- 判定持续施法时间。返回浮点值。


使用以上函数时,你常常会在某种条件下返回默认行为。一个例子就是复仇之魂的移形换位。装备阿哈利姆神杖后,这个技能只要特殊的GetCooldown()行为。在这些情况下,你可以调用"BaseClass"来做,和你在平常没有在脚本中重写它一样。

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

	return self.BaseClass.GetCooldown( self, nLevel )


一些技能可能会想要产生比默认标志所允许内的更有表现力的自定义施法错误。这被称作CastFilter。根据技能的行为,你会想要选择以下函数对中的一对。

CastFilterResultTarget( hTarget ) -- hTarget是目标NPC。
GetCustomCastErrorTarget( hTarget) -- hTarget是目标NPC。

CastFilterResultLocation( vLocation ) -- vLocation是目标位置。
GetCustomCastErrorLocation( vLocation ) -- vLocation是目标位置。

CastFilterResult() -- 无目标技能
GetCustomCastError() -- 无目标技能

所有CastFilterResult函数必须返回一个UnitFilterResul枚举值。(如:UF_SUCCESS, UF_FAIL_CUSTOM)。返回UF_SUCCESS会引起技能传递过滤器,调用UF_FAIL_CUSTOM会引起合适的GetCustomCastError函数被调用。
所有GetCustomCastError函数必须返回一个字符串值(指向addon_english.txt文件中一个合适的入口点)。


这是一个复仇之魂移形换位的CastFilter的例子。移形换位的施法行为允许小兵,但施法者必须装备阿哈利姆神杖。移形换位也不能对自己使用。注意CastFilterResult和GetCustomCastError是共享函数,这意味着它们同时在服务器和客户端上运行。

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

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

属性

这里也有几个没有暴露在npc_abilities_custom.txt中的属性技能。通常来说,你只需要在你的技能需要不同于默认的特定行为时重写这些函数。举几个例子:

* IsStealable() -- 如果拉比克能偷取此技能则返回true。
* ProcsMagicStick() -- 如果敌方英雄能在此技能释放后为魔棒充能则返回true。
* IsRefreshable() -- 该技能如果能被刷新则返回true。
* GetPlaybackRateOverride() -- 返回需要被播放的施法动画的速率(浮点值)。


例子

这是lua版本的复仇之魂移形换位的完整脚本。

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修改器

修改器的工作方式现在与Lua技能更加相似,但设置却稍微不同。和Lua技能一样,先新建一个命名合适的.lua文件。这里有个斯温战吼的例子。在文件顶端,创建一个与文件名相同的类。这个例子中就是modifier_sven_warcry_lua

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


lua修改器有个独有的额外步骤。你必须在创建它们之前用引擎注册它们。一个干这事的好地方就是在相关技能文件中。通常修改器由技能创建,但也不是一定这样。如果时后者的情况,你可以用基础游戏模式脚本调用。唯一需求是必须在修改器任何的实例被创建之前被调用。因为modifier_sven_warcry_lua与战吼技能关联,它能在那被注册。注意这在不同于修改器被定义的"sven_warcry_lua.lua"文件中创立。

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

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


第一个参数是注册的修改器(也是脚本文件)的名字,第二个参数是LuaModifierType的枚举类型,用来确立(如果有的话)修改器对其父对象应用的动作控制器类型。以下是不同类型:

* LUA_MODIFIER_MOTION_NONE - 无动作控制器
* LUA_MODIFIER_MOTION_HORIZONTAL - 横向动作控制器
* LUA_MODIFIER_MOTION_VERTICAL - 垂直动作控制器
* LUA_MODIFIER_MOTION_BOTH - 同时拥有横向和垂直动作控制器


修改器现在能通过添加修改器的普通方法被添加。注意在新更新中,修改器(CDOTA_Buff)是一个Lua中的已知类型,因此你可以用它们创建本地变量并对它们调用函数(完整列表见script_help2),这对定义你自己的修改器很有用。类似技能,lua修改器是引擎调用的重写函数。许多修改器调用一个相似的,与它们的特定函数无关且对基础设置和对声明变量很有用的函数集。几个例子:

* OnCreated( kv ) -- 当修改器被创建时被调用,带着一个在"kv"中的值的表。客户端/服务器。无返回类型。
* OnRefresh( kv ) -- 当修改器被刷新时被调用(当已存在时被创建)。客户端/服务器。无返回类型。
* IsHidden() -- 若此修改器不应出现在buff栏则返回true。客户端/服务器。布尔返回类型。
* IsDebuff() -- 若此修改器应作为debuff出现在buff栏则返回true。客户端/服务器。布尔返回类型。
* IsPurgable() -- 若此修改器可被净化则返回true。客户端/服务器。布尔返回类型。
* GetEffectName() -- 返回若此buff有效时,作用于父对象的例子特效名。客户端/服务器。字符串返回类型。


注意这些函数会在客户端和服务器中被分别调用。一般来说,最好只在服务器中表现游戏逻辑。客户端的修改器功能往往只用作提示(以致额外事物能在HUD中准确显示)。如果你在游戏中创建修改器时得到Lua错误,但修改器仍然在游戏逻辑中正确表现,这往往是一个尝试在客户端实行游戏逻辑的信号。


修改器函数

DeclareFunctions()是一个许多lua修改器都想使用的函数。这个函数应该返回一个包含你的修改器想要影响的事件和属性的表。枚举与函数值的完整列表比较长,可以在游戏中输入script_help2查看。这是一个斯温战吼修改器的例子。这个修改器想要影响其父对象的护甲和移动速度,所以DeclareFunctions必须返回相关的枚举值。

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


影响以上属性的第二步是重写它们的关联函数。每个属性期望一个特定函数名。

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

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

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


params参数对所有属性和事件相关函数都是普通的。它是一个用事件发生时的特定内容载入的表。用一个循环和Msg()函数,你能打印表的内容。战吼的属性函数非常简单,所以这用斯温巨力挥舞的例子。注意属性函数对客户端和服务器都有效,所以游戏逻辑只在服务器表现。

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

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

某些修改器想要在某些间隔表现游戏逻辑。你可以对修改器调用StartIntervalThink()来完成。一旦间隔开始,引擎会寻找OnIntervalThink()函数,该函数会在每次计时间隔发生时被调用。以-1作为参数调用StartIntervalThink()函数会终止计时。莉娜的炽魂利用了这些函数,例子:

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

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

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


计时器

有时修改器想要围绕某地而不是NPC做一些特效。这种情况下你可以使用“计时器”,计时器修改器实际上是一个不可见、无敌、带着一个修改器的单位。它们的结构与修改器没有不同,当创建方式却稍微不同。莉娜的光击阵在一个区域创建了一个延时特效,因此修改器计时器在这种情况下被使用。这是如何创建的例子:

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

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

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

记得一件事,计时器失效必须移除马甲单位。UTIL_Remove( self:GetParent() )是一个好办法。这样会同时移除修改器。

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

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

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


修改器状态

不同于属性和事件,修改器可以应用"状态"。一些状态的例子包括眩晕、隐形、相位等等。完整列表请查看script_help2中的modifierstate枚举。状态通过在你的修改器中添加CheckState()来应用。常见情况是应用眩晕。注意语法稍不同于DeclareFunctions()。

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

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

	return state
end

这有个光击阵中应用眩晕修改器的例子。

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

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


修改器函数

--- Enum modifierfunction
MODIFIER_EVENT_ON_ABILITY_END_CHANNEL = 112 -- OnAbilityEndChannel
MODIFIER_EVENT_ON_ABILITY_EXECUTED = 109 -- OnAbilityExecuted
MODIFIER_EVENT_ON_ABILITY_FULLY_CAST = 110 -- OnAbilityFullyCast
MODIFIER_EVENT_ON_ABILITY_START = 108 -- OnAbilityStart
MODIFIER_EVENT_ON_ATTACK = 101 -- OnAttack
MODIFIER_EVENT_ON_ATTACKED = 118 -- OnAttacked
MODIFIER_EVENT_ON_ATTACK_ALLIED = 104 -- OnAttackAllied
MODIFIER_EVENT_ON_ATTACK_FAIL = 103 -- OnAttackFail
MODIFIER_EVENT_ON_ATTACK_LANDED = 102 -- OnAttackLanded
MODIFIER_EVENT_ON_ATTACK_RECORD = 99 -- OnAttackRecord
MODIFIER_EVENT_ON_ATTACK_START = 100 -- OnAttackStart
MODIFIER_EVENT_ON_BREAK_INVISIBILITY = 111 -- OnBreakInvisibility
MODIFIER_EVENT_ON_BUILDING_KILLED = 130 -- OnBuildingKilled
MODIFIER_EVENT_ON_DEATH = 119 -- OnDeath
MODIFIER_EVENT_ON_DOMINATED = 146 -- OnDominated
MODIFIER_EVENT_ON_HEALTH_GAINED = 125 -- OnHealthGained
MODIFIER_EVENT_ON_HEAL_RECEIVED = 129 -- OnHealReceived
MODIFIER_EVENT_ON_HERO_KILLED = 128 -- OnHeroKilled
MODIFIER_EVENT_ON_MANA_GAINED = 126 -- OnManaGained
MODIFIER_EVENT_ON_MODEL_CHANGED = 131 -- OnModelChanged
MODIFIER_EVENT_ON_ORB_EFFECT = 117
MODIFIER_EVENT_ON_ORDER = 106 -- OnOrder
MODIFIER_EVENT_ON_PROCESS_UPGRADE = 113
MODIFIER_EVENT_ON_PROJECTILE_DODGE = 105 -- OnProjectileDodge
MODIFIER_EVENT_ON_REFRESH = 114
MODIFIER_EVENT_ON_RESPAWN = 120 -- OnRespawn
MODIFIER_EVENT_ON_SET_LOCATION = 124 -- OnSetLocation
MODIFIER_EVENT_ON_SPENT_MANA = 121 -- OnSpentMana
MODIFIER_EVENT_ON_STATE_CHANGED = 116 -- OnStateChanged
MODIFIER_EVENT_ON_TAKEDAMAGE = 115 -- OnTakeDamage
MODIFIER_EVENT_ON_TAKEDAMAGE_KILLCREDIT = 127 -- OnTakeDamageKillCredit
MODIFIER_EVENT_ON_TELEPORTED = 123 -- OnTeleported
MODIFIER_EVENT_ON_TELEPORTING = 122 -- OnTeleporting
MODIFIER_EVENT_ON_UNIT_MOVED = 107 -- OnUnitMoved
MODIFIER_FUNCTION_INVALID = 255
MODIFIER_FUNCTION_LAST = 147
MODIFIER_PROPERTY_ABILITY_LAYOUT = 145 -- GetModifierAbilityLayout
MODIFIER_PROPERTY_ABSOLUTE_NO_DAMAGE_MAGICAL = 88 -- GetAbsoluteNoDamageMagical
MODIFIER_PROPERTY_ABSOLUTE_NO_DAMAGE_PHYSICAL = 87 -- GetAbsoluteNoDamagePhysical
MODIFIER_PROPERTY_ABSOLUTE_NO_DAMAGE_PURE = 89 -- GetAbsoluteNoDamagePure
MODIFIER_PROPERTY_ABSORB_SPELL = 77 -- 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 = 60 -- GetModifierAttackRangeBonus
MODIFIER_PROPERTY_AVOID_DAMAGE = 34 -- GetModifierAvoidDamage
MODIFIER_PROPERTY_AVOID_SPELL = 35 -- GetModifierAvoidSpell
MODIFIER_PROPERTY_BASEATTACK_BONUSDAMAGE = 2 -- GetModifierBaseAttack_BonusDamage
MODIFIER_PROPERTY_BASEDAMAGEOUTGOING_PERCENTAGE = 28 -- GetModifierBaseDamageOutgoing_Percentage
MODIFIER_PROPERTY_BASEDAMAGEOUTGOING_PERCENTAGE_UNIQUE = 29 -- GetModifierBaseDamageOutgoing_PercentageUnique
MODIFIER_PROPERTY_BASE_ATTACK_TIME_CONSTANT = 23 -- GetModifierBaseAttackTimeConstant
MODIFIER_PROPERTY_BASE_MANA_REGEN = 44 -- GetModifierBaseRegen
MODIFIER_PROPERTY_BONUS_DAY_VISION = 80 -- GetBonusDayVision
MODIFIER_PROPERTY_BONUS_NIGHT_VISION = 81 -- GetBonusNightVision
MODIFIER_PROPERTY_BONUS_NIGHT_VISION_UNIQUE = 82 -- GetBonusNightVisionUnique
MODIFIER_PROPERTY_BONUS_VISION_PERCENTAGE = 83 -- GetBonusVisionPercentage
MODIFIER_PROPERTY_BOUNTY_CREEP_MULTIPLIER = 97 -- GetModifierBountyCreepMultiplier
MODIFIER_PROPERTY_BOUNTY_OTHER_MULTIPLIER = 98 -- GetModifierBountyOtherMultiplier
MODIFIER_PROPERTY_CASTTIME_PERCENTAGE = 67 -- GetModifierPercentageCasttime
MODIFIER_PROPERTY_CHANGE_ABILITY_VALUE = 144 -- GetModifierChangeAbilityValue
MODIFIER_PROPERTY_COOLDOWN_PERCENTAGE = 66 -- GetModifierPercentageCooldown
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 = 69 -- GetModifierConstantDeathGoldCost
MODIFIER_PROPERTY_DISABLE_AUTOATTACK = 79 -- GetDisableAutoAttack
MODIFIER_PROPERTY_DISABLE_HEALING = 94 -- GetDisableHealing
MODIFIER_PROPERTY_DISABLE_TURNING = 142 -- GetModifierDisableTurning
MODIFIER_PROPERTY_EVASION_CONSTANT = 33 -- GetModifierEvasion_Constant
MODIFIER_PROPERTY_EXTRA_HEALTH_BONUS = 54 -- GetModifierExtraHealthBonus
MODIFIER_PROPERTY_EXTRA_HEALTH_PERCENTAGE = 56 -- GetModifierExtraHealthPercentage
MODIFIER_PROPERTY_EXTRA_MANA_BONUS = 55 -- GetModifierExtraManaBonus
MODIFIER_PROPERTY_EXTRA_STRENGTH_BONUS = 53 -- GetModifierExtraStrengthBonus
MODIFIER_PROPERTY_FIXED_DAY_VISION = 84 -- GetFixedDayVision
MODIFIER_PROPERTY_FIXED_NIGHT_VISION = 85 -- GetFixedNightVision
MODIFIER_PROPERTY_FORCE_DRAW_MINIMAP = 141 -- GetForceDrawOnMinimap
MODIFIER_PROPERTY_HEALTH_BONUS = 51 -- GetModifierHealthBonus
MODIFIER_PROPERTY_HEALTH_REGEN_CONSTANT = 49 -- GetModifierConstantHealthRegen
MODIFIER_PROPERTY_HEALTH_REGEN_PERCENTAGE = 50 -- GetModifierHealthRegenPercentage
MODIFIER_PROPERTY_IGNORE_CAST_ANGLE = 143 -- GetModifierIgnoreCastAngle
MODIFIER_PROPERTY_ILLUSION_LABEL = 91 -- GetModifierIllusionLabel
MODIFIER_PROPERTY_INCOMING_DAMAGE_PERCENTAGE = 30 -- GetModifierIncomingDamage_Percentage
MODIFIER_PROPERTY_INCOMING_PHYSICAL_DAMAGE_PERCENTAGE = 31 -- GetModifierIncomingPhysicalDamage_Percentage
MODIFIER_PROPERTY_INCOMING_SPELL_DAMAGE_CONSTANT = 32 -- GetModifierIncomingSpellDamageConstant
MODIFIER_PROPERTY_INVISIBILITY_LEVEL = 8 -- GetModifierInvisibilityLevel
MODIFIER_PROPERTY_IS_ILLUSION = 90 -- GetIsIllusion
MODIFIER_PROPERTY_IS_SCEPTER = 135 -- GetModifierScepter
MODIFIER_PROPERTY_LIFETIME_FRACTION = 138 -- GetUnitLifetimeFraction
MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS = 41 -- GetModifierMagicalResistanceBonus
MODIFIER_PROPERTY_MAGICAL_RESISTANCE_DECREPIFY_UNIQUE = 43 -- GetModifierMagicalResistanceDecrepifyUnique
MODIFIER_PROPERTY_MAGICAL_RESISTANCE_ITEM_UNIQUE = 42 -- GetModifierMagicalResistanceItemUnique
MODIFIER_PROPERTY_MANACOST_PERCENTAGE = 68 -- GetModifierPercentageManacost
MODIFIER_PROPERTY_MANA_BONUS = 52 -- GetModifierManaBonus
MODIFIER_PROPERTY_MANA_REGEN_CONSTANT = 45 -- GetModifierConstantManaRegen
MODIFIER_PROPERTY_MANA_REGEN_CONSTANT_UNIQUE = 46 -- GetModifierConstantManaRegenUnique
MODIFIER_PROPERTY_MANA_REGEN_PERCENTAGE = 47 -- GetModifierPercentageManaRegen
MODIFIER_PROPERTY_MANA_REGEN_TOTAL_PERCENTAGE = 48 -- GetModifierTotalPercentageManaRegen
MODIFIER_PROPERTY_MIN_HEALTH = 86 -- GetMinHealth
MODIFIER_PROPERTY_MISS_PERCENTAGE = 36 -- GetModifierMiss_Percentage
MODIFIER_PROPERTY_MODEL_CHANGE = 133 -- GetModifierModelChange
MODIFIER_PROPERTY_MODEL_SCALE = 134 -- 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_OVERRIDE_ANIMATION = 74 -- GetOverrideAnimation
MODIFIER_PROPERTY_OVERRIDE_ANIMATION_RATE = 76 -- GetOverrideAnimationRate
MODIFIER_PROPERTY_OVERRIDE_ANIMATION_WEIGHT = 75 -- GetOverrideAnimationWeight
MODIFIER_PROPERTY_OVERRIDE_ATTACK_MAGICAL = 95 -- GetOverrideAttackMagical
MODIFIER_PROPERTY_PERSISTENT_INVISIBILITY = 9 -- GetModifierPersistentInvisibility
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS = 37 -- GetModifierPhysicalArmorBonus
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS_ILLUSIONS = 38 -- GetModifierPhysicalArmorBonusIllusions
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS_UNIQUE = 39 -- GetModifierPhysicalArmorBonusUnique
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS_UNIQUE_ACTIVE = 40 -- GetModifierPhysicalArmorBonusUniqueActive
MODIFIER_PROPERTY_PHYSICAL_CONSTANT_BLOCK = 71 -- GetModifierPhysical_ConstantBlock
MODIFIER_PROPERTY_PREATTACK_BONUS_DAMAGE = 0 -- GetModifierPreAttack_BonusDamage
MODIFIER_PROPERTY_PREATTACK_BONUS_DAMAGE_POST_CRIT = 1 -- GetModifierPreAttack_BonusDamagePostCrit
MODIFIER_PROPERTY_PREATTACK_CRITICALSTRIKE = 70 -- GetModifierPreAttack_CriticalStrike
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 = 61 -- GetModifierProjectileSpeedBonus
MODIFIER_PROPERTY_PROVIDES_FOW_POSITION = 139 -- GetModifierProvidesFOWVision
MODIFIER_PROPERTY_REFLECT_SPELL = 78 -- GetReflectSpell
MODIFIER_PROPERTY_REINCARNATION = 62 -- ReincarnateTime
MODIFIER_PROPERTY_RESPAWNTIME = 63 -- GetModifierConstantRespawnTime
MODIFIER_PROPERTY_RESPAWNTIME_PERCENTAGE = 64 -- GetModifierPercentageRespawnTime
MODIFIER_PROPERTY_RESPAWNTIME_STACKING = 65 -- GetModifierStackingRespawnTime
MODIFIER_PROPERTY_SPELLS_REQUIRE_HP = 140 -- GetModifierSpellsRequireHP
MODIFIER_PROPERTY_STATS_AGILITY_BONUS = 58 -- GetModifierBonusStats_Agility
MODIFIER_PROPERTY_STATS_INTELLECT_BONUS = 59 -- GetModifierBonusStats_Intellect
MODIFIER_PROPERTY_STATS_STRENGTH_BONUS = 57 -- GetModifierBonusStats_Strength
MODIFIER_PROPERTY_SUPER_ILLUSION = 92 -- GetModifierSuperIllusion
MODIFIER_PROPERTY_TOOLTIP = 132 -- OnTooltip
MODIFIER_PROPERTY_TOTALDAMAGEOUTGOING_PERCENTAGE = 27 -- GetModifierTotalDamageOutgoing_Percentage
MODIFIER_PROPERTY_TOTAL_CONSTANT_BLOCK = 73 -- GetModifierTotal_ConstantBlock
MODIFIER_PROPERTY_TOTAL_CONSTANT_BLOCK_UNAVOIDABLE_PRE_ARMOR = 72 -- GetModifierPhysical_ConstantBlockUnavoidablePreArmor
MODIFIER_PROPERTY_TRANSLATE_ACTIVITY_MODIFIERS = 136 -- GetActivityTranslationModifiers
MODIFIER_PROPERTY_TRANSLATE_ATTACK_SOUND = 137 -- GetAttackSound
MODIFIER_PROPERTY_TURN_RATE_PERCENTAGE = 93 -- GetModifierTurnRate_Percentage
MODIFIER_PROPERTY_UNIT_STATS_NEEDS_REFRESH = 96 -- GetModifierUnitStatsNeedsRefresh