Skip to main content
Glama

Calculate damage for one matchup

calculate_damage
Read-onlyIdempotent

Simulate one Pokémon attack end to end: provide attacker, defender, and move, plus optional field conditions, to receive every damage roll, KO chance, and computed stats for both sides.

Instructions

Simulate one attack end to end: one attacker set, one defender set, one named move, optionally under weather, terrain, game type, or side conditions. Use calculate_matchups when one attacker must be tested against several defenders, and calculate_stats for stat tables with no battle. field.weather takes Sand/Sun/Rain/Hail/Snow and field.terrain Electric/Grassy/Psychic/Misty; attackerSide/defenderSide take calc flags (isReflect, isLightScreen, isAuroraVeil, spikes 0-3, isSR), and set levels default to 100 here. Species and move names are validated first, so typos return an isError. Returns every damage roll, damageRange, koChance text, a description line, and both sets’ computed stats. Read-only and offline.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
moveYesMove used by the attacker, e.g. "Earthquake", "Make It Rain"; must be a real move name.
fieldNoBattlefield conditions applied to the calc; omit it for a neutral Singles field with no weather, terrain, or hazards.
attackerYesThe attacking Pokémon: species plus optional level, nature, IVs, EVs, item, ability, boosts, status, and current HP.
defenderYesThe defending Pokémon, same fields as `attacker`; its Defense/SpD, HP, typing, and ability drive the result.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
moveYesCanonical move name that was calculated, e.g. "Dragon Claw".
fieldYesThe battlefield the calc ran under, echoed back with its defaults filled in.
damageYesDamage dealt by the attack: a single number for a straight-damage move (0 when the defender is immune), a flat list of rolls for a move that rolls its own damage (e.g. False Swipe), or one roll list per hit for a multi-hit move (e.g. Population Bomb, Dragon Darts).
attackerYesThe attacking set as the calc resolved it, including the six stats it swung with.
defenderYesThe defending set as the calc resolved it, including the six stats it was hit on.
koChanceNoHuman-readable KO chance, e.g. "guaranteed OHKO" or "31.3% chance to 2HKO"; an empty string when no KO is possible (e.g. False Swipe), and absent when the calc could not describe the matchup at all, which is the immunity case.
damageRangeYes[minimum, maximum] damage: `calculate_damage` totals every roll (multi-hit moves are summed), while `calculate_matchups` reports the flattened per-hit rolls, so its bounds stay single-hit values. [0, 0] means nothing could be calculated.
descriptionYesOne-line summary of the whole matchup, e.g. "252 Atk Choice Band Garchomp Dragon Claw vs. 252 HP / 252+ Def Corviknight: 64-76 (16.4 - 19.5%) -- possible 6HKO"; an explicit 0-damage note when the calc could not describe it.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed16 schema fields changedv3.2.0
    • changedInput schema / properties / attacker / description
      Previous value: -"The attacking Pokémon: species plus optional level, nature, IVs, EVs, item, ability, boosts, status, Tera type, and current HP."New value: +"The attacking Pokémon: species plus optional level, nature, IVs, EVs, item, ability, boosts, status, and current HP."
    • removedInput schema / properties / attacker / properties / teraType
      Removed value: -{
      -  "description": "Tera type to use when the move is Terastallized, e.g. \"Fairy\".",
      -  "type": "string"
      -}
    • removedInput schema / properties / defender / properties / teraType
      Removed value: -{
      -  "description": "Tera type to use when the move is Terastallized, e.g. \"Fairy\".",
      -  "type": "string"
      -}
    • removedInput schema / properties / generation
      Removed value: -{
      -  "default": 9,
      -  "description": "Generation whose data to use, 1-9 (default 9). Earlier generations omit moves, items, abilities, and forms that did not exist yet.",
      -  "maximum": 9,
      -  "minimum": 1,
      -  "type": "integer"
      -}
    • changedOutput schema / properties / attacker / properties / boosts / description
      Previous value: -"Stat stages in effect for the calculation; all six keys are present with 0 for unboosted stats."New value: +"Stat stages in effect for the calculation; absent when none were supplied, since every omitted stage is 0."
    • changedOutput schema / properties / attacker / properties / evs / description
      Previous value: -"EVs the set was calculated with, keyed by stat id (hp, atk, def, spa, spd, spe) with stats left at 0 omitted; generations 1-2 fix all six at 252 when the call supplies none."New value: +"EVs the set was calculated with, keyed by stat id (hp, atk, def, spa, spd, spe) with stats left at 0 omitted."
    • changedOutput schema / properties / attacker / properties / ivs / description
      Previous value: -"IVs the set was calculated with; all six keys are present, defaulting to 31."New value: +"IVs the set was calculated with; present only when the call supplied a non-default one, since an all-31 spread is what every omitted IV gives."
    • removedOutput schema / properties / attacker / properties / teraType
      Removed value: -{
      -  "description": "Tera type echoed back when the call supplied one; absent otherwise.",
      -  "type": "string"
      -}
    • changedOutput schema / properties / attacker / required
      Previous value: -[
      -  "species",
      -  "level",
      -  "nature",
      -  "evs",
      -  "championsPoints",
      -  "ivs",
      -  "boosts",
      -  "stats"
      -]New value: +[
      +  "species",
      +  "level",
      +  "nature",
      +  "evs",
      +  "championsPoints",
      +  "stats"
      +]
    • changedOutput schema / properties / defender / properties / boosts / description
      Previous value: -"Stat stages in effect for the calculation; all six keys are present with 0 for unboosted stats."New value: +"Stat stages in effect for the calculation; absent when none were supplied, since every omitted stage is 0."
    • changedOutput schema / properties / defender / properties / evs / description
      Previous value: -"EVs the set was calculated with, keyed by stat id (hp, atk, def, spa, spd, spe) with stats left at 0 omitted; generations 1-2 fix all six at 252 when the call supplies none."New value: +"EVs the set was calculated with, keyed by stat id (hp, atk, def, spa, spd, spe) with stats left at 0 omitted."
    • changedOutput schema / properties / defender / properties / ivs / description
      Previous value: -"IVs the set was calculated with; all six keys are present, defaulting to 31."New value: +"IVs the set was calculated with; present only when the call supplied a non-default one, since an all-31 spread is what every omitted IV gives."
    • removedOutput schema / properties / defender / properties / teraType
      Removed value: -{
      -  "description": "Tera type echoed back when the call supplied one; absent otherwise.",
      -  "type": "string"
      -}
    • changedOutput schema / properties / defender / required
      Previous value: -[
      -  "species",
      -  "level",
      -  "nature",
      -  "evs",
      -  "championsPoints",
      -  "ivs",
      -  "boosts",
      -  "stats"
      -]New value: +[
      +  "species",
      +  "level",
      +  "nature",
      +  "evs",
      +  "championsPoints",
      +  "stats"
      +]
    • removedOutput schema / properties / generation
      Removed value: -{
      -  "description": "Generation whose data and mechanics were used, 1-9.",
      -  "maximum": 9007199254740991,
      -  "minimum": -9007199254740991,
      -  "type": "integer"
      -}
    • changedOutput schema / required
      Previous value: -[
      -  "generation",
      -  "attacker",
      -  "defender",
      -  "move",
      -  "field",
      -  "damage",
      -  "damageRange",
      -  "description"
      -]New value: +[
      +  "attacker",
      +  "defender",
      +  "move",
      +  "field",
      +  "damage",
      +  "damageRange",
      +  "description"
      +]
  2. Changed6 schema fields changedv2.0.2
    • addedInput schema / properties / attacker / properties / championsPoints
      Added value: +{
      +  "additionalProperties": {
      +    "type": "number"
      +  },
      +  "description": "Pokémon Champions stat points keyed by stat id (hp, atk, def, spa, spd, spe): whole numbers, each 0-32, totalling at most 66. This is the spread the game’s training screen takes, and an alternative to `evs` — give one or the other, not both. One point is worth 8 EVs, so a converted spread is trimmed from its largest stats to fit the 510 EV cap the calculator enforces.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • addedInput schema / properties / defender / properties / championsPoints
      Added value: +{
      +  "additionalProperties": {
      +    "type": "number"
      +  },
      +  "description": "Pokémon Champions stat points keyed by stat id (hp, atk, def, spa, spd, spe): whole numbers, each 0-32, totalling at most 66. This is the spread the game’s training screen takes, and an alternative to `evs` — give one or the other, not both. One point is worth 8 EVs, so a converted spread is trimmed from its largest stats to fit the 510 EV cap the calculator enforces.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / attacker / properties / championsPoints
      Added value: +{
      +  "additionalProperties": {
      +    "type": "number"
      +  },
      +  "description": "The spread as Pokémon Champions stat points (whole numbers, at most 32 in a stat, 66 total) — what the game’s training screen takes; stats left uninvested are omitted and a maxed stat reads 32. The two systems budget differently (510 EVs against 66 points), so a spread trimmed to fit the EV cap reads back a point or two under what was asked: this is the nearest point spread for the stats actually computed, not a copy of the input.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • changedOutput schema / properties / attacker / required
      Previous value: -[
      -  "species",
      -  "level",
      -  "nature",
      -  "evs",
      -  "ivs",
      -  "boosts",
      -  "stats"
      -]New value: +[
      +  "species",
      +  "level",
      +  "nature",
      +  "evs",
      +  "championsPoints",
      +  "ivs",
      +  "boosts",
      +  "stats"
      +]
    • addedOutput schema / properties / defender / properties / championsPoints
      Added value: +{
      +  "additionalProperties": {
      +    "type": "number"
      +  },
      +  "description": "The spread as Pokémon Champions stat points (whole numbers, at most 32 in a stat, 66 total) — what the game’s training screen takes; stats left uninvested are omitted and a maxed stat reads 32. The two systems budget differently (510 EVs against 66 points), so a spread trimmed to fit the EV cap reads back a point or two under what was asked: this is the nearest point spread for the stats actually computed, not a copy of the input.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • changedOutput schema / properties / defender / required
      Previous value: -[
      -  "species",
      -  "level",
      -  "nature",
      -  "evs",
      -  "ivs",
      -  "boosts",
      -  "stats"
      -]New value: +[
      +  "species",
      +  "level",
      +  "nature",
      +  "evs",
      +  "championsPoints",
      +  "ivs",
      +  "boosts",
      +  "stats"
      +]
  3. Changed3 schema fields changedv2.0.0
    • changedInput schema / properties / attacker / properties / moves / description
      Previous value: -"Moveset names, e.g. [\"Earthquake\", \"Dragon Claw\"]; used by `calc_matchups` to pick the hardest-hitting move per defender."New value: +"Moveset names, e.g. [\"Earthquake\", \"Dragon Claw\"]; used by `calculate_matchups` to pick the hardest-hitting move per defender."
    • changedInput schema / properties / defender / properties / moves / description
      Previous value: -"Moveset names, e.g. [\"Earthquake\", \"Dragon Claw\"]; used by `calc_matchups` to pick the hardest-hitting move per defender."New value: +"Moveset names, e.g. [\"Earthquake\", \"Dragon Claw\"]; used by `calculate_matchups` to pick the hardest-hitting move per defender."
    • changedOutput schema / properties / damageRange / description
      Previous value: -"[minimum, maximum] damage: `calculate_damage` totals every roll (multi-hit moves are summed), while `calc_matchups` reports the flattened per-hit rolls, so its bounds stay single-hit values. [0, 0] means nothing could be calculated."New value: +"[minimum, maximum] damage: `calculate_damage` totals every roll (multi-hit moves are summed), while `calculate_matchups` reports the flattened per-hit rolls, so its bounds stay single-hit values. [0, 0] means nothing could be calculated."
  4. Changed39 schema fields changedv1.1.1
    • addedInput schema / properties / attacker / description
      Added value: +"The attacking Pokémon: species plus optional level, nature, IVs, EVs, item, ability, boosts, status, Tera type, and current HP."
    • addedInput schema / properties / attacker / properties / ability / description
      Added value: +"Ability name, e.g. \"Intimidate\", \"Protosynthesis\"; defaults to the species’ default ability."
    • addedInput schema / properties / attacker / properties / abilityOn / description
      Added value: +"Force the ability on (true) or off (false), e.g. to compare Protosynthesis active vs not; omitted leaves it to the calc."
    • addedInput schema / properties / attacker / properties / boosts / description
      Added value: +"Stat stages keyed by stat id (hp, atk, def, spa, spd, spe), each -6..+6; omitted stats are 0 (e.g. { atk: 2 } = +2 Attack)."
    • addedInput schema / properties / attacker / properties / curHP / description
      Added value: +"Current HP when entering damaged, e.g. 120; defaults to full HP."
    • addedInput schema / properties / attacker / properties / evs / description
      Added value: +"EVs keyed by stat id (hp, atk, def, spa, spd, spe), each 0-252 in steps of 4; omitted stats are 0, and a total above 510 is rejected."
    • addedInput schema / properties / attacker / properties / isDynamaxed / description
      Added value: +"Treat this Pokémon as Dynamaxed (doubles HP and alters several moves)."
    • addedInput schema / properties / attacker / properties / item / description
      Added value: +"Held item name, e.g. \"Choice Band\", \"Assault Vest\", \"Leftovers\"; the calc applies its damage, Speed, or bulk effect."
    • addedInput schema / properties / attacker / properties / ivs / description
      Added value: +"IVs keyed by stat id (hp, atk, def, spa, spd, spe), each 0-31; omitted stats default to 31."
    • addedInput schema / properties / attacker / properties / level / description
      Added value: +"Level 1-100; defaults to 100 in the damage tools and 50 in the stat/speed tools."
    • addedInput schema / properties / attacker / properties / moves
      Added value: +{
      +  "description": "Moveset names, e.g. [\"Earthquake\", \"Dragon Claw\"]; used by `calc_matchups` to pick the hardest-hitting move per defender.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedInput schema / properties / attacker / properties / nature / description
      Added value: +"Nature name, e.g. \"Jolly\", \"Modest\", \"Adamant\"; defaults to Serious (neutral) when omitted."
    • addedInput schema / properties / attacker / properties / species / description
      Added value: +"Species or form name, e.g. \"Garchomp\", \"Ogerpon-Wellspring\"."
    • addedInput schema / properties / attacker / properties / status / description
      Added value: +"Pre-existing status such as \"brn\", \"par\", or \"tox\"; burn halves physical damage, paralysis cuts Speed."
    • addedInput schema / properties / attacker / properties / teraType / description
      Added value: +"Tera type to use when the move is Terastallized, e.g. \"Fairy\"."
    • addedInput schema / properties / defender / description
      Added value: +"The defending Pokémon, same fields as `attacker`; its Defense/SpD, HP, typing, and ability drive the result."
    • addedInput schema / properties / defender / properties / ability / description
      Added value: +"Ability name, e.g. \"Intimidate\", \"Protosynthesis\"; defaults to the species’ default ability."
    • addedInput schema / properties / defender / properties / abilityOn / description
      Added value: +"Force the ability on (true) or off (false), e.g. to compare Protosynthesis active vs not; omitted leaves it to the calc."
    • addedInput schema / properties / defender / properties / boosts / description
      Added value: +"Stat stages keyed by stat id (hp, atk, def, spa, spd, spe), each -6..+6; omitted stats are 0 (e.g. { atk: 2 } = +2 Attack)."
    • addedInput schema / properties / defender / properties / curHP / description
      Added value: +"Current HP when entering damaged, e.g. 120; defaults to full HP."
    • addedInput schema / properties / defender / properties / evs / description
      Added value: +"EVs keyed by stat id (hp, atk, def, spa, spd, spe), each 0-252 in steps of 4; omitted stats are 0, and a total above 510 is rejected."
    • addedInput schema / properties / defender / properties / isDynamaxed / description
      Added value: +"Treat this Pokémon as Dynamaxed (doubles HP and alters several moves)."
    • addedInput schema / properties / defender / properties / item / description
      Added value: +"Held item name, e.g. \"Choice Band\", \"Assault Vest\", \"Leftovers\"; the calc applies its damage, Speed, or bulk effect."
    • addedInput schema / properties / defender / properties / ivs / description
      Added value: +"IVs keyed by stat id (hp, atk, def, spa, spd, spe), each 0-31; omitted stats default to 31."
    • addedInput schema / properties / defender / properties / level / description
      Added value: +"Level 1-100; defaults to 100 in the damage tools and 50 in the stat/speed tools."
    • addedInput schema / properties / defender / properties / moves
      Added value: +{
      +  "description": "Moveset names, e.g. [\"Earthquake\", \"Dragon Claw\"]; used by `calc_matchups` to pick the hardest-hitting move per defender.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedInput schema / properties / defender / properties / nature / description
      Added value: +"Nature name, e.g. \"Jolly\", \"Modest\", \"Adamant\"; defaults to Serious (neutral) when omitted."
    • addedInput schema / properties / defender / properties / species / description
      Added value: +"Species or form name, e.g. \"Garchomp\", \"Ogerpon-Wellspring\"."
    • addedInput schema / properties / defender / properties / status / description
      Added value: +"Pre-existing status such as \"brn\", \"par\", or \"tox\"; burn halves physical damage, paralysis cuts Speed."
    • addedInput schema / properties / defender / properties / teraType / description
      Added value: +"Tera type to use when the move is Terastallized, e.g. \"Fairy\"."
    • addedInput schema / properties / field / description
      Added value: +"Battlefield conditions applied to the calc; omit it for a neutral Singles field with no weather, terrain, or hazards."
    • addedInput schema / properties / field / properties / attackerSide / description
      Added value: +"Attacker-side flags, e.g. { isHelpingHand: true, isTailwind: true, spikes: 2 }."
    • addedInput schema / properties / field / properties / defenderSide / description
      Added value: +"Defender-side flags, e.g. { isReflect: true, isLightScreen: true, isAuroraVeil: true, isSR: true }."
    • addedInput schema / properties / field / properties / gameType / description
      Added value: +"Doubles spreads damage across targets; default Singles."
    • addedInput schema / properties / field / properties / terrain / description
      Added value: +"Terrain: \"Electric\", \"Grassy\", \"Psychic\", or \"Misty\"; default none."
    • addedInput schema / properties / field / properties / weather / description
      Added value: +"Weather: \"Sand\", \"Sun\", \"Rain\", \"Hail\", \"Snow\", \"Harsh Sunshine\", \"Heavy Rain\", or \"Strong Winds\"; default none."
    • addedInput schema / properties / generation / description
      Added value: +"Generation whose data to use, 1-9 (default 9). Earlier generations omit moves, items, abilities, and forms that did not exist yet."
    • addedInput schema / properties / move / description
      Added value: +"Move used by the attacker, e.g. \"Earthquake\", \"Make It Rain\"; must be a real move name."
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "http://json-schema.org/draft-07/schema#",
      +  "additionalProperties": false,
      +  "properties": {
      +    "attacker": {
      +      "additionalProperties": false,
      +      "description": "The attacking set as the calc resolved it, including the six stats it swung with.",
      +      "properties": {
      +        "ability": {
      +          "description": "Ability used: the one supplied, else the species’ first ability; absent for a species with no abilities.",
      +          "type": "string"
      +        },
      +        "boosts": {
      +          "additionalProperties": false,
      +          "description": "Stat stages in effect for the calculation; all six keys are present with 0 for unboosted stats.",
      +          "properties": {
      +            "atk": {
      +              "description": "Stat stage for Attack: the stat behind physical damage dealt.",
      +              "type": "number"
      +            },
      +            "def": {
      +              "description": "Stat stage for Defense: the stat behind physical damage taken.",
      +              "type": "number"
      +            },
      +            "hp": {
      +              "description": "Stat stage for HP: hit points, which decide how much damage the set can take.",
      +              "type": "number"
      +            },
      +            "spa": {
      +              "description": "Stat stage for Special Attack: the stat behind special damage dealt.",
      +              "type": "number"
      +            },
      +            "spd": {
      +              "description": "Stat stage for Special Defense: the stat behind special damage taken.",
      +              "type": "number"
      +            },
      +            "spe": {
      +              "description": "Stat stage for Speed: turn order; the higher Speed moves first.",
      +              "type": "number"
      +            }
      +          },
      +          "required": [
      +            "hp",
      +            "atk",
      +            "def",
      +            "spa",
      +            "spd",
      +            "spe"
      +          ],
      +          "type": "object"
      +        },
      +        "evs": {
      +          "additionalProperties": {
      +            "type": "number"
      +          },
      +          "description": "EVs the set was calculated with, keyed by stat id (hp, atk, def, spa, spd, spe) with stats left at 0 omitted; generations 1-2 fix all six at 252 when the call supplies none.",
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "item": {
      +          "description": "Held item echoed back as supplied, e.g. \"Choice Band\", whose effect the calc applied; absent when the set carried none.",
      +          "type": "string"
      +        },
      +        "ivs": {
      +          "additionalProperties": false,
      +          "description": "IVs the set was calculated with; all six keys are present, defaulting to 31.",
      +          "properties": {
      +            "atk": {
      +              "description": "Individual value for Attack: the stat behind physical damage dealt.",
      +              "type": "number"
      +            },
      +            "def": {
      +              "description": "Individual value for Defense: the stat behind physical damage taken.",
      +              "type": "number"
      +            },
      +            "hp": {
      +              "description": "Individual value for HP: hit points, which decide how much damage the set can take.",
      +              "type": "number"
      +            },
      +            "spa": {
      +              "description": "Individual value for Special Attack: the stat behind special damage dealt.",
      +              "type": "number"
      +            },
      +            "spd": {
      +              "description": "Individual value for Special Defense: the stat behind special damage taken.",
      +              "type": "number"
      +            },
      +            "spe": {
      +              "description": "Individual value for Speed: turn order; the higher Speed moves first.",
      +              "type": "number"
      +            }
      +          },
      +          "required": [
      +            "hp",
      +            "atk",
      +            "def",
      +            "spa",
      +            "spd",
      +            "spe"
      +          ],
      +          "type": "object"
      +        },
      +        "level": {
      +          "description": "Level the set was calculated at; the damage tools default nested sets to level 100.",
      +          "maximum": 9007199254740991,
      +          "minimum": -9007199254740991,
      +          "type": "integer"
      +        },
      +        "nature": {
      +          "description": "Nature the stats were computed with, e.g. \"Jolly\"; Serious when the call omitted one.",
      +          "type": "string"
      +        },
      +        "species": {
      +          "description": "Canonical species name used in the calculation, e.g. \"Garchomp\".",
      +          "type": "string"
      +        },
      +        "stats": {
      +          "additionalProperties": false,
      +          "description": "The six stats of this set at its level, IVs, EVs, and nature; stat stages are applied inside the damage mechanics, so they are not folded in here.",
      +          "properties": {
      +            "atk": {
      +              "description": "Final Attack: the stat behind physical damage dealt.",
      +              "type": "number"
      +            },
      +            "def": {
      +              "description": "Final Defense: the stat behind physical damage taken.",
      +              "type": "number"
      +            },
      +            "hp": {
      +              "description": "Final HP: hit points, which decide how much damage the set can take.",
      +              "type": "number"
      +            },
      +            "spa": {
      +              "description": "Final Special Attack: the stat behind special damage dealt.",
      +              "type": "number"
      +            },
      +            "spd": {
      +              "description": "Final Special Defense: the stat behind special damage taken.",
      +              "type": "number"
      +            },
      +            "spe": {
      +              "description": "Final Speed: turn order; the higher Speed moves first.",
      +              "type": "number"
      +            }
      +          },
      +          "required": [
      +            "hp",
      +            "atk",
      +            "def",
      +            "spa",
      +            "spd",
      +            "spe"
      +          ],
      +          "type": "object"
      +        },
      +        "status": {
      +          "description": "Pre-existing status such as \"brn\", \"par\", or \"tox\"; absent when the set entered healthy.",
      +          "type": "string"
      +        },
      +        "teraType": {
      +          "description": "Tera type echoed back when the call supplied one; absent otherwise.",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "species",
      +        "level",
      +        "nature",
      +        "evs",
      +        "ivs",
      +        "boosts",
      +        "stats"
      +      ],
      +      "type": "object"
      +    },
      +    "damage": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "items": {
      +            "type": "number"
      +          },
      +          "type": "array"
      +        },
      +        {
      +          "items": {
      +            "items": {
      +              "type": "number"
      +            },
      +            "type": "array"
      +          },
      +          "type": "array"
      +        }
      +      ],
      +      "description": "Damage dealt by the attack: a single number for a straight-damage move (0 when the defender is immune), a flat list of rolls for a move that rolls its own damage (e.g. False Swipe), or one roll list per hit for a multi-hit move (e.g. Population Bomb, Dragon Darts)."
      +    },
      +    "damageRange": {
      +      "additionalItems": false,
      +      "description": "[minimum, maximum] damage: `calculate_damage` totals every roll (multi-hit moves are summed), while `calc_matchups` reports the flattened per-hit rolls, so its bounds stay single-hit values. [0, 0] means nothing could be calculated.",
      +      "items": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "number"
      +        }
      +      ],
      +      "maxItems": 2,
      +      "minItems": 2,
      +      "type": "array"
      +    },
      +    "defender": {
      +      "additionalProperties": false,
      +      "description": "The defending set as the calc resolved it, including the six stats it was hit on.",
      +      "properties": {
      +        "ability": {
      +          "description": "Ability used: the one supplied, else the species’ first ability; absent for a species with no abilities.",
      +          "type": "string"
      +        },
      +        "boosts": {
      +          "additionalProperties": false,
      +          "description": "Stat stages in effect for the calculation; all six keys are present with 0 for unboosted stats.",
      +          "properties": {
      +            "atk": {
      +              "description": "Stat stage for Attack: the stat behind physical damage dealt.",
      +              "type": "number"
      +            },
      +            "def": {
      +              "description": "Stat stage for Defense: the stat behind physical damage taken.",
      +              "type": "number"
      +            },
      +            "hp": {
      +              "description": "Stat stage for HP: hit points, which decide how much damage the set can take.",
      +              "type": "number"
      +            },
      +            "spa": {
      +              "description": "Stat stage for Special Attack: the stat behind special damage dealt.",
      +              "type": "number"
      +            },
      +            "spd": {
      +              "description": "Stat stage for Special Defense: the stat behind special damage taken.",
      +              "type": "number"
      +            },
      +            "spe": {
      +              "description": "Stat stage for Speed: turn order; the higher Speed moves first.",
      +              "type": "number"
      +            }
      +          },
      +          "required": [
      +            "hp",
      +            "atk",
      +            "def",
      +            "spa",
      +            "spd",
      +            "spe"
      +          ],
      +          "type": "object"
      +        },
      +        "evs": {
      +          "additionalProperties": {
      +            "type": "number"
      +          },
      +          "description": "EVs the set was calculated with, keyed by stat id (hp, atk, def, spa, spd, spe) with stats left at 0 omitted; generations 1-2 fix all six at 252 when the call supplies none.",
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "item": {
      +          "description": "Held item echoed back as supplied, e.g. \"Choice Band\", whose effect the calc applied; absent when the set carried none.",
      +          "type": "string"
      +        },
      +        "ivs": {
      +          "additionalProperties": false,
      +          "description": "IVs the set was calculated with; all six keys are present, defaulting to 31.",
      +          "properties": {
      +            "atk": {
      +              "description": "Individual value for Attack: the stat behind physical damage dealt.",
      +              "type": "number"
      +            },
      +            "def": {
      +              "description": "Individual value for Defense: the stat behind physical damage taken.",
      +              "type": "number"
      +            },
      +            "hp": {
      +              "description": "Individual value for HP: hit points, which decide how much damage the set can take.",
      +              "type": "number"
      +            },
      +            "spa": {
      +              "description": "Individual value for Special Attack: the stat behind special damage dealt.",
      +              "type": "number"
      +            },
      +            "spd": {
      +              "description": "Individual value for Special Defense: the stat behind special damage taken.",
      +              "type": "number"
      +            },
      +            "spe": {
      +              "description": "Individual value for Speed: turn order; the higher Speed moves first.",
      +              "type": "number"
      +            }
      +          },
      +          "required": [
      +            "hp",
      +            "atk",
      +            "def",
      +            "spa",
      +            "spd",
      +            "spe"
      +          ],
      +          "type": "object"
      +        },
      +        "level": {
      +          "description": "Level the set was calculated at; the damage tools default nested sets to level 100.",
      +          "maximum": 9007199254740991,
      +          "minimum": -9007199254740991,
      +          "type": "integer"
      +        },
      +        "nature": {
      +          "description": "Nature the stats were computed with, e.g. \"Jolly\"; Serious when the call omitted one.",
      +          "type": "string"
      +        },
      +        "species": {
      +          "description": "Canonical species name used in the calculation, e.g. \"Garchomp\".",
      +          "type": "string"
      +        },
      +        "stats": {
      +          "additionalProperties": false,
      +          "description": "The six stats of this set at its level, IVs, EVs, and nature; stat stages are applied inside the damage mechanics, so they are not folded in here.",
      +          "properties": {
      +            "atk": {
      +              "description": "Final Attack: the stat behind physical damage dealt.",
      +              "type": "number"
      +            },
      +            "def": {
      +              "description": "Final Defense: the stat behind physical damage taken.",
      +              "type": "number"
      +            },
      +            "hp": {
      +              "description": "Final HP: hit points, which decide how much damage the set can take.",
      +              "type": "number"
      +            },
      +            "spa": {
      +              "description": "Final Special Attack: the stat behind special damage dealt.",
      +              "type": "number"
      +            },
      +            "spd": {
      +              "description": "Final Special Defense: the stat behind special damage taken.",
      +              "type": "number"
      +            },
      +            "spe": {
      +              "description": "Final Speed: turn order; the higher Speed moves first.",
      +              "type": "number"
      +            }
      +          },
      +          "required": [
      +            "hp",
      +            "atk",
      +            "def",
      +            "spa",
      +            "spd",
      +            "spe"
      +          ],
      +          "type": "object"
      +        },
      +        "status": {
      +          "description": "Pre-existing status such as \"brn\", \"par\", or \"tox\"; absent when the set entered healthy.",
      +          "type": "string"
      +        },
      +        "teraType": {
      +          "description": "Tera type echoed back when the call supplied one; absent otherwise.",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "species",
      +        "level",
      +        "nature",
      +        "evs",
      +        "ivs",
      +        "boosts",
      +        "stats"
      +      ],
      +      "type": "object"
      +    },
      +    "description": {
      +      "description": "One-line summary of the whole matchup, e.g. \"252 Atk Choice Band Garchomp Dragon Claw vs. 252 HP / 252+ Def Corviknight: 64-76 (16.4 - 19.5%) -- possible 6HKO\"; an explicit 0-damage note when the calc could not describe it.",
      +      "type": "string"
      +    },
      +    "field": {
      +      "additionalProperties": false,
      +      "description": "The battlefield the calc ran under, echoed back with its defaults filled in.",
      +      "properties": {
      +        "gameType": {
      +          "description": "How many targets the move hit; \"Singles\" unless the call asked for Doubles.",
      +          "enum": [
      +            "Singles",
      +            "Doubles"
      +          ],
      +          "type": "string"
      +        },
      +        "terrain": {
      +          "description": "Terrain in effect, e.g. \"Electric\", \"Grassy\"; absent when the field had none.",
      +          "type": "string"
      +        },
      +        "weather": {
      +          "description": "Weather in effect, e.g. \"Sun\", \"Rain\", \"Sand\"; absent when the field had none.",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "gameType"
      +      ],
      +      "type": "object"
      +    },
      +    "generation": {
      +      "description": "Generation whose data and mechanics were used, 1-9.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "koChance": {
      +      "description": "Human-readable KO chance, e.g. \"guaranteed OHKO\" or \"31.3% chance to 2HKO\"; an empty string when no KO is possible (e.g. False Swipe), and absent when the calc could not describe the matchup at all, which is the immunity case.",
      +      "type": "string"
      +    },
      +    "move": {
      +      "description": "Canonical move name that was calculated, e.g. \"Dragon Claw\".",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "generation",
      +    "attacker",
      +    "defender",
      +    "move",
      +    "field",
      +    "damage",
      +    "damageRange",
      +    "description"
      +  ],
      +  "type": "object"
      +}
  5. First observedv0.1.0

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds useful behavioral context beyond that: name validation with isError on typos, level defaults, and the exact contents of the return value.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence adds value: what the tool does, when to use siblings, side-condition flag examples, validation behavior, output contents, and its read-only nature. It is front-loaded with the core action and does not waste words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with nested objects, required parameters, and an output schema, the description provides enough standalone context: inputs, defaults, sibling disambiguation, validation behavior, return contents, and safety. The structured schema and output schema fill the remaining mechanical details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already covers nearly all parameters, but the description adds meaning for side flags by listing isReflect, isLightScreen, isAuroraVeil, spikes 0-3, and isSR, which the schema does not enumerate. It also clarifies level default and the battlefield togls, going beyond the baseline schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Simulate one attack end to end' with one attacker, one defender, and one named move. It also distinguishes itself from calculate_matchups (one attacker vs many defenders) and calculate_stats (no battle), making tool selection unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly tells the agent when to use alternatives: use calculate_matchups when one attacker must be tested against several defenders, and calculate_stats for stat tables with no battle. It also gives defaults like level 100 and notes the optional field conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.