Abilities Data Driven
Most abilities in Dota 2 are defined by C++ code. When looking at these abilities, the npc_abilities.txt keyvalues file contains some ability metadata and exposes some tuning knobs, these are mostly metadata with all the actual behavior defined in code. The data driven ability system is a method to create custom abilities for Dota 2 and assign special properties and events to occur when they're used.
A Simple Example
Here is a very simple example ability. It's a passive that applies a visual effect to the unit with that ability.
"fx_test_ability" { // General //------------------------------------------------------------------------------------------------------------- "BaseClass" "ability_datadriven" "AbilityBehavior" "DOTA_ABILITY_BEHAVIOR_PASSIVE" "AbilityTextureName" "axe_battle_hunger" // Modifiers //------------------------------------------------------------------------------------------------------------- "Modifiers" { "fx_test_modifier" { "Passive" "1" "OnCreated" { "AttachEffect" { "Target" "CASTER" "EffectName" "generic_buff_1" "EffectAttachType" "follow_overhead" "EffectLifeDurationScale" "1" "EffectColorA" "255 255 0" } } } } }
The "BaseClass", "AbilityBehavior" and "AbilityTextureName" keys are common to all abilities:
"BaseClass" - Normally DOTA chooses the C++ class to connect to an ability by looking at the ability name (in this case "fx_test_ability"). If you'd like to force DOTA to use a different C++ class, the "BaseClass" key will do that - in this example we're using the ability_datadriven class to connect to the data driven ability system. It's possible to use this key to connect to any other existing ability code to make a new variant of an old ability, with different settings for whatever that ability exposes to keyvalues.
"ID" - ID is a unique number for stats tracking. This is not used for data driven abilities.
"AbilityBehavior" is a set of flags describing some properties of the ability. You can put flags in here separated by spaces and | for example "DOTA_ABILITY_BEHAVIOR_HIDDEN | DOTA_ABILITY_BEHAVIOR_NO_TARGET" - the spaces are important!
DOTA_ABILITY_BEHAVIOR_HIDDEN = 1 << 0, //This ability can be owned by a unit but can't be casted and wont show up on the HUD. DOTA_ABILITY_BEHAVIOR_PASSIVE = 1 << 1, //Can't be casted like above but this one shows up on the ability HUD DOTA_ABILITY_BEHAVIOR_NO_TARGET = 1 << 2, //Doesn't need a target to be cast, ability fires off as soon as the button is pressed DOTA_ABILITY_BEHAVIOR_UNIT_TARGET = 1 << 3, //Ability needs a target to be casted on. DOTA_ABILITY_BEHAVIOR_POINT = 1 << 4, //Ability can be cast anywhere the mouse cursor is (If a unit is clicked it will just be cast where the unit was standing) DOTA_ABILITY_BEHAVIOR_AOE = 1 << 5, //This ability draws a radius where the ability will have effect. Kinda like POINT but with a an area of effect display. DOTA_ABILITY_BEHAVIOR_NOT_LEARNABLE = 1 << 6, //This ability probably can be casted or have a casting scheme but cannot be learned (these are usually abilities that are temporary like techie's bomb detonate) DOTA_ABILITY_BEHAVIOR_CHANNELLED = 1 << 7, //This ability is channeled. If the user moves or is silenced the ability is interrupted. DOTA_ABILITY_BEHAVIOR_ITEM = 1 << 8, //This ability is tied up to an item. DOTA_ABILITY_BEHAVIOR_TOGGLE = 1 << 9, //This ability can be insta-toggled DOTA_ABILITY_BEHAVIOR_DIRECTIONAL = 1 << 10, //This ability has a direction from the hero, such as miranas arrow or pudge's hook DOTA_ABILITY_BEHAVIOR_IMMEDIATE = 1 << 11, //This ability can be used instantly without going into the action queue DOTA_ABILITY_BEHAVIOR_AUTOCAST = 1 << 12, //This ability can be casted automatically DOTA_ABILITY_BEHAVIOR_NOASSIST = 1 << 13, //This ability has no reticle assist DOTA_ABILITY_BEHAVIOR_AURA = 1 << 14, //This ability is an aura. We don't really use this other than to tag the ability as so DOTA_ABILITY_BEHAVIOR_ATTACK = 1 << 15, //This ability is an attack and cannot hit attack-immune targets DOTA_ABILITY_BEHAVIOR_DONT_RESUME_MOVEMENT = 1 << 16, //This ability should not resume movement when it completes. Only applicable to no-target, non-immediate abilities. DOTA_ABILITY_BEHAVIOR_ROOT_DISABLES = 1 << 17, //This ability cannot be used when rooted DOTA_ABILITY_BEHAVIOR_UNRESTRICTED = 1 << 18, //This ability is allowed when commands are restricted DOTA_ABILITY_BEHAVIOR_IGNORE_PSEUDO_QUEUE = 1 << 19, //This ability can be executed while stunned, casting, or force-attacking. Only applicable to toggled abilities. DOTA_ABILITY_BEHAVIOR_IGNORE_CHANNEL = 1 << 20, //This ability can be executed without interrupting channels DOTA_ABILITY_BEHAVIOR_DONT_CANCEL_MOVEMENT = 1 << 21, //This ability doesn't cause certain modifiers to end, used for courier and speed burst DOTA_ABILITY_BEHAVIOR_DONT_ALERT_TARGET = 1 << 22, //This ability does not alert enemies when target-cast on them DOTA_ABILITY_BEHAVIOR_DONT_RESUME_ATTACK = 1 << 23, //This ability should not resume command-attacking the previous target when it completes. Only applicable to no-target, non-immediate abilities and unit-target abilities. DOTA_ABILITY_BEHAVIOR_NORMAL_WHEN_STOLEN = 1 << 24, //This ability still uses its normal cast point when stolen. DOTA_ABILITY_BEHAVIOR_IGNORE_BACKSWING = 1 << 25, //This ability ignores backswing psuedoqueue DOTA_ABILITY_BEHAVIOR_RUNE_TARGET = 1 << 26, //TArgets Runes
"AbilityTextureName" is the icon that should be used in the UI for this ability. You can use this to borrow the icon from another ability just by putting that ability name here.
"Modifiers" is unique to data-driven abilities. This block describes a set of modifiers (a.k.a. Buffs) that are unique to this ability. Each modifier is named by the name of the keyvalues block that defines the modifier.
"Passive" in a modifier flags the modifier as a passive modifier that should automatically be applied to the ability owner.
"OnCreated" is an action block that is triggered when the ability is first attached to the owner. In this example, we attach a visual effect to the ability caster.
Ability Events and Actions
Abilities have various in-game events which can trigger behaviour. The events that can trigger actions on an ability are:
"OnToggleOn" "OnToggleOff" "OnSpellStart" "OnOwnerDied" "OnOwnerSpawned" "OnProjectileHit" "OnChannelSucceeded" "OnChannelFinish" "OnChannelInterrupted"
Each of these keys is a block that contains one or more action descriptions. The actions you can use are:
"ApplyModifier"
"Target" and "ModifierName".
"AttachEffect"
"EffectName", "EffectAttachType" and control point data.
"Blink"
"Target" (position to blink to)
"Random"
"Chance", "PseudoRandom", "OnSuccess" and "OnFailure"
"CreateThinker"
"Target" and "ModifierName"
"Damage"
"Target", "Type" and "MinDamage"/"MaxDamage" or "Damage"
"FireEffect"
"EffectName", "EffectAttachType" and control point data.
"FireSound"
"EffectName"
"Lifesteal"
"Target" and "LifestealPercent"
"RemoveModifier"
"Target" and "ModifierName"
"LinearProjectile"
"EffectName", "MoveSpeed", "StartRadius", "EndRadius", "TargetTeams", "TargetTypes", "TargetFlags", "HasFrontalCone".
"TrackingProjectile"
"EffectName", "Dodgeable", "ProvidesVision", "VisionRadius", "MoveSpeed", "SourceAttachment"
"SpawnUnit"
"UnitName", "UnitCount", "SpawnRadius"
"AddAbility"
"Target", "AbilityName"
"RemoveAbility"
"Target", "AbilityName"
"DestroyTrees"
"Target"

AddAbility
adds a new ability at level 0. RemoveAbility
deletes the ability even if it has been leveled. More complex ability management should be done through script as opposed to the data driven system.Action Targets
Target selection for actions exposes some choices. A "Target" key can have a value of "CASTER", "TARGET", "ATTACKER" or "UNIT" for simple single-target selection. These names mean different things in different events - experiment to discover exactly what in each case.
For selecting multiple targets in an area, make the "Target" key a block with the following subkeys:
"Center" - "CASTER", "TARGET", "ATTACKER", "UNIT" "Radius" - The radius to search for target in. "Teams" - Bit field or'ed of DOTA_UNIT_TARGET_TEAM_FRIENDLY DOTA_UNIT_TARGET_TEAM_ENEMY DOTA_UNIT_TARGET_TEAM_CUSTOM DOTA_UNIT_TARGET_TEAM_BOTH "Types" - Bit field or'ed of DOTA_UNIT_TARGET_HERO DOTA_UNIT_TARGET_CREEP DOTA_UNIT_TARGET_BUILDING DOTA_UNIT_TARGET_MECHANICAL DOTA_UNIT_TARGET_COURIER DOTA_UNIT_TARGET_OTHER DOTA_UNIT_TARGET_TREE DOTA_UNIT_TARGET_CUSTOM DOTA_UNIT_TARGET_BASIC DOTA_UNIT_TARGET_ALL "ExcludeTypes" - As the above, but reject any of the flagged types. "Flags" - Bit field or'ed of DOTA_UNIT_TARGET_FLAG_RANGED_ONLY DOTA_UNIT_TARGET_FLAG_MELEE_ONLY DOTA_UNIT_TARGET_FLAG_DEAD DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES DOTA_UNIT_TARGET_FLAG_NOT_MAGIC_IMMUNE_ALLIES DOTA_UNIT_TARGET_FLAG_INVULNERABLE DOTA_UNIT_TARGET_FLAG_FOW_VISIBLE DOTA_UNIT_TARGET_FLAG_NO_INVIS DOTA_UNIT_TARGET_FLAG_NOT_ANCIENTS DOTA_UNIT_TARGET_FLAG_PLAYER_CONTROLLED DOTA_UNIT_TARGET_FLAG_NOT_DOMINATED DOTA_UNIT_TARGET_FLAG_NOT_SUMMONED DOTA_UNIT_TARGET_FLAG_NOT_ILLUSIONS DOTA_UNIT_TARGET_FLAG_NOT_ATTACK_IMMUNE DOTA_UNIT_TARGET_FLAG_MANA_ONLY DOTA_UNIT_TARGET_FLAG_CHECK_DISABLE_HELP DOTA_UNIT_TARGET_FLAG_NOT_CREEP_HERO DOTA_UNIT_TARGET_FLAG_OUT_OF_WORLD DOTA_UNIT_TARGET_FLAG_NOT_NIGHTMARED "ExcludeFlags" - As the above, but reject any of the flagged states.
Modifier Properties
Modifier properties are gameplay values a modifier can change on the unit it is applied to. Here's a simple example of a modifier that slows attacks and movement speed (this chunk is a block inside the "Modifiers" block of an ability). To specify numeric values, you can put in a number or you can use %name formatting to grab values out of the AbilitySpecial block of the Ability. The advantage to using the %name syntax is that the value can change as the ability levels up and the numeric value can be formatted into tooltips. In this example, the slow duration comes from an AbilitySpecial block, but the slow values are just numbers.
"creature_slithereen_crush_slow" { "Duration" "%slow_duration" "Properties" { "MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE" "-20" "MODIFIER_PROPERTY_ATTACKSPEED_BONUS_PERCENTAGE" "-20" } }
Here is a list of the properties you can put in a modifier:
MODIFIER_PROPERTY_PREATTACK_BONUS_DAMAGE MODIFIER_PROPERTY_BASEATTACK_BONUSDAMAGE MODIFIER_PROPERTY_PERSISTENT_INVISIBILITY MODIFIER_PROPERTY_MOVESPEED_BONUS_CONSTANT MODIFIER_PROPERTY_MOVESPEED_BASE_OVERRIDE MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE_UNIQUE MODIFIER_PROPERTY_MOVESPEED_BONUS_UNIQUE MODIFIER_PROPERTY_MOVESPEED_ABSOLUTE MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT_SECONDARY MODIFIER_PROPERTY_BASE_ATTACK_TIME_CONSTANT MODIFIER_PROPERTY_DAMAGEOUTGOING_PERCENTAGE MODIFIER_PROPERTY_DAMAGEOUTGOING_PERCENTAGE_ILLUSION MODIFIER_PROPERTY_BASEDAMAGEOUTGOING_PERCENTAGE MODIFIER_PROPERTY_INCOMING_DAMAGE_PERCENTAGE MODIFIER_PROPERTY_INCOMING_PHYSICAL_DAMAGE_PERCENTAGE MODIFIER_PROPERTY_INCOMING_SPELL_DAMAGE_CONSTANT MODIFIER_PROPERTY_EVASION_CONSTANT MODIFIER_PROPERTY_AVOID_DAMAGE MODIFIER_PROPERTY_AVOID_SPELL MODIFIER_PROPERTY_MISS_PERCENTAGE MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS_ILLUSIONS MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS_UNIQUE MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS_UNIQUE_ACTIVE MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS MODIFIER_PROPERTY_MAGICAL_RESISTANCE_ITEM_UNIQUE MODIFIER_PROPERTY_MAGICAL_RESISTANCE_DECREPIFY_UNIQUE MODIFIER_PROPERTY_BASE_MANA_REGEN MODIFIER_PROPERTY_MANA_REGEN_CONSTANT MODIFIER_PROPERTY_MANA_REGEN_CONSTANT_UNIQUE MODIFIER_PROPERTY_MANA_REGEN_PERCENTAGE MODIFIER_PROPERTY_MANA_REGEN_TOTAL_PERCENTAGE MODIFIER_PROPERTY_HEALTH_REGEN_CONSTANT MODIFIER_PROPERTY_HEALTH_REGEN_PERCENTAGE MODIFIER_PROPERTY_HEALTH_BONUS MODIFIER_PROPERTY_MANA_BONUS MODIFIER_PROPERTY_STATS_STRENGTH_BONUS MODIFIER_PROPERTY_STATS_AGILITY_BONUS MODIFIER_PROPERTY_STATS_INTELLECT_BONUS MODIFIER_PROPERTY_ATTACK_RANGE_BONUS MODIFIER_PROPERTY_RESPAWNTIME MODIFIER_PROPERTY_DEATHGOLDCOST MODIFIER_PROPERTY_PREATTACK_CRITICALSTRIKE MODIFIER_PROPERTY_PHYSICAL_CONSTANT_BLOCK MODIFIER_PROPERTY_TOTAL_CONSTANT_BLOCK_UNAVOIDABLE_PRE_ARMOR MODIFIER_PROPERTY_TOTAL_CONSTANT_BLOCK MODIFIER_PROPERTY_OVERRIDE_ANIMATION MODIFIER_PROPERTY_OVERRIDE_ANIMATION_WEIGHT MODIFIER_PROPERTY_OVERRIDE_ANIMATION_RATE MODIFIER_PROPERTY_DISABLE_AUTOATTACK MODIFIER_PROPERTY_BONUS_DAY_VISION MODIFIER_PROPERTY_BONUS_NIGHT_VISION MODIFIER_PROPERTY_MIN_HEALTH MODIFIER_PROPERTY_ABSOLUTE_NO_DAMAGE_PHYSICAL MODIFIER_PROPERTY_ABSOLUTE_NO_DAMAGE_MAGICAL MODIFIER_PROPERTY_ABSOLUTE_NO_DAMAGE_PURE MODIFIER_PROPERTY_IS_ILLUSION MODIFIER_PROPERTY_TURN_RATE_PERCENTAGE MODIFIER_PROPERTY_DISABLE_HEALING
Modifier States
States are very similar to properties, except they are tri-state values. A state can have the value "MODIFIER_STATE_VALUE_NO_ACTION", "MODIFIER_STATE_VALUE_ENABLED" or "MODIFIER_STATE_VALUE_DISABLED". This example modifier attaches a simple stunned effect, overrides the base unit's animation and forces the unit into the stunned state:
"creature_bash_ministun" { "Duration" "%duration" "EffectName" "generic_stunned" "EffectAttachType" "follow_overhead" "Duration" "%stun_duration" "OverrideAnimation" "ACT_DOTA_DISABLED" "States" { "MODIFIER_STATE_STUNNED" "MODIFIER_STATE_VALUE_ENABLED" } }
Here is a list of all the states available to a modifier:
MODIFIER_STATE_ROOTED MODIFIER_STATE_SOFT_DISARMED MODIFIER_STATE_DISARMED MODIFIER_STATE_ATTACK_IMMUNE MODIFIER_STATE_SILENCED MODIFIER_STATE_MUTED MODIFIER_STATE_STUNNED MODIFIER_STATE_HEXED MODIFIER_STATE_INVISIBLE MODIFIER_STATE_INVULNERABLE MODIFIER_STATE_MAGIC_IMMUNE MODIFIER_STATE_PROVIDES_VISION MODIFIER_STATE_NIGHTMARED MODIFIER_STATE_BLOCK_DISABLED MODIFIER_STATE_EVADE_DISABLED MODIFIER_STATE_UNSELECTABLE MODIFIER_STATE_CANNOT_MISS MODIFIER_STATE_SPECIALLY_DENIABLE MODIFIER_STATE_FROZEN MODIFIER_STATE_COMMAND_RESTRICTED MODIFIER_STATE_NOT_ON_MINIMAP MODIFIER_STATE_NOT_ON_MINIMAP_FOR_ENEMIES MODIFIER_STATE_LOW_ATTACK_PRIORITY MODIFIER_STATE_NO_HEALTH_BAR MODIFIER_STATE_FLYING MODIFIER_STATE_NO_UNIT_COLLISION MODIFIER_STATE_NO_TEAM_MOVE_TO MODIFIER_STATE_NO_TEAM_SELECT MODIFIER_STATE_PASSIVES_DISABLED MODIFIER_STATE_DOMINATED MODIFIER_STATE_BLIND MODIFIER_STATE_OUT_OF_GAME
Modifier Events
Modifiers can also describe actions that should happen on various in-game events. Each of these keys is a block that describes actions - the action description system is documented elsewhere on this page. The events that are supported are:
OnCreated - The modifier has been created. OnAttacked - The unit this modifier is attached to has been attacked. OnAttackLanded - The unit this modifier is attached to has landed an attack on a target. OnDestroy - The modifier has been removed.
A More Complex Example
Here is an ability that waits for the owner to die. On death, a thinker is created with an acid pool visual effect and an aura modifier which reduces armor and applies a damage over time effect.
//================================================================================================================= // Creature: Acid Spray //================================================================================================================= "creature_acid_spray" { // General //------------------------------------------------------------------------------------------------------------- "BaseClass" "ability_datadriven" "AbilityBehavior" "DOTA_ABILITY_BEHAVIOR_AOE" "AbilityUnitDamageType" "DAMAGE_TYPE_COMPOSITE" "AbilityTextureName" "alchemist_acid_spray" // Casting //------------------------------------------------------------------------------------------------------------- "AbilityCastPoint" "0.2" "AbilityCastRange" "900" "OnOwnerDied" { "CreateThinker" { "ModifierName" "creature_acid_spray_thinker" "Target" "CASTER" } } "Modifiers" { "creature_acid_spray_thinker" { "Aura" "create_acid_spray_armor_reduction_aura" "Aura_Radius" "%radius" "Aura_Teams" "DOTA_UNIT_TARGET_TEAM_ENEMY" "Aura_Types" "DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_CREEP | DOTA_UNIT_TARGET_MECHANICAL" "Aura_Flags" "DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES" "Duration" "%duration" "OnCreated" { "AttachEffect" { "EffectName" "alchemist_acid_spray" "EffectAttachType" "follow_origin" "Target" "TARGET" "ControlPoints" { "00" "0 0 0" "01" "%radius 1 1" } } } } "create_acid_spray_armor_reduction_aura" { "IsDebuff" "1" "IsPurgable" "0" "EffectName" "alchemist_acid_spray_debuff" "ThinkInterval" "%tick_rate" "OnIntervalThink" { "Damage" { "Type" "DAMAGE_TYPE_COMPOSITE" "Damage" "%damage" "Target" "TARGET" } } "Properties" { "MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS" "%armor_reduction" } } } // Special //------------------------------------------------------------------------------------------------------------- "AbilitySpecial" { "01" { "var_type" "FIELD_INTEGER" "radius" "250" } "02" { "var_type" "FIELD_FLOAT" "duration" "16.0" } "03" { "var_type" "FIELD_INTEGER" "damage" "118 128 138 158" } "04" { "var_type" "FIELD_INTEGER" "armor_reduction" "-3 -4 -5 -6" } "05" { "var_type" "FIELD_FLOAT" "tick_rate" "1.0" } } }