Как сделать Static Remnant пассивным?

TiLLyB00

Пользователь
16 Дек 2019
16
0
Как сделать так, чтобы ременанты использовались сами каждые несколько секунд? Пожалуйста, напишите код, я в луа и кастомных скиллах вообще не шарю, а так хоть посмотрю на примере вашего кода.
 
Последнее редактирование:

SniperX

Друзья CG
26 Фев 2018
539
100
Проект
Dota 2x4
Как сделать так, чтобы ременанты использовались сами каждые несколько секунд? Пожалуйста, напишите код, я в луа и кастомных скиллах вообще не шарю, а так хоть посмотрю на примере вашего кода.
Берёшь сначала абилку с библиотеки (не забудь про луа), потом в дд всовываешь модифаер, который постоянно работает (Passive, ThinkInvertal), и при каждом ThinkInterval (OnIntervalThink) будет юзать, то что в OnSpellStart, не забудь про AbilityBehavior, да и не забудь про timers.lua из баребонки, чтобы её подключить тебе надо вставить в свою кастомку эту штуку, затем пропиши в addon_game_mode.lua в самом начале require("timers.lua"), по идеи получится это

C++:
    "storm_spirit_static_remnant_passive"

    {

        "BaseClass"                        "ability_datadriven"

        "AbilityBehavior"                "DOTA_ABILITY_BEHAVIOR_PASSIVE"

        "AbilityUnitDamageType"            "DAMAGE_TYPE_MAGICAL" 

        "SpellImmunityType"                "SPELL_IMMUNITY_ENEMIES_NO"

        "FightRecapLevel"                "1"

        "AbilityTextureName"            "storm_spirit_static_remnant"

        "AbilityCastPoint"                "0 0 0 0"

        "AbilityCooldown"                "3.5"

        "AbilityDuration"                "12.0 12.0 12.0 12.0"

        "AbilityManaCost"                "70 80 90 100"

        "AbilitySpecial"

        {

            "01"

            {

                "var_type"            "FIELD_INTEGER"

                "static_remnant_radius"        "235"     

            }

            "02"

            {

                "var_type"            "FIELD_INTEGER"

                "static_remnant_damage_radius"    "260"

            }

            "03"

            {

                "var_type"            "FIELD_FLOAT"

                "static_remnant_delay"        "1.0"

            }

            "04"

            {

                "var_type"            "FIELD_INTEGER"

                "static_remnant_damage"            "140 180 220 260"

            }

            "05"

            {

                "var_type"            "FIELD_FLOAT"

                "interval"            "4 3 2 1" // Интервал каста

            }

        }

        "precache"

        {

            "particle"                "particles/units/heroes/hero_stormspirit/stormspirit_static_remnant.vpcf"

        }

        "Modifiers"

        {

            "modifier_static_remnant_trigger_datadriven"

            {

                "Passive"    "1"

                "IsHidden"    "1"

                "ThinkInterval" "%interval"

                "OnIntervalThink"

                {

                    "FireSound"

                    {

                        "Target"            "CASTER"

                        "EffectName"        "Hero_StormSpirit.StaticRemnantPlant"

                    }

                    "RunScript"

                    {

                        "ScriptFile"        "путь/к/луа/storm_spirit_static_remnant.lua"

                        "Function"            "static_remnant_init"

                    }

                }

            }

            "modifier_static_remnant_dummy_datadriven"

            {

                "OverrideAnimation"    "ACT_DOTA_CAST_ABILITY_1"

                "EffectName"        "particles/units/heroes/hero_stormspirit/stormspirit_static_remnant.vpcf"

                "EffectAttachType"    "follow_origin"

                "States"

                {

                    "MODIFIER_STATE_INVULNERABLE"                    "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_NO_HEALTH_BAR"                    "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_NO_UNIT_COLLISION"                "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_NOT_ON_MINIMAP"                    "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_UNSELECTABLE"                    "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_COMMAND_RESTRICTED"                "MODIFIER_STATE_VALUE_ENABLED"

                }

            }

            "modifier_static_remnant_dummy_freeze_datadriven"

            {

                "States"

                {

                    "MODIFIER_STATE_FROZEN"                            "MODIFIER_STATE_VALUE_ENABLED"

                }

            }

        }

    }
Lua:
function static_remnant_init( keys )

    local caster = keys.caster

    local target = caster:GetAbsOrigin()

    local ability = keys.ability

    local model_name = caster:GetModelName()

    local dummyModifierName = "modifier_static_remnant_dummy_datadriven"

    local dummyFreezeModifierName = "modifier_static_remnant_dummy_freeze_datadriven"

    local remnant_timer = 0.0

    local remnant_interval_check = 0.1

    local delay = ability:GetLevelSpecialValueFor( "static_remnant_delay", ability:GetLevel() - 1 )

    local trigger_radius = ability:GetLevelSpecialValueFor( "static_remnant_radius", ability:GetLevel() - 1 )

    local damage_radius = ability:GetLevelSpecialValueFor( "static_remnant_damage_radius", ability:GetLevel() - 1 )

    local ability_damage = ability:GetLevelSpecialValueFor( "static_remnant_damage", ability:GetLevel() - 1 )

    local ability_damage_type = ability:GetAbilityDamageType()

    local ability_duration = ability:GetDuration()

    local dummy = CreateUnitByName( caster:GetName(), target, false, caster, nil, caster:GetTeamNumber() )

    ability:ApplyDataDrivenModifier( caster, dummy, dummyModifierName, {} )

    Timers:CreateTimer( delay, function()

            if not dummy:HasModifier( dummyFreezeModifierName ) then

                ability:ApplyDataDrivenModifier( caster, dummy, dummyFreezeModifierName, {} )

            end

            local units = FindUnitsInRadius( caster:GetTeamNumber(), target, caster, trigger_radius,

                DOTA_UNIT_TARGET_TEAM_ENEMY, DOTA_UNIT_TARGET_BASIC + DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, 0, false )

            if #units > 0 then

                for k, v in pairs( units ) do

                    local damageTable = {

                        victim = v,

                        attacker = caster,

                        damage = ability_damage,

                        damage_type = ability_damage_type

                    }

                    ApplyDamage( damageTable )

                end

                StartSoundEvent( "Hero_StormSpirit.StaticRemnantExplode", dummy )

                dummy:RemoveSelf()

                return nil

            end

            remnant_timer = remnant_timer + remnant_interval_check

            if remnant_timer >= ability_duration then

                dummy:RemoveSelf()

                return nil

            else

                return remnant_interval_check

            end

        end

    )

end
Lua:
TIMERS_VERSION = "1.05"

--[[

  -- A timer running every second that starts immediately on the next frame, respects pauses

  Timers:CreateTimer(function()

      print ("Hello. I'm running immediately and then every second thereafter.")

      return 1.0

    end

  )

  Timers(function()

    print ("Hello. I'm running immediately and then every second thereafter.")

    return 1.0

  end)

  Timers:CreateTimer(GameMode.someFunction, GameMode)

  -- A timer running every second that starts 5 seconds in the future, respects pauses

  Timers:CreateTimer(5, function()

      print ("Hello. I'm running 5 seconds after you called me and then every second thereafter.")

      return 1.0

    end

  )

  Timers:CreateTimer({

    endTime = 10, -- when this timer should first execute, you can omit this if you want it to run first on the next frame

    callback = function()

      print ("Hello. I'm running 10 seconds after when I was started.")

    end

  })

  Timers:CreateTimer({

    useGameTime = false,

    endTime = 10, -- when this timer should first execute, you can omit this if you want it to run first on the next frame

    callback = function()

      print ("Hello. I'm running 10 seconds after I was started even if someone paused the game.")

    end

  })

Timers:CreateTimer("uniqueTimerString3", {

    useGameTime = false,

    endTime = 120,

    callback = function()

      print ("Hello. I'm running after 2 minutes and then every second thereafter.")

      return 1

    end

  })

    Timers:CreateTimer("uniqueTimerString3", {

    useOldStyle = true,

    endTime = GameRules:GetGameTime() + 5,

    callback = function()

      print ("Hello. I'm running after 5 seconds and then every second thereafter.")

      return GameRules:GetGameTime() + 1

    end

  })

]]

TIMERS_THINK = 0.01

if Timers == nil then

  print ( '[Timers] creating Timers' )

  Timers = {}

  setmetatable(Timers, {

    __call = function(t, ...)

      return t:CreateTimer(...)

    end

  })

end

function Timers:start()

  Timers = self

  self.timers = {}

  local ent = SpawnEntityFromTableSynchronous("info_target", {targetname="timers_lua_thinker"})

  ent:SetThink("Think", self, "timers", TIMERS_THINK)

end

function Timers:Think()

    local now = GameRules:GetGameTime()

  for k,v in pairs(Timers.timers) do

    local bUseGameTime = true

    if v.useGameTime ~= nil and v.useGameTime == false then

      bUseGameTime = false

    end

    local bOldStyle = false

    if v.useOldStyle ~= nil and v.useOldStyle == true then

      bOldStyle = true

    end

    local now = GameRules:GetGameTime()

    if not bUseGameTime then

      now = Time()

    end

    if v.endTime == nil then

      v.endTime = now

    end

    if now >= v.endTime then

      -- Remove from timers list

      Timers.timers[k] = nil

      Timers.runningTimer = k

      Timers.removeSelf = false

      local status, nextCall

      if v.context then

        status, nextCall = xpcall(function() return v.callback(v.context, v) end, function (msg)

                                    return msg..'\n'..debug.traceback()..'\n'

                                  end)

      else

        status, nextCall = xpcall(function() return v.callback(v) end, function (msg)

                                    return msg..'\n'..debug.traceback()..'\n'

                                  end)

      end

      Timers.runningTimer = nil

      if status then

        if nextCall and not Timers.removeSelf then

          if bOldStyle then

            v.endTime = v.endTime + nextCall - now

          else

            v.endTime = v.endTime + nextCall

          end

          Timers.timers[k] = v

        end

      else

        Timers:HandleEventError('Timer', k, nextCall)

      end

    end

  end

  return TIMERS_THINK

end

function Timers:HandleEventError(name, event, err)

  name = tostring(name or 'unknown')

  event = tostring(event or 'unknown')

  err = tostring(err or 'unknown')

  if not self.errorHandled then

    -- Store that we handled an error

    self.errorHandled = true

  end

end

function Timers:CreateTimer(name, args, context)

  if type(name) == "function" then

    if args ~= nil then

      context = args

    end

    args = {callback = name}

    name = DoUniqueString("timer")

  elseif type(name) == "table" then

    args = name

    name = DoUniqueString("timer")

  elseif type(name) == "number" then

    args = {endTime = name, callback = args}

    name = DoUniqueString("timer")

  end

  if not args.callback then

    print("Invalid timer created: "..name)

    return

  end

  local now = GameRules:GetGameTime()

  if args.useGameTime ~= nil and args.useGameTime == false then

    now = Time()

  end

  if args.endTime == nil then

    args.endTime = now

  elseif args.useOldStyle == nil or args.useOldStyle == false then

    args.endTime = now + args.endTime

  end

  args.context = context

  Timers.timers[name] = args

  return name

end

function Timers:RemoveTimer(name)

  Timers.timers[name] = nil

  if Timers.runningTimer == name then

    Timers.removeSelf = true

  end

end

function Timers:RemoveTimers(killAll)

  local timers = {}

  Timers.removeSelf = true

  if not killAll then

    for k,v in pairs(Timers.timers) do

      if v.persist then

        timers[k] = v

      end

    end

  end

  Timers.timers = timers

end

if not Timers.timers then Timers:start() end

GameRules.Timers = Timers
 
  • Нравится
Реакции: TiLLyB00

TiLLyB00

Пользователь
16 Дек 2019
16
0
Берёшь сначала абилку с библиотеки (не забудь про луа), потом в дд всовываешь модифаер, который постоянно работает (Passive, ThinkInvertal), и при каждом ThinkInterval (OnIntervalThink) будет юзать, то что в OnSpellStart, не забудь про AbilityBehavior, да и не забудь про timers.lua из баребонки, чтобы её подключить тебе надо вставить в свою кастомку эту штуку, затем пропиши в addon_game_mode.lua в самом начале require("timers.lua"), по идеи получится это

C++:
    "storm_spirit_static_remnant_passive"

    {

        "BaseClass"                        "ability_datadriven"

        "AbilityBehavior"                "DOTA_ABILITY_BEHAVIOR_PASSIVE"

        "AbilityUnitDamageType"            "DAMAGE_TYPE_MAGICAL"

        "SpellImmunityType"                "SPELL_IMMUNITY_ENEMIES_NO"

        "FightRecapLevel"                "1"

        "AbilityTextureName"            "storm_spirit_static_remnant"

        "AbilityCastPoint"                "0 0 0 0"

        "AbilityCooldown"                "3.5"

        "AbilityDuration"                "12.0 12.0 12.0 12.0"

        "AbilityManaCost"                "70 80 90 100"

        "AbilitySpecial"

        {

            "01"

            {

                "var_type"            "FIELD_INTEGER"

                "static_remnant_radius"        "235"    

            }

            "02"

            {

                "var_type"            "FIELD_INTEGER"

                "static_remnant_damage_radius"    "260"

            }

            "03"

            {

                "var_type"            "FIELD_FLOAT"

                "static_remnant_delay"        "1.0"

            }

            "04"

            {

                "var_type"            "FIELD_INTEGER"

                "static_remnant_damage"            "140 180 220 260"

            }

            "05"

            {

                "var_type"            "FIELD_FLOAT"

                "interval"            "4 3 2 1" // Интервал каста

            }

        }

        "precache"

        {

            "particle"                "particles/units/heroes/hero_stormspirit/stormspirit_static_remnant.vpcf"

        }

        "Modifiers"

        {

            "modifier_static_remnant_trigger_datadriven"

            {

                "Passive"    "1"

                "IsHidden"    "1"

                "ThinkInterval" "%interval"

                "OnIntervalThink"

                {

                    "FireSound"

                    {

                        "Target"            "CASTER"

                        "EffectName"        "Hero_StormSpirit.StaticRemnantPlant"

                    }

                    "RunScript"

                    {

                        "ScriptFile"        "путь/к/луа/storm_spirit_static_remnant.lua"

                        "Function"            "static_remnant_init"

                    }

                }

            }

            "modifier_static_remnant_dummy_datadriven"

            {

                "OverrideAnimation"    "ACT_DOTA_CAST_ABILITY_1"

                "EffectName"        "particles/units/heroes/hero_stormspirit/stormspirit_static_remnant.vpcf"

                "EffectAttachType"    "follow_origin"

                "States"

                {

                    "MODIFIER_STATE_INVULNERABLE"                    "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_NO_HEALTH_BAR"                    "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_NO_UNIT_COLLISION"                "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_NOT_ON_MINIMAP"                    "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_UNSELECTABLE"                    "MODIFIER_STATE_VALUE_ENABLED"

                    "MODIFIER_STATE_COMMAND_RESTRICTED"                "MODIFIER_STATE_VALUE_ENABLED"

                }

            }

            "modifier_static_remnant_dummy_freeze_datadriven"

            {

                "States"

                {

                    "MODIFIER_STATE_FROZEN"                            "MODIFIER_STATE_VALUE_ENABLED"

                }

            }

        }

    }
Lua:
function static_remnant_init( keys )

    local caster = keys.caster

    local target = caster:GetAbsOrigin()

    local ability = keys.ability

    local model_name = caster:GetModelName()

    local dummyModifierName = "modifier_static_remnant_dummy_datadriven"

    local dummyFreezeModifierName = "modifier_static_remnant_dummy_freeze_datadriven"

    local remnant_timer = 0.0

    local remnant_interval_check = 0.1

    local delay = ability:GetLevelSpecialValueFor( "static_remnant_delay", ability:GetLevel() - 1 )

    local trigger_radius = ability:GetLevelSpecialValueFor( "static_remnant_radius", ability:GetLevel() - 1 )

    local damage_radius = ability:GetLevelSpecialValueFor( "static_remnant_damage_radius", ability:GetLevel() - 1 )

    local ability_damage = ability:GetLevelSpecialValueFor( "static_remnant_damage", ability:GetLevel() - 1 )

    local ability_damage_type = ability:GetAbilityDamageType()

    local ability_duration = ability:GetDuration()

    local dummy = CreateUnitByName( caster:GetName(), target, false, caster, nil, caster:GetTeamNumber() )

    ability:ApplyDataDrivenModifier( caster, dummy, dummyModifierName, {} )

    Timers:CreateTimer( delay, function()

            if not dummy:HasModifier( dummyFreezeModifierName ) then

                ability:ApplyDataDrivenModifier( caster, dummy, dummyFreezeModifierName, {} )

            end

            local units = FindUnitsInRadius( caster:GetTeamNumber(), target, caster, trigger_radius,

                DOTA_UNIT_TARGET_TEAM_ENEMY, DOTA_UNIT_TARGET_BASIC + DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, 0, false )

            if #units > 0 then

                for k, v in pairs( units ) do

                    local damageTable = {

                        victim = v,

                        attacker = caster,

                        damage = ability_damage,

                        damage_type = ability_damage_type

                    }

                    ApplyDamage( damageTable )

                end

                StartSoundEvent( "Hero_StormSpirit.StaticRemnantExplode", dummy )

                dummy:RemoveSelf()

                return nil

            end

            remnant_timer = remnant_timer + remnant_interval_check

            if remnant_timer >= ability_duration then

                dummy:RemoveSelf()

                return nil

            else

                return remnant_interval_check

            end

        end

    )

end
Lua:
TIMERS_VERSION = "1.05"

--[[

  -- A timer running every second that starts immediately on the next frame, respects pauses

  Timers:CreateTimer(function()

      print ("Hello. I'm running immediately and then every second thereafter.")

      return 1.0

    end

  )

  Timers(function()

    print ("Hello. I'm running immediately and then every second thereafter.")

    return 1.0

  end)

  Timers:CreateTimer(GameMode.someFunction, GameMode)

  -- A timer running every second that starts 5 seconds in the future, respects pauses

  Timers:CreateTimer(5, function()

      print ("Hello. I'm running 5 seconds after you called me and then every second thereafter.")

      return 1.0

    end

  )

  Timers:CreateTimer({

    endTime = 10, -- when this timer should first execute, you can omit this if you want it to run first on the next frame

    callback = function()

      print ("Hello. I'm running 10 seconds after when I was started.")

    end

  })

  Timers:CreateTimer({

    useGameTime = false,

    endTime = 10, -- when this timer should first execute, you can omit this if you want it to run first on the next frame

    callback = function()

      print ("Hello. I'm running 10 seconds after I was started even if someone paused the game.")

    end

  })

Timers:CreateTimer("uniqueTimerString3", {

    useGameTime = false,

    endTime = 120,

    callback = function()

      print ("Hello. I'm running after 2 minutes and then every second thereafter.")

      return 1

    end

  })

    Timers:CreateTimer("uniqueTimerString3", {

    useOldStyle = true,

    endTime = GameRules:GetGameTime() + 5,

    callback = function()

      print ("Hello. I'm running after 5 seconds and then every second thereafter.")

      return GameRules:GetGameTime() + 1

    end

  })

]]

TIMERS_THINK = 0.01

if Timers == nil then

  print ( '[Timers] creating Timers' )

  Timers = {}

  setmetatable(Timers, {

    __call = function(t, ...)

      return t:CreateTimer(...)

    end

  })

end

function Timers:start()

  Timers = self

  self.timers = {}

  local ent = SpawnEntityFromTableSynchronous("info_target", {targetname="timers_lua_thinker"})

  ent:SetThink("Think", self, "timers", TIMERS_THINK)

end

function Timers:Think()

    local now = GameRules:GetGameTime()

  for k,v in pairs(Timers.timers) do

    local bUseGameTime = true

    if v.useGameTime ~= nil and v.useGameTime == false then

      bUseGameTime = false

    end

    local bOldStyle = false

    if v.useOldStyle ~= nil and v.useOldStyle == true then

      bOldStyle = true

    end

    local now = GameRules:GetGameTime()

    if not bUseGameTime then

      now = Time()

    end

    if v.endTime == nil then

      v.endTime = now

    end

    if now >= v.endTime then

      -- Remove from timers list

      Timers.timers[k] = nil

      Timers.runningTimer = k

      Timers.removeSelf = false

      local status, nextCall

      if v.context then

        status, nextCall = xpcall(function() return v.callback(v.context, v) end, function (msg)

                                    return msg..'\n'..debug.traceback()..'\n'

                                  end)

      else

        status, nextCall = xpcall(function() return v.callback(v) end, function (msg)

                                    return msg..'\n'..debug.traceback()..'\n'

                                  end)

      end

      Timers.runningTimer = nil

      if status then

        if nextCall and not Timers.removeSelf then

          if bOldStyle then

            v.endTime = v.endTime + nextCall - now

          else

            v.endTime = v.endTime + nextCall

          end

          Timers.timers[k] = v

        end

      else

        Timers:HandleEventError('Timer', k, nextCall)

      end

    end

  end

  return TIMERS_THINK

end

function Timers:HandleEventError(name, event, err)

  name = tostring(name or 'unknown')

  event = tostring(event or 'unknown')

  err = tostring(err or 'unknown')

  if not self.errorHandled then

    -- Store that we handled an error

    self.errorHandled = true

  end

end

function Timers:CreateTimer(name, args, context)

  if type(name) == "function" then

    if args ~= nil then

      context = args

    end

    args = {callback = name}

    name = DoUniqueString("timer")

  elseif type(name) == "table" then

    args = name

    name = DoUniqueString("timer")

  elseif type(name) == "number" then

    args = {endTime = name, callback = args}

    name = DoUniqueString("timer")

  end

  if not args.callback then

    print("Invalid timer created: "..name)

    return

  end

  local now = GameRules:GetGameTime()

  if args.useGameTime ~= nil and args.useGameTime == false then

    now = Time()

  end

  if args.endTime == nil then

    args.endTime = now

  elseif args.useOldStyle == nil or args.useOldStyle == false then

    args.endTime = now + args.endTime

  end

  args.context = context

  Timers.timers[name] = args

  return name

end

function Timers:RemoveTimer(name)

  Timers.timers[name] = nil

  if Timers.runningTimer == name then

    Timers.removeSelf = true

  end

end

function Timers:RemoveTimers(killAll)

  local timers = {}

  Timers.removeSelf = true

  if not killAll then

    for k,v in pairs(Timers.timers) do

      if v.persist then

        timers[k] = v

      end

    end

  end

  Timers.timers = timers

end

if not Timers.timers then Timers:start() end

GameRules.Timers = Timers
Большие спасибо!
 
Реклама: