Отключить автоматическое пополнение зарядов предмета

  • Автор темы Автор темы Bacchus
  • Дата начала Дата начала

Bacchus

Пользователь
25 Ноя 2021
25
1
Проект
Gods&Avatars
Создал предмет с зарядами.
По какой-то причине заряды предмета увеличиваются со временем.
Значение зарядов доходит до 5 и увеличение зарядов прекращается.
При использовании предмета я задаю новое значение заряда и сразу отображается указанное значение, потом постепенно количество зарядов снова увеличивается.
Как отключить автоматическое увеличение зарядов?
PS эта фигня появилась после какого-то обновления доты. До этого все работало окей, код после этого не менял.

dota_error.jpg
 
Создал предмет с зарядами.
По какой-то причине заряды предмета увеличиваются со временем.
Значение зарядов доходит до 5 и увеличение зарядов прекращается.
При использовании предмета я задаю новое значение заряда и сразу отображается указанное значение, потом постепенно количество зарядов снова увеличивается.
Как отключить автоматическое увеличение зарядов?
PS эта фигня появилась после какого-то обновления доты. До этого все работало окей, код после этого не менял.

Посмотреть вложение 2211
Код скинь
 
Уровень заряда завязан на self.types.level
Я его меняю при использовании предмета - OnSpellStart
Еще в функции AddNewStat - но ее вызываю при определенном событии в UI
Еще функция SetCustomProperties - ее вызываю при копировании предмета (есть такая механика в игре).

Но ни одна из этих функций не имеет таймера.


Код:
    "item_base_custom"
    {
        // General
        //-------------------------------------------------------------------------------------------------------------
        "BaseClass"                        "item_lua"
        "ScriptFile"                    "lua_items/item_base_custom.lua"
        "AbilityTextureName"            "item_start"
        "AbilityBehavior"                "DOTA_ABILITY_BEHAVIOR_NO_TARGET"
        "Model"                            "models/props_gameplay/gem01.vmdl"

        "AbilityManaCost"                "0"
        "AbilityCooldown"                "0"
        "AbilityChannelTime"            "0"
        "ItemStockMax"                     "1"
        "ItemStockTime"                 "0"
        
        // Item Info
        //-------------------------------------------------------------------------------------------------------------
        "ItemCost"                        "0"
        "ItemShopTags"                    ""
        "ItemQuality"                    "component"
        "ItemAliases"                    ""
        "ItemPurchasable"                "0"
        "ItemSellable"                    "0"
        "ItemDroppable"                 "1"
        "ItemShareability"                "ITEM_FULLY_SHAREABLE"

        "ItemInitialCharges"            "1"
        "ItemDisplayCharges"            "0"
        "ItemPermanent"                 "0"
    }
Lua:
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
 
Уровень заряда завязан на self.types.level
Я его меняю при использовании предмета - OnSpellStart
Еще в функции AddNewStat - но ее вызываю при определенном событии в UI
Еще функция SetCustomProperties - ее вызываю при копировании предмета (есть такая механика в игре).

Но ни одна из этих функций не имеет таймера.


Код:
    "item_base_custom"
    {
        // General
        //-------------------------------------------------------------------------------------------------------------
        "BaseClass"                        "item_lua"
        "ScriptFile"                    "lua_items/item_base_custom.lua"
        "AbilityTextureName"            "item_start"
        "AbilityBehavior"                "DOTA_ABILITY_BEHAVIOR_NO_TARGET"
        "Model"                            "models/props_gameplay/gem01.vmdl"

        "AbilityManaCost"                "0"
        "AbilityCooldown"                "0"
        "AbilityChannelTime"            "0"
        "ItemStockMax"                     "1"
        "ItemStockTime"                 "0"
       
        // Item Info
        //-------------------------------------------------------------------------------------------------------------
        "ItemCost"                        "0"
        "ItemShopTags"                    ""
        "ItemQuality"                    "component"
        "ItemAliases"                    ""
        "ItemPurchasable"                "0"
        "ItemSellable"                    "0"
        "ItemDroppable"                 "1"
        "ItemShareability"                "ITEM_FULLY_SHAREABLE"

        "ItemInitialCharges"            "1"
        "ItemDisplayCharges"            "0"
        "ItemPermanent"                 "0"
    }
Lua:
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
Попробуй в KV добавить "AbilityChargeRestoreTime" "0" где-нибудь рядом с зарядами
 
И ещё объясни принцип работы способности, тогда можно будет ещё подумать почему
Это универсальный предмет.
За золото можно его улучшать.
При первом использовании и на каждом 5 уровне заряда игроку предлагается выбрать новый атрибут для предмета.
Пример атрибутов - увеличение силы, ловкости, регенерации хп или маны, броня и т.д.
Информацию о том, какие атрибуты были выбраны храниться в специfльной CustomNetTables таблице и дублируется в таблице self.types.
Заряд отображает сколько раз улучшался предмет после получения атрибута (может иметь значение от 1 до 5) и на уровень бонуса.
Использование предмета - бесплатно по мане, но требует золото. При улучшении увеличивается уровень предмета и его заряд.
Например, первым был выбран бонус силы. Игрок сразу получает 2 единицы силы. И за каждый заряд - еще 2 единицы.
Если предмет улучшался 5 раз, то на пятый раз снова появиться окно выбора атрибута и будет добавлен новый атрибут, например, броня.
Тогда предмет будет давать 2 (базовое улучшение) * 5 (кол-во зарядов) силы и 3 * 1 брони.
Следующее улучшение будет давать так же 10 силы, но уже 3 * 2 = 6 брони.
Для вычисления бонуса предмета используется специальный модификатор.

Lua:
require( 'items_const' )
require( 'global_const' )

modifier_special_value = modifier_special_value 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 {
            MODIFIER_PROPERTY_OVERRIDE_ABILITY_SPECIAL,
            MODIFIER_PROPERTY_OVERRIDE_ABILITY_SPECIAL_VALUE
        }
    end,
    GetAttributes           = function(self) return MODIFIER_ATTRIBUTE_MULTIPLE + MODIFIER_ATTRIBUTE_IGNORE_INVULNERABLE end,
})

function modifier_special_value:GetModifierOverrideAbilitySpecial( params )
      local ability = params.ability
    local specialname = params.ability_special_value
    local level = params.ability_special_level
    if specialname == 'price' or (ability:GetAbilityName() == 'item_base_custom' and  specialname:find("_f") == nil) then
        return 1
    end

    return 0
end

-- Переопределение значения свойства
function modifier_special_value:GetModifierOverrideAbilitySpecialValue(params)
    local ability = params.ability
    local specialname = params.ability_special_value
    local level = params.ability_special_level
    if ability ~= nil and specialname == 'price'and ability:GetAbilityName() ~= 'item_base_custom' then
        local base = params.ability:GetLevelSpecialValueNoOverride( specialname, level )
        local price  = math.floor( base * math.pow( 1.3, self:GetParent():GetLevel() - 1 ) + 0.5)
        print('GetModifierOverrideAbilitySpecialValue price'..price)
        return price
    end
    if ability ~= nil and ability:GetAbilityName() == 'item_base_custom' and VALUE_NAME[specialname] ~= nil then

        local charges = 0
        local base_value = ability:GetLevelSpecialValueNoOverride(specialname, level )
        local types = CustomNetTables:GetTableValue( "custom_item_state", string.format( "%d", ability:GetEntityIndex() ) )
        --print(ability:GetAbilityName()..'  '..string.format( "%d", ability:GetEntityIndex() ))
        --DeepPrint(types)
        local i = 1
        while i<#ORDINAL and types[ORDINAL[i+1]] ~= 0 do
            if types[ORDINAL[i]] == VALUE_NAME[specialname] then charges = charges + 5 end
            i = i + 1
        end
        if types[ORDINAL[i]] == VALUE_NAME[specialname] then
            charges = charges + ability:GetCurrentCharges()
        end
        local sfname = specialname..'_f'
        local fname = params.ability:GetLevelSpecialValueNoOverride( sfname, level )
        local func = FuncTable[fname]
        --print('GetModifierOverrideAbilitySpecialValue sfname: '..sfname..' fname: '..fname)
        return func(base_value, charges)
    end
    return 5 -- Вернуть 0, если свойство не требуется переопределять
end

function DeepPrint(t)
    for k, v in pairs(t) do
        print('DeepPrint key: '..k)
        if type( v ) == 'table' then
            --DeepPrint(v)
        else
            print('DeepPrint value: '..tostring(v))
        end
    end
end
 
Офигеть, теперь почему-то и стоимость маны стала 5.
 
Реклама: