How to check if player and illusion existed

edited July 2015 in Questions

It's me again, Sorry for my English :P

Update: I think I found problem then I changed my title topic. At overload_check_order function still running when illusions gone, Error text will appear count as illusions timeout. Then how to check if illusions are gone (I tried EntIndexToHScript( event.PlayerID ) but only use for Heroes not illusions)

I have an idea to create new ability of Strom Spirit "Illusion Remnant". It's like "Static Remnant" but when casted its will create new illusions and apply ability "Overload" modifier for next attack to caster and illusions too.

I using SpellLibrary. To add new abilities of "Conjure Image" and "Overload" this is my code

npc_abilities_custom.txt (I lazy to edit overload then I copy all of code to test first)

"storm_spirit_overload_custom"
{
    // General
    //-------------------------------------------------------------------------------------------------------------
    "BaseClass"                     "ability_datadriven"
    "AbilityBehavior"               "DOTA_ABILITY_BEHAVIOR_PASSIVE"
    "AbilityUnitDamageType"         "DAMAGE_TYPE_MAGICAL"   
    "SpellImmunityType"             "SPELL_IMMUNITY_ENEMIES_NO"
    "AbilityTextureName"            "storm_spirit_overload"

    "AbilityDuration"               "0.6 0.6 0.6 0.6"

    / Damage.
    //-------------------------------------------------------------------------------------------------------------
    "AbilityDamage"                 "30 50 70 90"

    // Stats
    //-------------------------------------------------------------------------------------------------------------
    "AbilityModifierSupportBonus"   "40"

    // Special
    //-------------------------------------------------------------------------------------------------------------
    "AbilitySpecial"
    {
        "01"
        {
            "var_type"                      "FIELD_INTEGER"
            "overload_aoe"                  "275"
        }

        "02"
        {
            "var_type"                      "FIELD_INTEGER"
            "overload_move_slow"            "-80"
        }

        "03"
        {
            "var_type"                      "FIELD_INTEGER"
            "overload_attack_slow"          "-50"
        }
        "04"
        {
            "var_type"                      "FIELD_FLOAT"
            "tooltip_duration"              "0.6 0.6 0.6 0.6"
        }
    }

    // Data driven
    //-------------------------------------------------------------------------------------------------------------
    "precache"
    {
        "soundfile"                         "soundevents/game_sounds_heroes/game_sounds_stormspirit.vsndevts"
        "particle"                          "particles/units/heroes/hero_stormspirit/stormspirit_overload_ambient.vpcf"
    }

    "Modifiers"
    {
        "modifier_overload_passive_datadriven"
        {
            "Passive"                       "1"
            "IsPurgable"                    "0"
            "IsHidden"                      "0"
            "IsBuff"                        "1"

            "OnCreated"
            {
                "RunScript"
                {
                    "ScriptFile"            "heroes/hero_stormspirit/overload.lua"
                    "Function"              "overload_check_order"
                }
            }
        }

        "modifier_overload_damage_datadriven"
        {
            "IsPurgable"                    "0"
            "IsHidden"                      "1"

            "OnCreated"
            {
                "AttachEffect"
                {
                    "Target"                "CASTER"
                    "EffectName"            "particles/units/heroes/hero_stormspirit/stormspirit_overload_ambient.vpcf"
                    "EffectAttachType"      "start_at_customorigin"
                    "ControlPointEntities"
                    {
                        "CASTER"            "attach_attack1"
                    }
                }
            }

            "OnAttackLanded"
            {
                "FireSound"
                {
                    "Target"                "TARGET"
                    "EffectName"            "Hero_StormSpirit.Overload"
                }

                "FireEffect"
                {
                    "Target"                "TARGET"
                    "EffectName"            "particles/units/heroes/hero_stormspirit/stormspirit_overload_discharge.vpcf"
                    "EffectAttachType"      "start_at_origin"
                }

                "ActOnTargets"
                {
                    "Target"
                    {
                        "Center"            "TARGET"
                        "Radius"            "%overload_aoe"
                        "Teams"             "DOTA_UNIT_TARGET_TEAM_ENEMY"
                        "Types"             "DOTA_UNIT_TARGET_BASIC | DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_MECHANICAL"
                        "Flags"             "DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES"
                    }

                    "Action"
                    {
                        "Damage"
                        {
                            "Target"        "TARGET"
                            "Damage"        "%AbilityDamage"
                            "Type"          "DAMAGE_TYPE_MAGICAL"
                        }

                        "ApplyModifier"
                        {
                            "Target"        "TARGET"
                            "ModifierName"  "modifier_overload_debuff_datadriven"
                        }
                    }
                }

                "RemoveModifier"
                {
                    "Target"                "CASTER"
                    "ModifierName"          "modifier_overload_damage_datadriven"
                }
            }
        }

        "modifier_overload_debuff_datadriven"
        {
            "IsDebuff"                      "1"

            "Duration"                      "%tooltip_duration"

            "Properties"
            {
                "MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE"  "%overload_move_slow"
                "MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT"  "%overload_attack_slow"
            }
        }
    }
}

"storm_spirit_illusion_remnant"
{
    "MaxLevel"                      "7"
    "LevelsBetweenUpgrades"         "6"
    "BaseClass"                     "ability_datadriven"
    "AbilityBehavior"               "DOTA_ABILITY_BEHAVIOR_NO_TARGET | DOTA_ABILITY_BEHAVIOR_IMMEDIATE"
    "AbilityCastPoint"              "0"
    "AbilityCooldown"               "10"
    "AbilityDamage"                 "0"
    "AbilityManaCost"               "50 60 70 80 90 100 110"    
    "AbilitySpecial"
    {
        "01"
        {
            "var_type"                          "FIELD_FLOAT"
            "illusion_duration"                 "32.0"
        }
        "02"
        {
            "var_type"                          "FIELD_FLOAT"
            "illusion_outgoing_damage"          "-70.0 -60.0 -50.0 -40.0"       
        }
        "03"
        {
            "var_type"                          "FIELD_FLOAT"
            "illusion_outgoing_tooltip"         "30.0 40.0 50.0 60.0"
        }
        "04"
        {
            "var_type"                          "FIELD_FLOAT"
            "illusion_incoming_damage"          "325.0"
        }
        "05"
        {
            "var_type"                          "FIELD_FLOAT"
            "illusion_incoming_damage_total_tooltip"            "425.0"
        }               
    }
    "OnSpellStart"
    {
        "FireSound"
        {
            "EffectName"    "DOTA_Item.Manta.Activate"
            "Target"        "CASTER"
        }
        "RunScript"
        {
            "ScriptFile"        "abilities_function.lua"
            "Function"          "ConjureImage"
        }
    }
}

vscripts\abilities_function.lua (I only edited at apply new modifier, it was ability of Terrorblade)

function ConjureImage( event )
    print("Conjure Image")
    local caster = event.caster
    local player = caster:GetPlayerID()
    local ability = event.ability
    local unit_name = caster:GetUnitName()
    local origin = caster:GetAbsOrigin() + RandomVector(100)
    local duration = ability:GetLevelSpecialValueFor( "illusion_duration", ability:GetLevel() - 1 )
    local outgoingDamage = ability:GetLevelSpecialValueFor( "illusion_outgoing_damage", ability:GetLevel() - 1 )
    local incomingDamage = ability:GetLevelSpecialValueFor( "illusion_incoming_damage", ability:GetLevel() - 1 )

    -- handle_UnitOwner needs to be nil, else it will crash the game.
    local illusion = CreateUnitByName(unit_name, origin, true, caster, nil, caster:GetTeamNumber())
    illusion:SetPlayerID(caster:GetPlayerID())
    illusion:SetControllableByPlayer(player, true)

    -- Level Up the unit to the casters level
    local casterLevel = caster:GetLevel()
    for i=1,casterLevel-1 do
        illusion:HeroLevelUp(false)
    end

    -- Set the skill points to 0 and learn the skills of the caster
    illusion:SetAbilityPoints(0)
    for abilitySlot=0,15 do
        local ability = caster:GetAbilityByIndex(abilitySlot)
        if ability ~= nil then 
            local abilityLevel = ability:GetLevel()
            local abilityName = ability:GetAbilityName()
            local illusionAbility = illusion:FindAbilityByName(abilityName)
            illusionAbility:SetLevel(abilityLevel)
        end
    end

    -- Recreate the items of the caster
    for itemSlot=0,5 do
        local item = caster:GetItemInSlot(itemSlot)
        if item ~= nil then
            local itemName = item:GetName()
            local newItem = CreateItem(itemName, illusion, illusion)
            illusion:AddItem(newItem)
        end
    end

    -- Add our datadriven Metamorphosis modifier if appropiate
    -- You can add other buffs that want to be passed to illusions this way
    if caster:HasModifier("modifier_overload_passive_datadriven") then
        local meta_ability = caster:FindAbilityByName("storm_spirit_overload_custom")
        meta_ability:ApplyDataDrivenModifier(illusion, illusion, "modifier_overload_damage_datadriven", nil)
    end

    -- Set the unit as an illusion
    -- modifier_illusion controls many illusion properties like +Green damage not adding to the unit damage, not being able to cast spells and the team-only blue particle
    illusion:AddNewModifier(caster, ability, "modifier_illusion", { duration = duration, outgoing_damage = outgoingDamage, incoming_damage = incomingDamage })

    -- Without MakeIllusion the unit counts as a hero, e.g. if it dies to neutrals it says killed by neutrals, it respawns, etc.
    illusion:MakeIllusion()
end

vscripts\heroes\hero_stormspirit\overload.lua (This is I think here is problem)

function overload_check_order( keys )
    local caster = keys.caster
    local ability = keys.ability
    ListenToGameEvent( "dota_player_used_ability", function( event )
        -- Check if ability on cast bar is casted
        for i = 0, (caster:GetAbilityCount() - 1) do
                ability:ApplyDataDrivenModifier( caster, caster, "modifier_overload_damage_datadriven", {} )
                break
        end
    end, nil)
end

It's work great! When I casted all of illusions will get modifier too. But stuck at some bug when I casted often sometime will cause text error showup even it still work

stack traceback:

[C]: in function 'GetAbilityCount'

...nt\scripts\vscripts\heroes\hero_stormspirit\overload.lua:13: in function <...nt\scripts\vscripts\heroes\hero_stormspirit\overload.lua:11>

Script Runtime Error: ...nt\scripts\vscripts\heroes\hero_stormspirit\overload.lua:13: This object has been deleted from C++ and no longer exists. (Use :IsNull() to detect this.)

Here some picture:

At ability 3 there is illusion and 4 is overload asd

You will see when it use ability illusion it will create overload for illusion too asd

It's work to all illusions (Manta too) when caster casted some ability asd

This is error text I don't know how to fix it but on ability overload still work normaly asd

How to fix it? I really new for LUA and English too. Thanks :D

Hello I live in Thailand, I just 19 now and I very love to be a programmer :D But you should know. Most people of Thailand can't talk English like me :P

Comments

  • edited July 2015 Posts: 1,670

    There was no need for the long post with all the ability code, better use pastebin links and just copy 1 line of the error.

    The "This object has been deleted from C++" error is caused due to attempting to access a handle that was already deleted and grabbed by the garbage collector.

    You absolutely don't want to define a Game Event Listener inside an overload script. You generally define these once in a main lua file (not a file to be called with RunScript), and if you are looking for a global behavior just do the logic in there.

    What you want to do instead, is having a caster.illusions table which will contain the handles of all your created illusions (and will be cleaned up after they time out/get destroyed), so in the overload_check_order you can just iterate over them doing ApplyDataDrivenModifier after the main hero casts a spell (from the RunScript of OnSpellStart)

    The concept of Modding Community doesn't go well together with Competitive Business
    My Project Page || My GitHub Profile ||

  • Posts: 4

    Thank you for answer, If I have more questions I will user pastebin :D

    But I'm still in beginning for LUA I cannot write my own code only use other source for edit. I will try later when I'm ready for now I just changed to next plan. :D

    Hello I live in Thailand, I just 19 now and I very love to be a programmer :D But you should know. Most people of Thailand can't talk English like me :P