Created on by Noya

Ability KeyValues

DataDriven Ability

A DataDriven ability is a collection KeyValues. KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.

DataDriven abilities are defined inside scripts/npc/npc_abilities_custom.txt under a game addon folder.

This skeleton contains many keyvalues which will be expanded upon in this documentation.

"datadriven_skeleton"
{
// General
// ----------------------------------------------------------------------------------------
"BaseClass" "ability_datadriven"
"AbilityBehavior" "DOTA_ABILITY_BEHAVIOR_UNIT_TARGET"
"AbilityTextureName" "spellicon"
"AbilityUnitTargetTeam" "DOTA_UNIT_TARGET_TEAM_ENEMY"
"AbilityUnitTargetType" "DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_BASIC"
"AbilityUnitTargetFlags" "DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES"
"AbilityUnitDamageType" "DAMAGE_TYPE_MAGICAL"
"AbilityType" "DOTA_ABILITY_TYPE_BASIC"
"MaxLevel" "7"
"RequiredLevel" "-4"
"LevelsBetweenUpgrades" "7"
"AbilityCastPoint" "0.0"
"AbilityCastAnimation" "ACT_DOTA_ATTACK"
"AnimationPlaybackRate" "1"
"AnimationIgnoresModelScale" "1"
// Stats
//----------------------------------------------------------------------------------------
"AbilityDamage" "0 0 0 0"
"AbilityManaCost" "0 0 0 0"
"AbilityCooldown" "0.0 0.0 0.0 0.0"
"AbilityCastRange" "0"
"AbilityCastRangeBuffer" "250"
"AbilityChannelTime" "0.0 0.0 0.0 0.0"
"AbilityChannelledManaCostPerSecond" "30 35 40 45"
"AbilityDuration" "0.0 0.0 0.0 0.0"
"AoERadius" "250"
// ...
}

BaseClass

BaseClass can be any default dota ability name or "ability_datadriven", which allows the use of the entire data driven ability system.

Using a dota ability as the BaseClass can be done either as an override of the ability (goes in npc_abilities_override.txt) or just as a new ability in npc_abilities.custom.txt which inherits the exposed variables. This however doesn't let us change/add its internal structure, as that code is locked in C++ code.

Here we'll focus on everything that concerns writing custom abilities from scratch, using the "BaseClass" "ability_datadriven".

AbilityBehavior

This describes how the ability works, the general behavior to perform when it is executed.

You can use different behaviors together, separated by spaces and | pipes.

Example:

"DOTA_ABILITY_BEHAVIOR_CHANNELLED | DOTA_ABILITY_BEHAVIOR_NO_TARGET"

List of every possible AbilityBehavior

AbilityBehaviorDescription
DOTA_ABILITY_BEHAVIOR_NO_TARGETDoesn't need a target to be cast.
Ability fires off as soon as the button is pressed.
DOTA_ABILITY_BEHAVIOR_UNIT_TARGETNeeds a target to be cast on.
Requires AbilityUnitTargetTeam and AbilityUnitTargetType, see Targeting.
DOTA_ABILITY_BEHAVIOR_POINTCan 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_PASSIVECannot be cast.
DOTA_ABILITY_BEHAVIOR_CHANNELLEDChanneled ability.
If the user moves, or is silenced/stunned, the ability is interrupted.
DOTA_ABILITY_BEHAVIOR_TOGGLECan be toggled On/Off.
DOTA_ABILITY_BEHAVIOR_AURAAbility is an aura.
Not really used other than to tag the ability as such.
DOTA_ABILITY_BEHAVIOR_AUTOCASTCan be cast automatically.
Usually doesn't work by itself in anything that is not an ATTACK ability.
DOTA_ABILITY_BEHAVIOR_HIDDENCan't be cast, and won't show up on the HUD.
DOTA_ABILITY_BEHAVIOR_AOECan draw a radius where the ability will have effect.
Like POINT, but with an area of effect display.
Makes use of AOERadius.
DOTA_ABILITY_BEHAVIOR_NOT_LEARNABLECAnnot be learned by clicking on the HUD.
Example: Invoker's abilities.
DOTA_ABILITY_BEHAVIOR_ITEMAbility is tied to an item. There is no need to use this, the game will internally assign this behavior to any "item_datadriven".
DOTA_ABILITY_BEHAVIOR_DIRECTIONALHas a direction from the hero.
Examples: Mirana's Arrow, or Pudge's Hook.
DOTA_ABILITY_BEHAVIOR_IMMEDIATECan be used instantly, without going into the action queue.
DOTA_ABILITY_BEHAVIOR_NOASSISTAbility has no reticle assist. (?)
DOTA_ABILITY_BEHAVIOR_ATTACKIs an attack, and cannot hit attack-immune targets.
DOTA_ABILITY_BEHAVIOR_ROOT_DISABLESCannot be used when rooted.
DOTA_ABILITY_BEHAVIOR_UNRESTRICTEDAbility is allowed when commands are restricted.
Example: Lifestealer's Consume.
DOTA_ABILITY_BEHAVIOR_DONT_ALERT_TARGETDoes not alert enemies when target-cast on them.
Example: Spirit Breaker's Charge.
DOTA_ABILITY_BEHAVIOR_DONT_RESUME_MOVEMENTShould not resume movement when it completes.
Only applicable ot no-target, non-immediate abilities.
DOTA_ABILITY_BEHAVIOR_DONT_RESUME_ATTACKAbility 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_STOLENAbility still uses its normal cast point when stolen.
Examples: Meepo's Poof, Furion's Teleport.
DOTA_ABILITY_BEHAVIOR_IGNORE_BACKSWINGAbility ignores backswing pseudoqueue.
DOTA_ABILITY_BEHAVIOR_IGNORE_PSEUDO_QUEUECan be executed while stunned, casting, or force-attacking. Only applicable to toggled abilities.
Example: Morphling's Attribute Shift.
DOTA_ABILITY_BEHAVIOR_RUNE_TARGETTargets runes.
DOTA_ABILITY_BEHAVIOR_IGNORE_CHANNELDoesn't cancel abilities with _CHANNELED behavior.
DOTA_ABILITY_BEHAVIOR_OPTIONAL_UNIT_TARGETBottle and Wards.
DOTA_ABILITY_BEHAVIOR_OPTIONAL_NO_TARGET(?)

Behavior Tooltips

The following behaviors will generate a line in the ability tooltip. You want at least one of 1 behavior of this list. The rest of the ability behaviors don't have any UI support yet.

The UI can only show one behavior tooltip, but internally it will behave as expected, as long two contradicting keys are not used together (like NO_TARGET with UNIT_TARGET).

AbilityBehaviorABILITY: TooltipTakes precdence over:
DOTA_ABILITY_BEHAVIOR_NO_TARGETNo Target
DOTA_ABILITY_BEHAVIOR_UNIT_TARGETUnit TargetPOINT
DOTA_ABILITY_BEHAVIOR_POINTPoint Target
DOTA_ABILITY_BEHAVIOR_PASSIVEPassive
DOTA_ABILITY_BEHAVIOR_CHANNELLEDChanneledPOINT and UNIT
DOTA_ABILITY_BEHAVIOR_TOGGLETogglePOINT and UNIT
DOTA_ABILITY_BEHAVIOR_AURAAuraPASSIVE
DOTA_ABILITY_BEHAVIOR_AUTOCASTAuto-CastUNIT_TARGET

For example, an ability with

"AbilityBehavior" "DOTA_ABILITY_BEHAVIOR_UNIT_TARGET | DOTA_ABILITY_BEHAVIOR_CHANNELED"

will be shown like this:

img

AbilityType

Omitting this will default to DOTA_ABILITY_TYPE_BASIC.

AbilityTypeDescription
DOTA_ABILITY_TYPE_BASICNormal ability, learnable at level 1 and upgradeable every 2 levels.
DOTA_ABILITY_TYPE_ULTIMATE5 levels between upgrades, and requires level 6 to spend the first point on it.
Also tags the ability as ultimate for the HUD.
DOTA_ABILITY_TYPE_ATTRIBUTESUsed for attribute_bonus.
DOTA_ABILITY_TYPE_HIDDENWhat for?

Additionally, ability level intervals and limits can be directly changed with these keyvalues inside the ability block:

MaxLevel

The UI currently supports the following ability level displays: 1, 3, 4, and 7.

You can still use any integer value as MaxLevel, and it will assign the proper level values internally, but it will use a combination of these UI display numbers, then "start again" to another UI.

Example:

"MaxLevel" "10"

RequiredLevel

At which level the ability can first be learned. This takes negative values, to enable for skills to be skilled at any point, because the next value sets the levels between ranks of the ability, including the first one.

LevelsBetweenUpgrades

How many levels to wait to be able to learnt he next rank.

Example:

"MaxLevel" "7"
"RequiredLevel" "-4"
"LevelsBetweenUpgrades" "7"

Results in an ability that can be first skilled at levels 3/10/17/24/31/38/45.

Max level of the heroes can be changed using the Lua SetCustomHeroMaxLevel(MAX_LEVEL) API function.

AbilityTextureName

The icon file name that should be used in the UI for this ability. You can reutilize the icon from another just by putting that ability name here if desired. The internal name of every default dota ability can be found in: Built-In Ability Names.

To use your own icons, place them in resources/flash3/images/spellicons in you game addon folder, and just directly refer to the image name without the path or the extension.

Format: 128x128 PNG

"AbilityTextureName" "warchasers_buff"

img

Reject Self-Cast

Added in Reborn:

"CastFilterRejectCaster" "1"

Cast While Hidden

Added in Reborn:

"IsCastableWhileHidden" "1"

Targeting

3 key elements set the rules for target selection: Team, Type, and Flags.

Team

AbilityUnitTargetTeamDescription
DOTA_UNIT_TARGET_TEAM_BOTHAll
DOTA_UNIT_TARGET_TEAM_ENEMYEnemy
DOTA_UNIT_TARGET_TEAM_FRIENDLYAllied
DOTA_UNIT_TARGET_TEAM_NONEDefault value by omission.
DOTA_UNIT_TARGET_TEAM_CUSTOM(?)

Type

AbilityUnitTargetTypeTargets
DOTA_UNIT_TARGET_ALLEverything, including hidden entities.
DOTA_UNIT_TARGET_HEROnpc_dota_hero Heroes.
DOTA_NPC_UNIT_RELATIONSHIP_TYPE_HERO
DOTA_UNIT_TARGET_BASICBasic units, including summons.
DOTA_UNIT_TARGET_MECHANICALnpc_dota_creep_siege
DOTA_NPC_UNIT_RELATIONSHIP_TYPE_SIEGE
DOTA_UNIT_TARGET_BUILDINGnpc_dota_tower, npc_dota_building
DOTA_NPC_UNIT_RELATIONSHIP_TYPE_BUILDING
DOTA_UNIT_TARGET_TREEent_dota_tree
Examples: Tangos, Quelling Blade.
DOTA_UNIT_TARGET_CREEPnpc_dota_creature, npc_dota_creep
Same as BASIC, but might not include things like some summons.
Examples: Death Pact, Devour.
DOTA_UNIT_TARGET_COURIERnpc_dota_courier, npc_dota_flying_courier
DOTA_NPC_UNIT_RELATIONSHIP_TYPE_COURIER
DOTA_UNIT_TARGET_NONENothing!
DOTA_UNIT_TARGET_OTHEREverything not included in the previous types.
DOTA_UNIT_TARGET_CUSTOMNot exposed?
Examples: Replicate, Sunder, Demonic Conversion, Tether, Infest...

Flags

Flags allow targeting units that are ignored by default (for example, magic immune enemies,) or to ignore specific types of units that will otherwise be targetable (like Ancients, or magic immune allies.)

AbilityUnitTargetFlagsTargets / Ignores
DOTA_UNIT_TARGET_FLAG_NONEDefault value by omission.
DOTA_UNIT_TARGET_FLAG_DEADDead units, which are otherwise ignored.
DOTA_UNIT_TARGET_FLAG_MELEE_ONLYUnits with AttackCapabilities DOTA_UNIT_CAP_MELEE_ATTACK.
DOTA_UNIT_TARGET_FLAG_RANGED_ONLYUnits with AttackCapabilities DOTA_UNIT_CAP_RANGED_ATTACK.
DOTA_UNIT_TARGET_FLAG_MANA_ONLYUnits with mana, without "StatusMana" "0" in the npc_units file.
DOTA_UNIT_TARGET_FLAG_CHECK_DISABLE_HELPUnits with Disable Help on.
Not sure how to make a DataDriven ability use it?
DOTA_UNIT_TARGET_FLAG_NO_INVISIgnores invisible units (with MODIFIER_STATE_INVISIBLE.)
DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIESTargets ENEMY units with MODIFIER_STATE_MAGIC_IMMUNE.
Examples: Ensnare, Culling Blade, Primal Roar...
DOTA_UNIT_TARGET_FLAG_NOT_MAGIC_IMMUNE_ALLIESIgnores FRIENDLY units with MODIFIER_STATE_MAGIC_IMMUNE.
Example: Bane's Nightmare.
DOTA_UNIT_TARGET_FLAG_NOT_ATTACK_IMMUNEIgnores units with MODIFIER_STATE_ATTACK_IMMUNE.
DOTA_UNIT_TARGET_FLAG_FOW_VISIBLEBreaks when the unit goes into the fog of war.
Examples: Mana Drain, Life Drain.
DOTA_UNIT_TARGET_FLAG_INVULNERABLEUnits with MODIFIER_STATE_INVULNERABLE.
Examples: Assassinate, Recall, Boulder Smash...
DOTA_UNIT_TARGET_FLAG_NOT_ANCIENTSIgnores units with "IsAncient" "1" defined.
Example: Hand of Midas.
DOTA_UNIT_TARGET_FLAG_NOT_CREEP_HEROIgnores units with "ConsideredHero" "1" defined.
Examples: Astral Imprisonment, Disruption, Sunder.
DOTA_UNIT_TARGET_FLAG_NOT_DOMINATEDIgnores units with MODIFIER_STATE_DOMINATED.
DOTA_UNIT_TARGET_FLAG_NOT_ILLUSIONSIgnores untis with MODIFIER_PROPERTY_IS_ILLUSION.
DOTA_UNIT_TARGET_FLAG_NOT_NIGHTMAREDIgnores units with MODIFIER_STATE_NIGHTMARED.
DOTA_UNIT_TARGET_FLAG_NOT_SUMMONEDIgnores units created through the SpawnUnit action.
DOTA_UNIT_TARGET_FLAG_OUT_OF_WORLDUnits with MODIFIER_STATE_OUT_OF_GAME.
DOTA_UNIT_TARGET_FLAG_PLAYER_CONTROLLEDUnits controllable by a player, accesible with Lua's IsControllableByAnyPlayer().
DOTA_UNIT_TARGET_FLAG_PREFER_ENEMIESPrioritizes units over trees when both are selectable.

Clean list:

  • DOTA_UNIT_TARGET_FLAG_NONE
  • DOTA_UNIT_TARGET_FLAG_DEAD
  • DOTA_UNIT_TARGET_FLAG_MELEE_ONLY
  • DOTA_UNIT_TARGET_FLAG_RANGED_ONLY
  • DOTA_UNIT_TARGET_FLAG_MANA_ONLY
  • DOTA_UNIT_TARGET_FLAG_CHECK_DISABLE_HELP
  • DOTA_UNIT_TARGET_FLAG_NO_INVIS
  • DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES
  • DOTA_UNIT_TARGET_FLAG_NOT_MAGIC_IMMUNE_ALLIES
  • DOTA_UNIT_TARGET_FLAG_NOT_ATTACK_IMMUNE
  • DOTA_UNIT_TARGET_FLAG_FOW_VISIBLE
  • DOTA_UNIT_TARGET_FLAG_INVULNERABLE
  • DOTA_UNIT_TARGET_FLAG_NOT_ANCIENTS
  • DOTA_UNIT_TARGET_FLAG_NOT_CREEP_HERO
  • DOTA_UNIT_TARGET_FLAG_NOT_DOMINATED
  • DOTA_UNIT_TARGET_FLAG_NOT_ILLUSIONS
  • DOTA_UNIT_TARGET_FLAG_NOT_NIGHTMARED
  • DOTA_UNIT_TARGET_FLAG_NOT_SUMMONED
  • DOTA_UNIT_TARGET_FLAG_OUT_OF_WORLD
  • DOTA_UNIT_TARGET_FLAG_PLAYER_CONTROLLED
  • DOTA_UNIT_TARGET_FLAG_PREFER_ENEMIES

Fun with Flags

Flags were seen as AbilityUnitTargetFlags completions, but this is not their sole application.

The same applies to Team and Types.

  • "Flags" and "ExcludeFlags" in a "Target" block gives control over how to target units to apply actions on them later:
"Target"
{
"Center" "CASTER"
"Flags" "DOTA_UNIT_TARGET_FLAG_DEAD"
}
  • "TargetFlags" in a "LinearProjectile" action allows a LinearProjectile to ignore units that would otherwise be included by default in the Team+Type values, for example those with MODIFIER_STATE_INVISIBLE.
  • "Aura_Flags" in a modifier with the other "Aura" keys can be used, for example, to make an aura modifier only affect ranged units by adding DOTA_UNIT_TARGET_FLAG_RANGED_ONLY.

The same applies for Teams and Types.

Example: Targets all friendly units in a radius of the caster, including couriers, buildings, and siege units. Excludes heroes, summons, and other player controlled units.

"Target"
{
"Center" "CASTER"
"Radius" "%radius"
// AbilityUnitTargetTeam values.
"Teams" "DOTA_UNIT_TARGET_TEAM_FRIENDLY"
// AbilityUnitTargetTypes
"Types" "DOTA_UNIT_TARGET_ALL"
"ExcludeTypes" "DOTA_UNIT_TARGET_HERO"
// AbilityUnitTargetFlags
"Flags" "DOTA_UNIT_TARGET_FLAG_NOT_SUMMONED"
"ExcludeFlags" "DOTA_UNIT_TARGET_FLAG_PLAYER_CONTROLLED"
}

Example: Mirana's Arrow projectile rewrite that only hits heroes, including those that are magic immune:

"LinearProjectile"
{
"Target" "POINT"
"EffectName" "particles/units/heroes/hero_mirana/mirana_spell_arrow.vpcf"
"MoveSpeed" "857"
"StartRadius" "115"
"EndRadius" "115"
"StartPosition" "attach_attack1"
"FixedDistance" "3000"
"TargetTeams" "DOTA_UNIT_TARGET_TEAM_ENEMY"
"TargetTypes" "DOTA_UNIT_TARGET_HERO"
"TargetFlags" "DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES"
"HasFrontalCone" "0"
"ProvidesVision" "1"
"VisionRadius" "650"
}

With DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, and with DOTA_UNIT_TARGET_FLAG_NONE:

Other keyvalues of the Action Target block

Line

To target units in a line between the caster and the targeted point.

Instead of the "Radius" keyvalue, which only takes one parameter, Line takes Length and Thickness integer values in a block like this:

"Line"
{
"Length" "600"
"Thickness" "250"
}

Limiting the amount of targets

MaxTargets takes an integer value to limit the amount of targets the Target block will select.

"MaxTargets" "10"

Random also takes an integer to be as "take up to this number of units randomly."

"Random" "1"

(For more complex targeting, Lua scripting is the answer.)

ScriptSelectPoints

Its use is very rare, normally when the targeting is complex we would just use RunScript lua and do all the acitons inside the script.

ScriptSelectPoints
{
ScriptFile
Function
Radius
Count
}

A more in-depth explanation is needed to explain the complete usage of the Target block, as understanding the scope of the "Target" "TARGET" keyvalue is one of the most difficult things of the datadriven system.

Sources


If you have any content to expand or improve this documentation, please let me know.