require( 'items_const' )
require( 'global_const' )
LinkLuaModifier( "item_base_custom_modifier_stats", "lua_items/item_base_custom.lua", LUA_MODIFIER_MOTION_NONE )
item_base_custom = item_base_custom or class({})
function item_base_custom:GetIntrinsicModifierName()
return "item_base_custom_modifier_stats"
end
function item_base_custom:Spawn()
if IsServer() then
tmp = {}
for _, ord in pairs(ORDINAL) do
tmp[ord] = 0
end
tmp.level = 0
self.types = tmp
CustomNetTables:SetTableValue( "custom_item_state", string.format( "%d", self:GetEntityIndex() ), tmp )
else
local netTable = CustomNetTables:GetTableValue( "custom_item_state", string.format( "%d", self:GetEntityIndex() ) )
self.types = netTable
end
end
function item_base_custom:SetCustomProperties(prop)
local netTable = CustomNetTables:GetTableValue( "custom_item_state", string.format( "%d", self:GetEntityIndex() ) )
netTable.level = prop.level
for _, ord in pairs (ORDINAL) do
if prop[ord] > 0 then
netTable[ord] = prop[ord]
else
break
end
end
local ch = netTable.level % 5
self:SetCurrentCharges(ch == 0 and 5 or ch)
CustomNetTables:SetTableValue( "custom_item_state", string.format( "%d", self:GetEntityIndex() ), netTable )
end
function item_base_custom:GetAbilityTextureName()
local netTable = CustomNetTables:GetTableValue( "custom_item_state", string.format( "%d", self:GetEntityIndex() ) )
if netTable.level == 0 then
return "item_start"
else
return "item_gem"
end
end
function item_base_custom:GetGoldCost()
local netTable = CustomNetTables:GetTableValue( "custom_item_state", string.format( "%d", self:GetEntityIndex() ) )
return 50 * (math.pow(1.2, netTable.level))
end
function item_base_custom:GetCurrentCharges()
local ch = self.types.level % 5
return self.types.level == 0 and 0 or ch == 0 and 5 or ch
end
function item_base_custom:OnSpellStart()
if IsServer() then
self.types.level = self.types.level + 1
CustomNetTables:SetTableValue( "custom_item_state", string.format( "%d", self:GetEntityIndex() ), self.types )
else
local netTable = CustomNetTables:GetTableValue( "custom_item_state", string.format( "%d", self:GetEntityIndex() ) )
self.types = netTable.level
end
local ch = self.types.level % 5
local caster = self:GetCaster()
if ch == 1 then
local player = caster:GetPlayerOwner()
if player and not player:IsNull() then
CustomGameEventManager:Send_ServerToPlayer(player, "item_upgrade", self:GetStatsData(self:GetEntityIndex(), caster:GetEntityIndex()))
end
else
self:SetCurrentCharges(ch == 0 and 5 or ch)
end
HeroMechanic:UpdateUI(caster)
self:GetCaster():CalculateStatBonus(true)
end
function item_base_custom:GetStatsData(item_index, hero_index)
local stat1 = self:GetRandomStat()
local stat2 = self:GetRandomStat()
local stat3 = self:GetRandomStat()
while stat2 == stat1 do
stat2 = self:GetRandomStat()
end
while stat3 == stat1 or stat3 == stat2 do
stat3 = self:GetRandomStat()
end
local statsData = {
stats = {
{
item_index = item_index,
hero_index = hero_index,
statName = stat1,
statId = VALUE_NAME[stat1]
},
{
item_index = item_index,
hero_index = hero_index,
statName = stat2,
statId = VALUE_NAME[stat2]
},
{
item_index = item_index,
hero_index = hero_index,
statName = stat3,
statId = VALUE_NAME[stat3]
}
}
}
return statsData
end
function item_base_custom:GetRandomStat()
local class = self:GetRandomClass()
class = class == nil and 'c' or class
local stats_by_class = STAT_BY_CLASS[class]
return self:GetRandomValue(stats_by_class)
end
function item_base_custom:GetRandomValue(table)
local count = #table
local idx = RandomInt(1, count)
return table[idx]
end
function item_base_custom:AddNewStat(statId)
local last = self:GetLastStat()
self.types[last] = statId
self:SetCurrentCharges(1)
CustomNetTables:SetTableValue( "custom_item_state", string.format( "%d", self:GetEntityIndex() ), self.types )
self:GetCaster():CalculateStatBonus(true)
end
function item_base_custom:GetLastStat()
for _, ord in pairs(ORDINAL) do
if self.types[ord] == 0 then
return ord
end
end
end
function item_base_custom:GetRandomClass()
local caster = self:GetCaster()
self.level = caster:GetLevel()
local str = caster:GetBaseStrength()
local agi = caster:GetBaseAgility()
local int = caster:GetBaseIntellect()
cd = self:ClassDistribution(str, agi, int)
local r = RandomFloat(0, 1)
local tv = 0
for k,v in pairs(cd) do
tv = tv + v
if r < tv then
return k
end
end
end
function item_base_custom:ClassDistribution(s, a, i)
local g = 6 * s - a - i
g = g < 0 and 0 or g
local w = 8 * math.min(s,a)
local r = 6 * a - s - i
r = r < 0 and 0 or w
local m = 8 * math.min(a,i)
local z = 6 * i - s - a
z = z < 0 and 0 or z
local s = 8 * math.min(s,i)
local str = (g + w + s) / 3
local agi = (r + w + m) / 3
local int = (z + m + s) / 3
local t = g + w + r + m + z + s + str + agi + int
local c = math.floor(t / 9)
t = t + c
local class = {}
class.g, class.w, class.r, class.m, class.z, class.s, class.str, class.agi, class.int, class.c = g/t, w/t, r/t, m/t, z/t, s/t, str/t, agi/t, int/t, c/t
return class
end
mbc = mbc or class({})
modifier_base_custom = modifier_base_custom or class(mbc, nil, mbc)
function modifier_base_custom:AddType(type)
self.types = self.types or {}
self.types[type] = true
end
function modifier_base_custom:AddTypes(types)
self.types = self.types or {}
for _, t in pairs(types) do
self.types[t] = true
end
end
function modifier_base_custom:HasType(type)
if self.types[type] then
return true
end
return false
end
item_base_custom_modifier_stats = item_base_custom_modifier_stats or class({
IsHidden = function(self) return true end,
IsPurgable = function(self) return false end,
IsDebuff = function(self) return false end,
IsBuff = function(self) return false end,
RemoveOnDeath = function(self) return false end,
DeclareFunctions = function(self)
return {
--common
MODIFIER_PROPERTY_STATS_STRENGTH_BONUS,
MODIFIER_PROPERTY_STATS_AGILITY_BONUS,
MODIFIER_PROPERTY_STATS_INTELLECT_BONUS,
MODIFIER_PROPERTY_HEALTH_BONUS,
MODIFIER_PROPERTY_MANA_BONUS,
MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS,
MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS,
-- guard
MODIFIER_PROPERTY_PHYSICAL_CONSTANT_BLOCK,
MODIFIER_PROPERTY_MAGICAL_CONSTANT_BLOCK,
-- strength
MODIFIER_PROPERTY_HEAL_AMPLIFY_PERCENTAGE,
MODIFIER_PROPERTY_HEALTH_REGEN_CONSTANT,
-- warrior
MODIFIER_EVENT_ON_ATTACK,
MODIFIER_EVENT_ON_TAKEDAMAGE,
-- ranger
MODIFIER_PROPERTY_AVOID_DAMAGE,
MODIFIER_PROPERTY_PREATTACK_CRITICALSTRIKE,
--agility
MODIFIER_PROPERTY_PREATTACK_BONUS_DAMAGE,
MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT,
-- mage
MODIFIER_PROPERTY_AVOID_SPELL,
-- wizzard
MODIFIER_EVENT_ON_ABILITY_FULLY_CAST,
MODIFIER_PROPERTY_MANACOST_PERCENTAGE,
-- intellect
MODIFIER_PROPERTY_SPELL_AMPLIFY_PERCENTAGE,
MODIFIER_PROPERTY_MANA_REGEN_CONSTANT,
}
end,
GetAttributes = function(self) return MODIFIER_ATTRIBUTE_MULTIPLE + MODIFIER_ATTRIBUTE_IGNORE_INVULNERABLE end,
})
-- common
function item_base_custom_modifier_stats:GetModifierBonusStats_Strength()
return self:GetAbility():GetSpecialValueFor('str')
end
function item_base_custom_modifier_stats:GetModifierBonusStats_Agility()
return self:GetAbility():GetSpecialValueFor('agi')
end
function item_base_custom_modifier_stats:GetModifierBonusStats_Intellect()
return self:GetAbility():GetSpecialValueFor('int')
end
function item_base_custom_modifier_stats:GetModifierHealthBonus()
return self:GetAbility():GetSpecialValueFor('hpb')
end
function item_base_custom_modifier_stats:GetModifierManaBonus()
return self:GetAbility():GetSpecialValueFor('mpb')
end
function item_base_custom_modifier_stats:GetModifierMagicalResistanceBonus()
return self:GetAbility():GetSpecialValueFor('mrb')
end
function item_base_custom_modifier_stats:GetModifierPhysicalArmorBonus()
return self:GetAbility():GetSpecialValueFor('pab')
end
-- guard
function item_base_custom_modifier_stats:GetModifierMagical_ConstantBlock()
return self:GetAbility():GetSpecialValueFor('mcb')
end
function item_base_custom_modifier_stats:GetModifierPhysical_ConstantBlock()
return self:GetAbility():GetSpecialValueFor('pcb')
end
-- strength
function item_base_custom_modifier_stats:GetModifierHealAmplify_Percentage()
return self:GetAbility():GetSpecialValueFor('hap')
end
function item_base_custom_modifier_stats:GetModifierConstantHealthRegen()
return self:GetAbility():GetSpecialValueFor('hrc')
end
-- warrior
function item_base_custom_modifier_stats:OnAttack(keys)
if (not IsServer()) then
return
end
if keys.attacker ~= self:GetParent() then
return
end
if (keys.target:GetUnitName() == "npc_dota_observer_wards" or keys.target:GetUnitName() == "npc_dota_sentry_wards") then
return
end
if RandomFloat(0, 1) < self:GetAbility():GetSpecialValueFor('mst') then
local modifier = keys.target:AddNewModifier(
self:GetParent(),
self:GetAbility(),
"item_base_custom_modifier_attack_handler",
{}
)
modifier:SetStackCount(1)
end
end
function item_base_custom_modifier_stats:OnTakeDamage(keys)
if not IsServer() then
return
end
local attacker = keys.attacker
if attacker ~= self:GetParent() then
return
end
local lfs = self:GetAbility():GetSpecialValueFor('lfs')
if lfs > 0 then
local healAmount = lfs * keys.damage / 100
attacker:Heal(healAmount, self:GetAbility())
-- Создаем партиклы эффекта вокруг атакующего героя
local particle = ParticleManager:CreateParticle("particles/generic_gameplay/generic_lifesteal.vpcf", PATTACH_ABSORIGIN_FOLLOW, attacker)
ParticleManager:SetParticleControl(particle, 0, attacker:GetAbsOrigin())
ParticleManager:ReleaseParticleIndex(particle)
end
end
-- ranger
function item_base_custom_modifier_stats:GetModifierPreAttack_CriticalStrike(params)
if IsServer() then
if
RandomFloat( 0,1 ) < self:GetAbility():GetSpecialValueFor('cch') / 100 and params.target:GetTeamNumber() ~= self:GetParent():GetTeamNumber()
then
EmitSoundOn("Hero_SkeletonKing.CriticalStrike", params.target )
return self:GetAbility():GetSpecialValueFor('cpw')
end
end
return 0
end
function item_base_custom_modifier_stats:GetModifierAvoidDamage()
if IsClient() then return end
local adm = self:GetAbility():GetSpecialValueFor('adm')
if RandomFloat( 0,1 ) < adm / 100 then
if self:GetParent():IsHero() then
self:GetParent():EmitSound("dodge")
end
return 1
end
return 0
end
-- agility
function item_base_custom_modifier_stats:GetModifierPreAttack_BonusDamage()
return self:GetAbility():GetSpecialValueFor('pbd')
end
function item_base_custom_modifier_stats:GetModifierAttackSpeedBonus_Constant()
return self:GetAbility():GetSpecialValueFor('asb')
end
-- mage
function item_base_custom_modifier_stats:GetModifierAvoidSpell()
return self:GetAbility():GetSpecialValueFor('asp')
end
-- wizzard
function item_base_custom_modifier_stats:OnAbilityFullyCast(keys)
if (not IsServer()) then
return
end
if keys.attacker ~= self:GetParent() then
return
end
if RandomFloat(0, 1) < self:GetAbility():GetSpecialValueFor('msp') then
local modifier = keys.target:AddNewModifier(
self:GetParent(),
self:GetAbility(),
"item_base_custom_modifier_spell_handler",
{}
)
modifier:SetStackCount(1)
end
end
function item_base_custom_modifier_stats:GetModifierPercentageManacost()
return self:GetAbility():GetSpecialValueFor('mcp')
end
-- intellect
function item_base_custom_modifier_stats:GetModifierSpellAmplify_Percentage()
return self:GetAbility():GetSpecialValueFor('sap')
end
function item_base_custom_modifier_stats:GetModifierConstantManaRegen()
return self:GetAbility():GetSpecialValueFor('mrc')
end
item_base_custom_modifier_attack_handler = class({
IsHidden = function() return true end,
IsPurgable = function() return false end,
GetAttributes = function() return MODIFIER_ATTRIBUTE_MULTIPLE + MODIFIER_ATTRIBUTE_PERMANENT end,
})
function item_base_custom_modifier_attack_handler:OnCreated()
if not IsServer() then
return
end
self.caster = self.ability:GetCaster()
self.target = self:GetParent()
local stacks = 1
if kv.stackCount ~= nil then
stacks = kv.stackCount
end
self:SetStackCount(stacks)
self:StartIntervalThink(1)
end
function item_base_custom_modifier_attack_handler:OnIntervalThink()
if self.caster:IsAlive() then
self.caster:PerformAttack(self.target, true, true, true, false, true, false, false)
end
local stackCount = self:GetStackCount()
if stackCount == 1 then
self:StartIntervalThink( -1 )
self:Destroy()
else
stackCount = stackCount - 1
self:SetStackCount(stackCount)
end
end
item_base_custom_modifier_spell_handler = class({
IsHidden = function() return true end,
IsPurgable = function() return false end,
GetAttributes = function() return MODIFIER_ATTRIBUTE_MULTIPLE + MODIFIER_ATTRIBUTE_PERMANENT end,
})
function item_base_custom_modifier_spell_handler:OnCreated(kv)
if not IsServer() then
return
end
self.ability = self:GetAbility()
self.caster = self.ability:GetCaster()
self.target = self:GetParent()
local stacks = 1
if kv.stackCount ~= nil then
stacks = kv.stackCount
end
self:SetStackCount(stacks)
self:StartIntervalThink(1)
end
function item_base_custom_modifier_spell_handler:OnIntervalThink()
if self.caster:IsAlive() then
self.caster:SetCursorCastTarget( self.target )
self.ability:OnSpellStart()
end
local stackCount = self:GetStackCount()
if stackCount == 1 then
self:StartIntervalThink( -1 )
self:Destroy()
else
stackCount = stackCount - 1
self:SetStackCount(stackCount)
end
end