DataDriven Items

edited March 2016 in Tutorials

A comprehensive guide to npc_items_custom and coding items

img

General

Start with "item_" and your item name. If you don't put item_ at the begging of an item, bad things happen

"item_custom" { ... }

Each item needs its proper ID for purchasing on the shop, although you can define items without an ID if you only plan to create them through Lua. Do not override Dota IDs, use IDs over 2000

"ID" "3222"

Next is the BaseClass. It can be DataDriven, or overriding an existing item from the default dota item_names.

"BaseClass" "item_datadriven"
            "item_aegis"

If you want to override an item, you won't be able to change/add abilities, you'll be limited to change values from items.txt (and some values can't even be changed) So it's recommended to always try to make a datadriven version of the item if you want to have complete freedom on what your item does.

Now that we settled that, I'll review the most common key values seen in items.

Basic Rules

"ItemCost" "322"
"ItemKillable" "0" 
"ItemSellable" "1"
"ItemPurchasable" "1"
"ItemDroppable" "1"

ItemKillable lets both allies and enemies destroy the dropped item by attacking it.

Stock

"ItemStockMax" "1" 
"ItemStockTime" "100"
"ItemStockInitial" "3"

Ownership

If you omit the following, its behavior will be NOT_SHAREABLE

"ItemShareability" "ITEM_NOT_SHAREABLE"             //Rapier
                   "ITEM_PARTIALLY_SHAREABLE"       //Ring of Regen
                   "ITEM_FULLY_SHAREABLE"           //Gem
                   "ITEM_FULLY_SHAREABLE_STACKING"  //Consumables

Charges

"ItemInitialCharges" "1" //How many charges should the item start with - Tango x3 
"ItemDisplayCharges" "1" //Hide the charges of the item - Aegis 
"ItemRequiresCharges" "1" //The active ability needs charges to be used - Urn

Also remember to add this somewhere, normally at the beginning of a OnSpellStart block

"SpendCharge" {}

Stacking, Consumable

"ItemStackable" "1"
"ItemPermanent" "0"

If "ItemPermanent" is set to 1, charged items won't disappear when they hit 0 charges (Bottle, Urn, etc) By omitting it will also default to 1.

Auto Cast

This value is the key for Tomes of Stats and other consumable items:

"ItemCastOnPickup" "1"

Upgradeable items

"MaxUpgradeLevel" "5" // Dagon - 5
"ItemBaseLevel" "1" //You'll need 5 different items, and change each accordingly

Recipes

"item_recipe_custom" 
{
    "ID" "1200"
    "BaseClass"           "item_datadriven"
    "ItemRecipe"          "1" //destroyed after combine
    "ItemCost"            "0" //if its 0, it will combine without needing a recipe.
    "ItemResult"          "item_custom" //the result of combining the ItemRequirements
    "ItemRequirements"
    {
        "01" "item_ingredient_1;item_ingredient_2;item_ingredient_3"
        "02" "item_ingredient_1;item_ingredient_2;item_ingredient_alternative_3"
    }
}

IMPORTANT NOTE: Your item name for the recipe to be recognized by the Dota Shop UI NEEDS to have this format:

"item_recipe_(name of your item)"

Meaning if the ItemResult you want to get is called "item_capuchino", your recipe would be: "item_recipe_capuchino"

img

If you don't, the item will till be combinable but it won't show the neat lines to the possible upgrades.

Disassembling

"ItemDisassembleRule" "DOTA_ITEM_DISASSEMBLE_ALWAYS"
                      "DOTA_ITEM_DISASSEMBLE_NEVER"

Common Modifier Key Values for items

We now have an item, but it doesn't do anything on its own. To make it add stats or buffs, we need to set modifiers inside the item definition For more on Modifiers, check the [Constants in the wiki]

"Modifiers"
{
    "item_custom_modifier"
    {
        "Passive" "1"  
        "IsHidden" "0"  
        "Attributes" "MODIFIER_ATTRIBUTE_MULTIPLE" //This makes duplicate items stack their properties
        "Properties"
        {
            "MODIFIER_PROPERTY_MOVESPEED_BONUS_CONSTANT" "%movement_speed"
            "MODIFIER_PROPERTY_EVASION_CONSTANT" "%evasion"
            "MODIFIER_PROPERTY_STATS_STRENGTH_BONUS" "%bonus_str_agi"
            "MODIFIER_PROPERTY_STATS_AGILITY_BONUS" "%bonus_agi"
            "MODIFIER_PROPERTY_STATS_INTELLECT_BONUS" "%bonus_int"
            "MODIFIER_PROPERTY_BASEDAMAGEOUTGOING_PERCENTAGE" "%damage_bonus_percent"
        }

        "States"  
        {
            "MODIFIER_STATE_SPECIALLY_DENIABLE" "MODIFIER_STATE_VALUE_ENABLED"
            "MODIFIER_STATE_MAGIC_IMMUNE" "MODIFIER_STATE_VALUE_ENABLED"
            "MODIFIER_STATE_NO_HEALTH_BAR" "MODIFIER_STATE_VALUE_ENABLED"  
        }
    }
}

Adding spell functionality

Apart from this values specially related to items, you can add everything that could be part of a datadriven ability, for example:

"AbilityBehavior" "DOTA_ABILITY_BEHAVIOR_PASSIVE"
"AbilityUnitTargetTeam" "DOTA_UNIT_TARGET_TEAM_BOTH"
"AbilityUnitTargetType" "DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_BASIC"
"AbilityCastAnimation" "ACT_DOTA_CAST_ABILITY_1"
"AbilityManaCost" "100"
"AbilitySpecial"
{ ... }

Ability Events like "OnSpellStart", "OnOwnerDied" or "OnEquip" also go here in the main block.

You need at least set the AbilityBehavior for your item to not be active (if you don't, it will default to DOTA_ABILITY_BEHAVIOR_UNIT_TARGET).

See more on the complete DataDriven Ability Breakdown

Icons and Custom Shops

For your item to have an icon you'll need to go to your addon folder under this path:

/resource/flash3/images/items

And put a .PNG file with dimensions 88 x 64 (86 width is also valid), with the same name as the "item_custom", WITHOUT the "item_"

Then in your "item_custom" code, you add the following:

"AbilityTextureName" "item_custom"

You can also use the names of the dota icons. Just make sure this line starts with "item_, so the engine knows to look the image on the items folder.

Adding the item to a shop. Layout [Here] For this, inside your addon folder you need to go inside scripts/shops and make/edit a .txt file with this name file structure:

mapName_shops.txt

mapName should be the name of YOUR MAP (.vmap file in Hammer or content folder), NOT your addon name (both could be the same, or you could have multiple maps with different shops)

Adding "_shops" to the mapName is also mandatory.

A template shop file can be copied from here: http://pastebin.com/KZrtm1xQ

In addition to this file, your item can have key value rules for where it can be bought

"SideShop" "1"  
"SecretShop" "0"

At the moment of writing this guide, we can only set up 3 different shops (Home, Side and Secret). You can change categories and shop tab names, with [addon_english modding]

To make an actual shop area inside your map on Hammer, check this other tutorial tutorial_creating_a_custom_shop_step_by_step

To disable your dota items, use this npc_abillities_override.txt inside the scripts/npc folder.

Cosmetic Values: Models, Effects, Tags and others.

These values are optional but greatly improve the quality of your item

Sounds when Picked, Dropped

"UIPickupSound" "Item.PickUpRingShop" //Sound when adquiring the item
"UIDropSound" "Item.DropRecipeShop" //Sound when dropping the item manually
"WorldDropSound" "Item.DropGemWorld" //Sound when dropping the item on death (?)

Model and Glow in the world.

VMDL and Particle files can be seen through the [Asset Browser]

"Model" "models/chest_worlddrop.vmdl"
"Effect" "particles/generic_gameplay/dropped_item.vpcf"

You can find good models in /props_gameplay, /econ or use your own customs

Important: If you create the item through lua [CreateItemOnPositionSync], you need to provide vision of the world position where the item is being created, at least briefly, to properly display the particle effect.

Change the displayed color of the item

"ItemQuality"    "artifact" //Orange 
                 "epic" //Purple
                 "rare" //Blue
                 "common" //Green
                 "component" //White
                 "consumable" //White

Tags & Alias

Tags are defined in addon_english, find them in [dota_english] under // Tags Aliases help the search bar to find the item quickly with abreviations

"ItemShopTags" "int;str;agi;mana_pool;health_pool;hard_to_tag"
"ItemAliases" "this;appears_in;search"

Omit to not announce.

"ItemDeclarations" "DECLARE_PURCHASES_TO_TEAMMATES"
                   "DECLARE_PURCHASES_IN_SPEECH"
                   "DECLARE_PURCHASES_TO_SPECTATORS"

Restrictions

This is how Basher is disallowed for certain heroes

"InvalidHeroes" "npc_dota_hero_spirit_breaker;npc_dota_hero_faceless_void"

For the Scripted, more powerful version, read more on Item Restrictions & Requirements


Alt-Click

Alt-click text on items in Inventory and dropped on the ground. Takes the strings from resource/addon_english.txt or any other languages.

PingOverrideText

Overrides the default "[ALLIES] ItemName dropped here". It will look for #DOTA_Chat_Text_String (Text_String can be whatever) in your addon strings.

In the item_datadriven:

"PingOverrideText" "DOTA_Chat_Text_String" 

In addon_english.txt:

"DOTA_Chat_Text_String" "[VOLVO] Giff"

ItemAlertable

Displays "[ALLIES] Gather for ItemName here."

img

"ItemAlertable" "1" 

That's it for all the Item-related key values. In next post we'll review different examples.

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

Comments

  • edited June 2015 Posts: 1,670

    Examples

    1. Basic Item Skeleton
    2. Adding More Stats
    3. Charged Consumables
      • Tome of Stats
      • Potion of Health
      • Summons
    4. Upgradeable Items and Recipes
    5. Passives
      • Auras
      • Damage over time
      • Cleave
      • Crit
      • Lifesteal Orb
      • Block

    Basic Item Skeleton

    Copy this to start an item

    "item_custom" 
    {
        "ID"           "1100"
        "BaseClass"    "item_datadriven"
        "AbilityTextureName" "item_rapier"
        "Model"        "models/props_gameplay/recipe.vmdl" 
        "Effect"       "particles/generic_gameplay/dropped_item.vpcf"
        "ItemQuality"  "artifact"
    
        "ItemCost"     "322"
        "ItemKillable" "0" 
        "ItemSellable" "1"
        "ItemPurchasable" "1"
        "ItemDroppable" "1"
        "ItemShareability" "ITEM_NOT_SHAREABLE"
    
        "SideShop"     "1" 
        "SecretShop"   "0"
    
        "ItemStackable" "1"
        "ItemPermanent" "1"
        "ItemDisassembleRule" "DOTA_ITEM_DISASSEMBLE_ALWAYS"
    
        "AbilitySpecial"
        {
            "01"
            {
                "var_type"      "FIELD_INTEGER"
                "bonus_stat"    "100"
            }
        }
    
        "Modifiers"
        {
            "modifier_item_custom"
            {
                "Passive"  "1"
                "IsHidden" "1" 
                "Attributes" "MODIFIER_ATTRIBUTE_MULTIPLE"
                "Properties"
                {
                    "MODIFIER_PROPERTY_STATS_STRENGTH_BONUS" "%bonus_stat"
                }
            } 
        }
    } 
    

    Those are the most important values. For Charges, Upgrades, Sounds, Aliases & Declarations add the lines explained before, I kept them out of the basic layout because they aren't needed for most items.

    I also added a very basic passive Modifier which takes the bonus_stat from AbilitySpecial to give 1 Strength bonus. Using AbilitySpecial makes it easier to make tooltips and adjust item values later without having to change said tooltips.


    Adding More Stats

    Every value from Modifier Constants can be added to the "Properties" block, some very common examples are:

        "Properties"
        {
            "MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT" "%bonus_attackspeed"
            "MODIFIER_PROPERTY_STATS_STRENGTH_BONUS" "%bonus_str"
            "MODIFIER_PROPERTY_STATS_AGILITY_BONUS" "%bonus_agi"
            "MODIFIER_PROPERTY_STATS_INTELLECT_BONUS" "%bonus_int"
            "MODIFIER_PROPERTY_HEALTH_BONUS"    "%bonus_hp"
            "MODIFIER_PROPERTY_HEALTH_REGEN_CONSTANT" "%bonus_health_regen"
            "MODIFIER_PROPERTY_MANA_BONUS"  "%bonus_hp"
            "MODIFIER_PROPERTY_MANA_REGEN_PERCENTAGE""  "%bonus_mana_regen"
            "MODIFIER_PROPERTY_BASEDAMAGEOUTGOING_PERCENTAGE"   "%bonus_damage_percent"
        }
    

    Charged Consumables

    Linking to Warchasers until I find a better way to format this.

    Tome of Stats

    item_tome_of_knowledge

    Potion of Health

    item_potion_of_healing

    Summons

    item_demonic_figurine

    Upgradeable Items and Recipes


    Apart from these values, item code uses the same datadriven values as abilities. See the DataDriven Ability Breakdown

    Yet, we can do some examples:

    Passives

    Auras

    "AbilityBehavior" "DOTA_ABILITY_BEHAVIOR_AURA | DOTA_ABILITY_BEHAVIOR_PASSIVE"

    In a modifier block:

        "Aura"  "custom_aura"
        "Aura_Teams"    "DOTA_UNIT_TARGET_TEAM_FRIENDLY"
        "Aura_Radius"   "%radius"
        "Aura_Types"    "DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_BASIC"
        "Aura_Flags" "DOTA_UNIT_TARGET_FLAG_RANGED_ONLY"
    

    Then have a new modifier block with the Aura name with the desired effects.

    Damage over time

    Inside a modifier, use "ThinkInterval" "1" and have a "OnIntervalThink" block in which you do damage.

        "ThinkInterval" "1"
        "OnIntervalThink"
        {
            "Damage"
            {
                 "Target"
                 {
                     "Center" "CASTER"
                     "Radius" "%radius"
                     "Teams" "DOTA_UNIT_TARGET_TEAM_ENEMY"
                     "Types" "DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_BASIC"
                 }
                 "Type" "DAMAGE_TYPE_MAGICAL" 
                 "Damage"   "%damage_per_second"
            } 
        }
    

    Cleave

    Inside a modifier. Keep in mind this will work on ranged, so you need to restrict it when applying this modifier if you need.

        "OnAttackLanded"
        {
            "CleaveAttack"
            {
                "CleavePercent" "10"
                "CleaveRadius"  "140"
                "CleaveEffect"  "particles/units/heroes/hero_sven/sven_spell_great_cleave.vpcf"
            }
        }
    

    Crit

    There is a MODIFIER_PROPERTY_PREATTACK_CRITICALSTRIKE Property but this doesn't include a chance, so you need to use a DataDriven Random when starting the attack, and applying a modifier that has the crit, removing it later OnAttackLanded.

    The first RemoveModifier is added to disable people from canceling attacks to get a guaranteed crit.

    "modifier_crit"
    {
        "Passive"   "1"
        "IsHidden"  "1"
        "OnAttackStart"
        {
            "RemoveModifier"
            {
                "ModifierName" "crit"
                "Target" "CASTER"
            }
            "Random"
            {
                "Chance" "%crit_chance"
                "OnSuccess"
                {
                    "ApplyModifier"
                    {
                        "ModifierName" "crit"
                        "Target"    "CASTER"    
                    }        
                }
            }
        }
    }
    
    "crit"
    {
        "IsHidden"  "1"
        "Properties"
        {
            "MODIFIER_PROPERTY_PREATTACK_CRITICALSTRIKE" "%crit_bonus"
        }
    
        "OnAttackLanded"
        {
            "RemoveModifier"
            {
                "ModifierName"  "crit"
                "Target"    "CASTER"    
            }
    
            // Basic blood particle effect
            "FireEffect"
            {
            "EffectName" "particles/units/heroes/hero_phantom_assassin/phantom_assassin_crit_impact.vpcf"
                "EffectAttachType"  "follow_origin"
                "Target"    "TARGET"
            }
        }
    }
    

    Orb: Slow and Lifesteal with custom projectile


    "modifier_orb_of_frost" { "Passive" "1" "IsHidden" "1" "Attributes" "MODIFIER_ATTRIBUTE_MULTIPLE" "Properties" { "MODIFIER_PROPERTY_BASEATTACK_BONUSDAMAGE" "6" } "Orb" { "Priority" "DOTA_ORB_PRIORITY_ABILITY" "ProjectileName" "particles\items2_fx\skadi_projectile.vpcf" } "OnOrbImpact" { "Lifesteal" { "Target" "ATTACKER" "LifestealPercent" "%bonus_lifesteal" } "ApplyModifier" { "Target" "TARGET" "ModifierName" "modifier_orb_of_frost_slow" "Duration" "%slow_duration" } } } "modifier_orb_of_frost_slow" { "IsDebuff" "1" "Duration" "3" "Properties" { "MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE" "%move_speed_slow" "MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT" "%attack_speed_slow" } "EffectName" "particles/generic_gameplay/generic_slowed_cold.vpcf" "EffectAttachType" "attach_hitloc" "Target" "TARGET" }

    Note: DataDriven Lifesteal might steal from things you don't want to steal from, it's better done through lua

    Block

    This is a tricky one. Note that there are 2 modifiers again.

    The first one has OnAttacked which randoms a block chance, OnSuccess it applies the block modifier, OnFailure it removes it. Inside the block_modifier, OnAttacked removes itself.

    The OnCreated is just so it's possible to block the 1st hit after equiping the shield.

    "shield_modifier"
    {
        "Passive" "1"
        "IsHidden" "1"
        "Properties"
        {
            "MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS" "%magic_resistance"
        }
        "OnCreated"
        {
            "Random"
            {
                "Chance" "%block_chance"
                "OnSuccess"
                {
                    "ApplyModifier"
                    {
                        "Target" "CASTER"
                        "ModifierName" "block_modifier"
                    }
                }
            }
        }
        "OnAttacked"
        {
            "Random"
            {
                "Chance" "%block_chance"
                "OnSuccess"
                {
                    "ApplyModifier"
                    {
                        "Target" "CASTER"
                        "ModifierName" "block_modifier"
                    }
                }
                "OnFailure"
                {
                    "RemoveModifier"
                    {
                        "Target" "CASTER"
                        "ModifierName" "block_modifier"
                    }
                }
            }
        }
    }
    
    "block_modifier"
    {
        "IsBuff" "1"
        "IsHidden" "1"
        "Properties"
        {
            "MODIFIER_PROPERTY_PHYSICAL_CONSTANT_BLOCK" "%damage_blocked"
        }
        "OnAttacked"
        {
            "RemoveModifier"
            {
                "Target" "CASTER"
                "ModifierName" "block_modifier"
            }
        }
    }
    
    
    • Follow Item Drop systems here

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

  • In the crit example, what stops a user from repeatedly starting attacks without landing and enabling a guaranteed crit?

  • Posts: 36

    That also works in dota 2

  • edited December 2014 Posts: 1,670

    what stops a user from repeatedly starting attacks without landing and enabling a guaranteed crit?

    That's why I've put a short Duration in addition to the OnAttackLanded, so that the user can't spam attack-stop without landing an attack and ensuring the crit on a different target. Not sure if there's a better way around it.

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

  • "modifier_crit"
            {
                "Passive"   "1"
                "IsHidden"  "0"
                "OnAttackStart"
                {
                    // Add this block
                    "RemoveModifier"
                    {
                        "ModifierName"      "crit"
                        "Target"            "CASTER"
                    }
                    "Random"
                    {
                        "Chance" "10"
                        "OnSuccess"
                        {
                            "ApplyModifier"
                            {
                                "ModifierName" "crit"
                                "Target"    "CASTER"    
                            }        
                        }
                    }
                }
            }
    
            "crit"
            {
                //"Duration"  "1"
                "IsHidden"  "0"
                "Properties"
                {
                    "MODIFIER_PROPERTY_PREATTACK_CRITICALSTRIKE" "300"
                }
    
                "OnAttackLanded"
                {
                    "RemoveModifier"
                    {
                        "ModifierName"  "crit"
                        "Target"    "CASTER"    
                    }
    
                    // Basic blood particle effect
                    "FireEffect"
                    {
                        "EffectName" "particles/units/heroes/hero_phantom_assassin/phantom_assassin_crit_impact.vpcf"
                        "EffectAttachType"  "follow_origin"
                        "Target"    "TARGET"
                    }
                }
            }
    

    If you are worried about people canceling attacks to get a guaranteed crit then you can just remove the modifier first every time an attack starts as shown in the modification above

    Also, from testing it seems that the duration of the crit modifier doesn't matter at all since even if the attack takes 5 years to land it will end up being a crit even though the modifier is long gone when the attack lands

    testing signature

  • Posts: 1,670

    Edited and added a Block example

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

  • DunDun
    Posts: 123

    Neat. How do you set maximum stack for stackable items? i.e A pot can have up to 5 stacks

  • Posts: 1,670

    According to what I've read in IslandTrollTribes2 Ongoing Issues, there's no easy datadriven way, but a workaround with lua would be going through every item for every player in a global Thinker doing item:GetCurrentCharges() and SetCurrentCharges() if required.

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

  • DunDun
    Posts: 123

    Does combining items without recipe also require lua workaround? Tried to mimic ring of basilius but I couldn't get it to work

  • Posts: 1,670

    I tested and adding "ItemCost" "0" to the recipe item will do it.

    Edited the main guide to reflect this.

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

  • edited December 2014 Posts: 1,670

    Added "InvalidHeroes" which allows for easy restrictions, along with a link to the scripts to extend Item Restrictions.

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

  • edited December 2014 Posts: 1,670

    Added "ItemAlertable" and "PingOverrideText" which allow to modify the Alt-Click texts for items.

    img

    Click here to jump to it

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

  • In the "Common Modifier Key Values for items" and "Basic Item Skeleton" sections, I think the key should be "Modifiers" not "Modifier" in your examples.

  • edited December 2014 Posts: 1,670

    Correct, made an awful typo on both, fixed now Thank you

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

  • What exactly does "ItemStockTime" do? The time when the Item comes into the shop or when its refilled?

  • @Noya How do you make an item drop on death (like a rapier or gem)? Is there a built in handle for it or do I have to do something like check the NPC's items on death, LaunchLoot a new instance of the droppable item etc?

  • Posts: 1,670

    @whitenitro0 There's no built-in property, but the item having an OnDeath -> RunScript that does caster:DropItemAtPositionImmediate(ability, caster:GetAbsOrigin()) should work

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

  • Posts: 13

    how do you configure whats in the recipe?

  • Posts: 1,670

    how do you configure whats in the recipe?

    With the ItemRequirements block

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