Мультикаст для любых спобоностей

avtakhov

Пользователь
28 Июн 2023
25
7
Привет всем! Я наткнулся на форуме на реализацию мультикаста Огра, но она показалась мне громоздкой и перегруженной. Поэтому я решил написать свой алгоритм, который кажется мне более простым и понятным.

Lua:
LinkLuaModifier("modifier_multicast", "additional_abilities/multicast", LUA_MODIFIER_MOTION_NONE)

multicast = multicast or {}

function multicast:GetIntrinsicModifierName()
    return "modifier_multicast"
end

function multicast:OnCreated()
end

modifier_multicast = modifier_multicast or {}

function modifier_multicast:IsHidden()
    return true
end

function modifier_multicast:IsDebuff()
    return false
end

function modifier_multicast:IsPurgable()
    return false
end

function modifier_multicast:DeclareFunctions()
    return { MODIFIER_EVENT_ON_ABILITY_FULLY_CAST }
end

function modifier_multicast:OnAbilityFullyCast(parameters)
    if parameters.unit ~= self:GetCaster() or parameters.ability == self:GetAbility()
            or self:GetCaster():PassivesDisabled() or parameters.ability:IsItem() or parameters.ability:IsHidden() then
        return
    end

    local multicast_4_times = self:GetAbility():GetSpecialValueFor("multicast_4_times")
    local multicast_3_times = self:GetAbility():GetSpecialValueFor("multicast_3_times")
    local multicast_2_times = self:GetAbility():GetSpecialValueFor("multicast_2_times")

    local behavior = parameters.ability:GetBehavior()
    local forbidden = DOTA_ABILITY_BEHAVIOR_CHANNELLED + DOTA_ABILITY_BEHAVIOR_TOGGLE + DOTA_ABILITY_BEHAVIOR_VECTOR_TARGETING
    if bit.band(behavior, forbidden) ~= 0 then
        return
    end

    local random = RandomFloat(0, 100)
    local multicast_n_times
    if random < multicast_4_times then
        multicast_n_times = 4
    elseif random < multicast_3_times then
        multicast_n_times = 3
    elseif random < multicast_2_times then
        multicast_n_times = 2
    else
        return
    end

    Thinker:New(
            parameters.unit,
            parameters.ability,
            parameters.ability:GetCursorPosition(),
            parameters.target,
            multicast_n_times,
            self:GetAbility():GetSpecialValueFor("delay")
    )
end

Thinker = Thinker or {}

function Thinker:New(caster, ability, position, target, multicast_n_times, delay)
    local instance = {
        caster = caster,
        ability = ability,
        position = position,
        target = target,
        multicast_n_times = multicast_n_times,
        used_times = 1,
        delay = delay
    }

    GameRules:GetGameModeEntity():SetThink(
            function()
                return instance:OnThink()
            end,
            nil,
            caster:entindex() .. "$" .. ability:GetAbilityName(), -- interrupt current multicast of the same ability from the same hero
            delay
    )

    return setmetatable(instance, { __index = self })
end

function Thinker:OnThink()
    self.caster:SetCursorPosition(self.position)
    self.caster:SetCursorCastTarget(self.target)
    self.ability:OnSpellStart()

    self.used_times = self.used_times + 1
    local pfx = ParticleManager:CreateParticle(
            "particles/units/heroes/hero_ogre_magi/ogre_magi_multicast.vpcf",
            PATTACH_OVERHEAD_FOLLOW,
            self.caster
    )
    ParticleManager:SetParticleControl(pfx, 1, Vector(self.used_times, 1, 0))

    if self.used_times < self.multicast_n_times then
        return self.delay
    else
        return nil
    end
end
Lua:
    "multicast"
    {
        "BaseClass"                        "ability_lua"
        "ScriptFile"                    "additional_abilities/multicast"
        "AbilityTextureName"            "additional/multicast"
        "AbilityType"                    "DOTA_ABILITY_TYPE_ULTIMATE"
        "FightRecapLevel"                "2"
        "AbilityBehavior"                "DOTA_ABILITY_BEHAVIOR_PASSIVE"
        "AbilityCastAnimation"            "ACT_INVALID"
        "MaxLevel"                      "3"

        "AbilitySpecial"
        {
            "01"
            {
                "var_type"                "FIELD_FLOAT"
                "multicast_2_times"        "75 75 75"
            }

            "02"
            {
                "var_type"                "FIELD_FLOAT"
                "multicast_3_times"        "0 30 30"
            }
            "03"
            {
                "var_type"                "FIELD_FLOAT"
                "multicast_4_times"        "0 0 15"
            }
            "04"
            {
                "var_type"              "FIELD_FLOAT"
                "delay"                 "0.7"
            }
        }
    }

Допущения, которые упростили реализацию:
  • Не работает с предметами
  • Для скилов с обездвиживающим модификатором на время каста, обороты мультикаста могут крутиться вхолостую (прыжок мираны, прыжок течса)
  • Не все переключаемые способности имеют соответствующий флаг [valve moment], поэтому некоторые неочевидные переключаемые способности могут мультикаститься (например, d у феникса)
  • Отключен для прерываемых способностей (upheavel, death ward итд)
  • Тестировал на ограниченном пуле героев из Dota1x2
Дайте знать, что вы думаете!
 
Привет всем! Я наткнулся на форуме на реализацию мультикаста Огра, но она показалась мне громоздкой и перегруженной. Поэтому я решил написать свой алгоритм, который кажется мне более простым и понятным.

Lua:
LinkLuaModifier("modifier_multicast", "additional_abilities/multicast", LUA_MODIFIER_MOTION_NONE)

multicast = multicast or {}

function multicast:GetIntrinsicModifierName()
    return "modifier_multicast"
end

function multicast:OnCreated()
end

modifier_multicast = modifier_multicast or {}

function modifier_multicast:IsHidden()
    return true
end

function modifier_multicast:IsDebuff()
    return false
end

function modifier_multicast:IsPurgable()
    return false
end

function modifier_multicast:DeclareFunctions()
    return { MODIFIER_EVENT_ON_ABILITY_FULLY_CAST }
end

function modifier_multicast:OnAbilityFullyCast(parameters)
    if parameters.unit ~= self:GetCaster() or parameters.ability == self:GetAbility()
            or self:GetCaster():PassivesDisabled() or parameters.ability:IsItem() or parameters.ability:IsHidden() then
        return
    end

    local multicast_4_times = self:GetAbility():GetSpecialValueFor("multicast_4_times")
    local multicast_3_times = self:GetAbility():GetSpecialValueFor("multicast_3_times")
    local multicast_2_times = self:GetAbility():GetSpecialValueFor("multicast_2_times")

    local behavior = parameters.ability:GetBehavior()
    local forbidden = DOTA_ABILITY_BEHAVIOR_CHANNELLED + DOTA_ABILITY_BEHAVIOR_TOGGLE + DOTA_ABILITY_BEHAVIOR_VECTOR_TARGETING
    if bit.band(behavior, forbidden) ~= 0 then
        return
    end

    local random = RandomFloat(0, 100)
    local multicast_n_times
    if random < multicast_4_times then
        multicast_n_times = 4
    elseif random < multicast_3_times then
        multicast_n_times = 3
    elseif random < multicast_2_times then
        multicast_n_times = 2
    else
        return
    end

    Thinker:New(
            parameters.unit,
            parameters.ability,
            parameters.ability:GetCursorPosition(),
            parameters.target,
            multicast_n_times,
            self:GetAbility():GetSpecialValueFor("delay")
    )
end

Thinker = Thinker or {}

function Thinker:New(caster, ability, position, target, multicast_n_times, delay)
    local instance = {
        caster = caster,
        ability = ability,
        position = position,
        target = target,
        multicast_n_times = multicast_n_times,
        used_times = 1,
        delay = delay
    }

    GameRules:GetGameModeEntity():SetThink(
            function()
                return instance:OnThink()
            end,
            nil,
            caster:entindex() .. "$" .. ability:GetAbilityName(), -- interrupt current multicast of the same ability from the same hero
            delay
    )

    return setmetatable(instance, { __index = self })
end

function Thinker:OnThink()
    self.caster:SetCursorPosition(self.position)
    self.caster:SetCursorCastTarget(self.target)
    self.ability:OnSpellStart()

    self.used_times = self.used_times + 1
    local pfx = ParticleManager:CreateParticle(
            "particles/units/heroes/hero_ogre_magi/ogre_magi_multicast.vpcf",
            PATTACH_OVERHEAD_FOLLOW,
            self.caster
    )
    ParticleManager:SetParticleControl(pfx, 1, Vector(self.used_times, 1, 0))

    if self.used_times < self.multicast_n_times then
        return self.delay
    else
        return nil
    end
end
Lua:
    "multicast"
    {
        "BaseClass"                        "ability_lua"
        "ScriptFile"                    "additional_abilities/multicast"
        "AbilityTextureName"            "additional/multicast"
        "AbilityType"                    "DOTA_ABILITY_TYPE_ULTIMATE"
        "FightRecapLevel"                "2"
        "AbilityBehavior"                "DOTA_ABILITY_BEHAVIOR_PASSIVE"
        "AbilityCastAnimation"            "ACT_INVALID"
        "MaxLevel"                      "3"

        "AbilitySpecial"
        {
            "01"
            {
                "var_type"                "FIELD_FLOAT"
                "multicast_2_times"        "75 75 75"
            }

            "02"
            {
                "var_type"                "FIELD_FLOAT"
                "multicast_3_times"        "0 30 30"
            }
            "03"
            {
                "var_type"                "FIELD_FLOAT"
                "multicast_4_times"        "0 0 15"
            }
            "04"
            {
                "var_type"              "FIELD_FLOAT"
                "delay"                 "0.7"
            }
        }
    }

Допущения, которые упростили реализацию:
  • Не работает с предметами
  • Для скилов с обездвиживающим модификатором на время каста, обороты мультикаста могут крутиться вхолостую (прыжок мираны, прыжок течса)
  • Не все переключаемые способности имеют соответствующий флаг [valve moment], поэтому некоторые неочевидные переключаемые способности могут мультикаститься (например, d у феникса)
  • Отключен для прерываемых способностей (upheavel, death ward итд)
  • Тестировал на ограниченном пуле героев из Dota1x2
Дайте знать, что вы думаете!
Я думаю всем похуй - ибо я давал скилл из кастомки которая в открытом доступе на гитхабе, не меняя ничего и не добавляя, просто что-б было и не задавали много вопросов, а как, а что и почему мультикаст не мультикастит дотовские способности

И ещё ты раздел перепутал
 
Реклама: