initial commit
This commit is contained in:
@@ -0,0 +1,520 @@
|
||||
local ____lualib = require("lualib_bundle")
|
||||
local __TS__Class = ____lualib.__TS__Class
|
||||
local __TS__ClassExtends = ____lualib.__TS__ClassExtends
|
||||
local __TS__Decorate = ____lualib.__TS__Decorate
|
||||
local ____exports = {}
|
||||
local ____dota_ts_adapter = require("lib.dota_ts_adapter")
|
||||
local BaseAbility = ____dota_ts_adapter.BaseAbility
|
||||
local BaseModifier = ____dota_ts_adapter.BaseModifier
|
||||
local registerAbility = ____dota_ts_adapter.registerAbility
|
||||
local registerModifier = ____dota_ts_adapter.registerModifier
|
||||
local ____hero_rage_config = require("abilities.system.hero_rage_config")
|
||||
local shouldHeroUseRageResource = ____hero_rage_config.shouldHeroUseRageResource
|
||||
function ____exports.heroRageGetModifier(self, hero)
|
||||
return hero:FindModifierByName(____exports.modifier_hero_rage.name)
|
||||
end
|
||||
function ____exports.heroRageSet(self, hero, value)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
local m = ____exports.heroRageGetModifier(nil, hero)
|
||||
if not m then
|
||||
return
|
||||
end
|
||||
m:SetStackCount(math.max(
|
||||
0,
|
||||
math.min(
|
||||
math.floor(value),
|
||||
m.maxRage
|
||||
)
|
||||
))
|
||||
m:pushRageNetClient()
|
||||
end
|
||||
--- Списание ярости после успешного каста (стоимость из `rage_cost` в KV или своё число).
|
||||
function ____exports.heroRageTrySpend(self, hero, cost)
|
||||
if not IsServer() then
|
||||
return false
|
||||
end
|
||||
if cost <= 0 then
|
||||
return true
|
||||
end
|
||||
local m = ____exports.heroRageGetModifier(nil, hero)
|
||||
if not m then
|
||||
return false
|
||||
end
|
||||
if m:GetStackCount() < cost then
|
||||
return false
|
||||
end
|
||||
m:addRageInternal(-cost)
|
||||
return true
|
||||
end
|
||||
local function defaultSpawnParams()
|
||||
return {
|
||||
max_rage = 100,
|
||||
rage_per_attack = 6,
|
||||
rage_per_damage = 1,
|
||||
attack_speed_per_stack = 0,
|
||||
time_out_of_combat = 4,
|
||||
tick = 0.01
|
||||
}
|
||||
end
|
||||
____exports.ability_hero_rage = __TS__Class()
|
||||
local ability_hero_rage = ____exports.ability_hero_rage
|
||||
ability_hero_rage.name = "ability_hero_rage"
|
||||
ability_hero_rage.____file_path = "scripts/vscripts/abilities/system/hero_rage.lua"
|
||||
__TS__ClassExtends(ability_hero_rage, BaseAbility)
|
||||
function ability_hero_rage.prototype.GetIntrinsicModifierName(self)
|
||||
return ____exports.modifier_hero_rage.name
|
||||
end
|
||||
function ability_hero_rage.prototype.OnOwnerDied(self)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
local c = self:GetCaster()
|
||||
____exports.heroRageSet(nil, c, 0)
|
||||
end
|
||||
ability_hero_rage = __TS__Decorate(
|
||||
ability_hero_rage,
|
||||
ability_hero_rage,
|
||||
{registerAbility(nil)},
|
||||
{kind = "class", name = "ability_hero_rage"}
|
||||
)
|
||||
____exports.ability_hero_rage = ability_hero_rage
|
||||
____exports.modifier_hero_rage = __TS__Class()
|
||||
local modifier_hero_rage = ____exports.modifier_hero_rage
|
||||
modifier_hero_rage.name = "modifier_hero_rage"
|
||||
modifier_hero_rage.____file_path = "scripts/vscripts/abilities/system/hero_rage.lua"
|
||||
__TS__ClassExtends(modifier_hero_rage, BaseModifier)
|
||||
function modifier_hero_rage.prototype.____constructor(self, ...)
|
||||
BaseModifier.prototype.____constructor(self, ...)
|
||||
self.maxRage = 100
|
||||
self.ragePerAttack = 0
|
||||
self.ragePerDamage = 0
|
||||
self.attackSpeedPerStack = 0
|
||||
self.timeOutOfCombatThreshold = 4
|
||||
self.tick = 0.01
|
||||
self.outOfCombatTime = 0
|
||||
end
|
||||
function modifier_hero_rage.prototype.pushRageNetClient(self)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
CustomNetTables:SetTableValue(
|
||||
"custom_stats",
|
||||
"rage_ent_" .. tostring(self.parentHero:entindex()),
|
||||
{
|
||||
cur = self:GetStackCount(),
|
||||
max = self.maxRage
|
||||
}
|
||||
)
|
||||
end
|
||||
function modifier_hero_rage.prototype.clearRageNetClient(self)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
CustomNetTables:SetTableValue(
|
||||
"custom_stats",
|
||||
"rage_ent_" .. tostring(self.parentHero:entindex()),
|
||||
{off = 1}
|
||||
)
|
||||
end
|
||||
function modifier_hero_rage.prototype.IsHidden(self)
|
||||
return true
|
||||
end
|
||||
function modifier_hero_rage.prototype.IsPurgable(self)
|
||||
return false
|
||||
end
|
||||
function modifier_hero_rage.prototype.RemoveOnDeath(self)
|
||||
return false
|
||||
end
|
||||
function modifier_hero_rage.prototype.DeclareFunctions(self)
|
||||
return {
|
||||
MODIFIER_EVENT_ON_ATTACK_LANDED,
|
||||
MODIFIER_EVENT_ON_TAKEDAMAGE,
|
||||
MODIFIER_EVENT_ON_ABILITY_EXECUTED,
|
||||
MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT,
|
||||
MODIFIER_PROPERTY_MANA_REGEN_TOTAL_PERCENTAGE,
|
||||
MODIFIER_PROPERTY_FIXED_MANA_REGEN,
|
||||
MODIFIER_PROPERTY_FORCE_MAX_MANA,
|
||||
MODIFIER_PROPERTY_DAMAGEOUTGOING_PERCENTAGE,
|
||||
MODIFIER_PROPERTY_MANACOST_PERCENTAGE_STACKING
|
||||
}
|
||||
end
|
||||
function modifier_hero_rage.prototype.GetModifierPercentageManacostStacking(self, ...)
|
||||
local args = {...}
|
||||
local event = args[1]
|
||||
if event and event.ability and not event.ability:IsNull() and event.ability:IsItem() then
|
||||
return 100
|
||||
end
|
||||
return 0
|
||||
end
|
||||
function modifier_hero_rage.prototype.GetModifierDamageOutgoing_Percentage(self, event)
|
||||
return self:GetStackCount() * 0.25
|
||||
end
|
||||
function modifier_hero_rage.prototype.GetModifierTotalPercentageManaRegen(self)
|
||||
return 0
|
||||
end
|
||||
function modifier_hero_rage.prototype.GetModifierFixedManaRegen(self)
|
||||
return 0
|
||||
end
|
||||
function modifier_hero_rage.prototype.GetModifierForceMaxMana(self)
|
||||
return self.maxRage
|
||||
end
|
||||
function modifier_hero_rage.prototype.syncManaToRage(self)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
local hero = self.parentHero
|
||||
local rage = self:GetStackCount()
|
||||
local maxM = hero:GetMaxMana()
|
||||
hero:SetMaxMana(100)
|
||||
hero:SetMana(math.min(rage, maxM))
|
||||
end
|
||||
function modifier_hero_rage.prototype.reapplyManaPoolAfterStatBump(self)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
local hero = self.parentHero
|
||||
local rage = self:GetStackCount()
|
||||
hero:SetMaxMana(self.maxRage)
|
||||
hero:SetMana(math.min(
|
||||
rage,
|
||||
hero:GetMaxMana()
|
||||
))
|
||||
end
|
||||
function modifier_hero_rage.prototype.OnTakeDamage(self, event)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
if event.damage <= 0 then
|
||||
return
|
||||
end
|
||||
local victim = event.unit
|
||||
local attacker = event.attacker
|
||||
if attacker == self.parentHero and victim and victim:GetTeamNumber() ~= self.parentHero:GetTeamNumber() then
|
||||
if self.ragePerAttack ~= 0 then
|
||||
self:addRageInternal(self.ragePerAttack)
|
||||
end
|
||||
self:reapplyManaPoolAfterStatBump()
|
||||
return
|
||||
end
|
||||
if victim == self.parentHero then
|
||||
if self.ragePerDamage ~= 0 then
|
||||
self:addRageInternal(self.ragePerDamage)
|
||||
end
|
||||
self:reapplyManaPoolAfterStatBump()
|
||||
end
|
||||
end
|
||||
function modifier_hero_rage.prototype.getAbilityRageSpendCost(self, ability)
|
||||
local customRageCost = math.max(
|
||||
0,
|
||||
math.floor(ability:GetSpecialValueFor("rage_cost"))
|
||||
)
|
||||
if customRageCost > 0 then
|
||||
return customRageCost
|
||||
end
|
||||
return math.max(
|
||||
0,
|
||||
math.floor(ability:GetManaCost(ability:GetLevel()))
|
||||
)
|
||||
end
|
||||
function modifier_hero_rage.prototype.OnAbilityExecuted(self, event)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
if event.unit ~= self.parentHero then
|
||||
return
|
||||
end
|
||||
local ability = event.ability
|
||||
if not ability or ability:IsNull() then
|
||||
return
|
||||
end
|
||||
if ability:IsItem() then
|
||||
return
|
||||
end
|
||||
if ability == self:GetAbility() then
|
||||
return
|
||||
end
|
||||
local cost = self:getAbilityRageSpendCost(ability)
|
||||
if cost <= 0 then
|
||||
return
|
||||
end
|
||||
____exports.heroRageTrySpend(nil, self.parentHero, cost)
|
||||
end
|
||||
function modifier_hero_rage.prototype.OnCreated(self, params)
|
||||
local parent = self:GetParent()
|
||||
self.parentHero = parent
|
||||
local rawAbility = self:GetAbility()
|
||||
local ability = rawAbility and rawAbility:GetAbilityName() == "ability_hero_rage" and rawAbility or nil
|
||||
local def = defaultSpawnParams(nil)
|
||||
if ability then
|
||||
self.maxRage = math.max(
|
||||
1,
|
||||
math.floor(ability:GetSpecialValueFor("max_rage"))
|
||||
)
|
||||
self.ragePerAttack = ability:GetSpecialValueFor("rage_per_attack")
|
||||
self.ragePerDamage = ability:GetSpecialValueFor("rage_per_damage")
|
||||
self.attackSpeedPerStack = ability:GetSpecialValueFor("attack_speed_per_stack")
|
||||
self.timeOutOfCombatThreshold = math.max(
|
||||
0.1,
|
||||
ability:GetSpecialValueFor("time_out_of_combat")
|
||||
)
|
||||
self.tick = math.max(
|
||||
0.03,
|
||||
ability:GetSpecialValueFor("tick")
|
||||
)
|
||||
else
|
||||
self.maxRage = math.max(
|
||||
1,
|
||||
math.floor(params.max_rage or def.max_rage)
|
||||
)
|
||||
self.ragePerAttack = params.rage_per_attack or def.rage_per_attack
|
||||
self.ragePerDamage = params.rage_per_damage or def.rage_per_damage
|
||||
self.attackSpeedPerStack = params.attack_speed_per_stack or def.attack_speed_per_stack
|
||||
self.timeOutOfCombatThreshold = math.max(0.1, params.time_out_of_combat or def.time_out_of_combat)
|
||||
self.tick = math.max(0.03, params.tick or def.tick)
|
||||
end
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
parent.__zHeroRage = self
|
||||
self:SetStackCount(0)
|
||||
self.outOfCombatTime = 0
|
||||
parent:AddNewModifier(
|
||||
parent,
|
||||
self:GetAbility() or nil,
|
||||
____exports.modifier_hero_rage_max.name,
|
||||
{}
|
||||
)
|
||||
self:StartIntervalThink(self.tick)
|
||||
self:pushRageNetClient()
|
||||
self:syncManaToRage()
|
||||
self.levelUpListener = ListenToGameEvent(
|
||||
"dota_player_gained_level",
|
||||
function(event)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
if not IsValidEntity(self.parentHero) then
|
||||
return
|
||||
end
|
||||
if not self.parentHero:IsRealHero() or self.parentHero:IsIllusion() then
|
||||
return
|
||||
end
|
||||
local pid = self.parentHero:GetPlayerOwnerID()
|
||||
if event.player ~= pid then
|
||||
return
|
||||
end
|
||||
self:reapplyManaPoolAfterStatBump()
|
||||
end,
|
||||
nil
|
||||
)
|
||||
end
|
||||
function modifier_hero_rage.prototype.OnDestroy(self)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
if self.levelUpListener ~= nil then
|
||||
StopListeningToGameEvent(self.levelUpListener)
|
||||
self.levelUpListener = nil
|
||||
end
|
||||
self:clearRageNetClient()
|
||||
local p = self:GetParent()
|
||||
if p.__zHeroRage == self then
|
||||
p.__zHeroRage = nil
|
||||
end
|
||||
p:RemoveModifierByName(____exports.modifier_hero_rage_max.name)
|
||||
end
|
||||
function modifier_hero_rage.prototype.OnRefresh(self)
|
||||
local rawAbility = self:GetAbility()
|
||||
local ability = rawAbility and rawAbility:GetAbilityName() == "ability_hero_rage" and rawAbility or nil
|
||||
if ability then
|
||||
self.maxRage = math.max(
|
||||
1,
|
||||
math.floor(ability:GetSpecialValueFor("max_rage"))
|
||||
)
|
||||
self.ragePerAttack = ability:GetSpecialValueFor("rage_per_attack")
|
||||
self.ragePerDamage = ability:GetSpecialValueFor("rage_per_damage")
|
||||
self.attackSpeedPerStack = ability:GetSpecialValueFor("attack_speed_per_stack")
|
||||
self.timeOutOfCombatThreshold = math.max(
|
||||
0.1,
|
||||
ability:GetSpecialValueFor("time_out_of_combat")
|
||||
)
|
||||
self.tick = math.max(
|
||||
0.03,
|
||||
ability:GetSpecialValueFor("tick")
|
||||
)
|
||||
end
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
self:clampRageStack()
|
||||
local maxMod = self.parentHero:FindModifierByName(____exports.modifier_hero_rage_max.name)
|
||||
if maxMod then
|
||||
maxMod:SetStackCount(self.maxRage)
|
||||
end
|
||||
self:pushRageNetClient()
|
||||
self:syncManaToRage()
|
||||
end
|
||||
function modifier_hero_rage.prototype.OnStackCountChanged(self, _stack)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
self:clampRageStack()
|
||||
self:pushRageNetClient()
|
||||
self:syncManaToRage()
|
||||
end
|
||||
function modifier_hero_rage.prototype.OnIntervalThink(self)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
self:syncManaToRage()
|
||||
self.outOfCombatTime = self.outOfCombatTime + self.tick
|
||||
if self.outOfCombatTime >= self.timeOutOfCombatThreshold then
|
||||
self:addRageInternal(-1)
|
||||
end
|
||||
end
|
||||
function modifier_hero_rage.prototype.OnAttackLanded(self, event)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
end
|
||||
function modifier_hero_rage.prototype.GetModifierAttackSpeedBonus_Constant(self)
|
||||
return self.attackSpeedPerStack * self:GetStackCount()
|
||||
end
|
||||
function modifier_hero_rage.prototype.resetOutOfCombatTimer(self)
|
||||
self.outOfCombatTime = 0
|
||||
end
|
||||
function modifier_hero_rage.prototype.addRageInternal(self, delta)
|
||||
self:resetOutOfCombatTimer()
|
||||
local next = self:GetStackCount() + delta
|
||||
if next > self.maxRage then
|
||||
next = self.maxRage
|
||||
end
|
||||
if next < 0 then
|
||||
next = 0
|
||||
end
|
||||
self:SetStackCount(next)
|
||||
end
|
||||
function modifier_hero_rage.prototype.clampRageStack(self)
|
||||
local v = self:GetStackCount()
|
||||
if v < 0 then
|
||||
v = 0
|
||||
end
|
||||
if v > self.maxRage then
|
||||
v = self.maxRage
|
||||
end
|
||||
if v ~= self:GetStackCount() then
|
||||
self:SetStackCount(v)
|
||||
end
|
||||
end
|
||||
modifier_hero_rage = __TS__Decorate(
|
||||
modifier_hero_rage,
|
||||
modifier_hero_rage,
|
||||
{registerModifier(nil)},
|
||||
{kind = "class", name = "modifier_hero_rage"}
|
||||
)
|
||||
____exports.modifier_hero_rage = modifier_hero_rage
|
||||
____exports.modifier_hero_rage_max = __TS__Class()
|
||||
local modifier_hero_rage_max = ____exports.modifier_hero_rage_max
|
||||
modifier_hero_rage_max.name = "modifier_hero_rage_max"
|
||||
modifier_hero_rage_max.____file_path = "scripts/vscripts/abilities/system/hero_rage.lua"
|
||||
__TS__ClassExtends(modifier_hero_rage_max, BaseModifier)
|
||||
function modifier_hero_rage_max.prototype.____constructor(self, ...)
|
||||
BaseModifier.prototype.____constructor(self, ...)
|
||||
self.manaBonusLock = false
|
||||
end
|
||||
function modifier_hero_rage_max.prototype.IsHidden(self)
|
||||
return true
|
||||
end
|
||||
function modifier_hero_rage_max.prototype.IsPurgable(self)
|
||||
return false
|
||||
end
|
||||
function modifier_hero_rage_max.prototype.RemoveOnDeath(self)
|
||||
return false
|
||||
end
|
||||
function modifier_hero_rage_max.prototype.DeclareFunctions(self)
|
||||
return {MODIFIER_PROPERTY_MANA_BONUS}
|
||||
end
|
||||
function modifier_hero_rage_max.prototype.GetModifierManaBonus(self)
|
||||
if self.manaBonusLock then
|
||||
return 0
|
||||
end
|
||||
self.manaBonusLock = true
|
||||
local maxWithoutThis = self:GetParent():GetMaxMana()
|
||||
self.manaBonusLock = false
|
||||
local targetMax = self:GetStackCount()
|
||||
return targetMax - maxWithoutThis
|
||||
end
|
||||
function modifier_hero_rage_max.prototype.OnCreated(self)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
local parent = self:GetParent()
|
||||
local rage = parent:FindModifierByName(____exports.modifier_hero_rage.name)
|
||||
self:SetStackCount(rage and rage.maxRage or 0)
|
||||
end
|
||||
modifier_hero_rage_max = __TS__Decorate(
|
||||
modifier_hero_rage_max,
|
||||
modifier_hero_rage_max,
|
||||
{registerModifier(nil)},
|
||||
{kind = "class", name = "modifier_hero_rage_max"}
|
||||
)
|
||||
____exports.modifier_hero_rage_max = modifier_hero_rage_max
|
||||
function ____exports.heroRageGetCurrent(self, hero)
|
||||
local m = ____exports.heroRageGetModifier(nil, hero)
|
||||
return m and m:GetStackCount() or 0
|
||||
end
|
||||
function ____exports.heroRageGetMax(self, hero)
|
||||
local m = ____exports.heroRageGetModifier(nil, hero)
|
||||
return m and m.maxRage or 0
|
||||
end
|
||||
function ____exports.heroRageIncrease(self, hero, amount)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
local m = ____exports.heroRageGetModifier(nil, hero)
|
||||
if not m then
|
||||
return
|
||||
end
|
||||
m:addRageInternal(amount)
|
||||
end
|
||||
function ____exports.heroRageDecrement(self, hero, amount)
|
||||
____exports.heroRageIncrease(
|
||||
nil,
|
||||
hero,
|
||||
-math.abs(amount)
|
||||
)
|
||||
end
|
||||
--- Вешает систему ярости на героя из конфига `HERO_RAGE_UNIT_NAMES`.
|
||||
-- Если в `game/` уже есть `ability_hero_rage` в KV — берётся она, иначе — модификатор с дефолтами.
|
||||
function ____exports.attachHeroRageSystemForConfiguredHero(self, hero)
|
||||
if not IsServer() then
|
||||
return
|
||||
end
|
||||
if not hero:IsRealHero() or hero:IsIllusion() then
|
||||
return
|
||||
end
|
||||
if not shouldHeroUseRageResource(
|
||||
nil,
|
||||
hero:GetUnitName()
|
||||
) then
|
||||
return
|
||||
end
|
||||
if hero:FindModifierByName(____exports.modifier_hero_rage.name) then
|
||||
return
|
||||
end
|
||||
hero:AddAbility("ability_hero_rage")
|
||||
local rageAb = hero:FindAbilityByName("ability_hero_rage")
|
||||
if rageAb ~= nil then
|
||||
rageAb:SetLevel(1)
|
||||
return
|
||||
end
|
||||
hero:AddNewModifier(
|
||||
hero,
|
||||
getModifierSourceAbility(nil, hero),
|
||||
____exports.modifier_hero_rage.name,
|
||||
defaultSpawnParams(nil)
|
||||
)
|
||||
end
|
||||
return ____exports
|
||||
Reference in New Issue
Block a user