{
  "schemaVersion": 1,
  "slug": "pokemon-damage-calculator",
  "category": "gaming",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "400bdc5102b9f31698387e846e05bbd28a97c6524773823c52cbef90bc7171da",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/pokemon-damage-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "Dmg = ⌊((2L ÷ 5 + 2) × P × Atk ÷ Def ÷ 50 + 2) × m × r⌋",
    "vars": [
      [
        "Dmg",
        "Damage"
      ],
      [
        "L",
        "Level (1–100)"
      ],
      [
        "P",
        "Move power"
      ],
      [
        "Atk",
        "Attack stat"
      ],
      [
        "Def",
        "Defense stat"
      ],
      [
        "m",
        "Modifier: STAB × type"
      ]
    ],
    "note": "r = 0.85–1 random roll; min and max floored separately; m = 1 or 1.5 × effectiveness; average = (min + max) ÷ 2."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-12",
    "sources": [
      {
        "name": "Smogon damage-calc — generation-aware reference calculator",
        "url": "https://github.com/smogon/damage-calc/blob/master/README.md"
      }
    ],
    "basis": "This is a simplified single-hit scenario, not a generation-specific battle engine. It uses the entered stats, STAB and type multiplier with a 0.85–1 damage factor; it omits intermediate rounding, critical hits, abilities, items, weather and stat stages. A knockout is guaranteed only when the minimum modeled damage reaches the target HP; if only the maximum reaches it, a knockout is possible, not guaranteed.",
    "limitations": "A knockout is guaranteed only when the minimum modeled damage reaches the target HP; if only the maximum reaches it, a knockout is possible, not guaranteed.",
    "implementationHash": "400bdc5102b9f31698387e846e05bbd28a97c6524773823c52cbef90bc7171da",
    "domain": "digital"
  },
  "contract": {
    "compute": "if (![level,power,attack,defense,effectiveness,targetHP].every(Number.isFinite) || !Number.isInteger(level) || level<1 || level>100 || power<=0 || attack<=0 || defense<=0 || targetHP<=0 || ![0,0.25,0.5,1,2,4].includes(effectiveness) || !['yes','no'].includes(stab)) return {minDamage:null,maxDamage:null,averageDamage:null,percentHP:null,stabMultiplier:null,effectivenessMultiplier:null,knockOut:null,__error:'inputError'}; const lv = Math.max(1, Math.min(100, Math.round(level))); const base = (2*lv/5 + 2)*power*attack/defense/50 + 2; const mods = (stab === 'yes' ? 1.5 : 1)*effectiveness; const min = Math.floor(base*0.85*mods); const max = Math.floor(base*mods); return { minDamage: min, maxDamage: max, averageDamage: (min + max)/2, percentHP: targetHP > 0 ? (min + max)/2/targetHP*100 : 0, stabMultiplier: stab === 'yes' ? 1.5 : 1, effectivenessMultiplier: effectiveness, knockOut: min >= targetHP ? 'Guaranteed knockout' : max >= targetHP ? 'Knockout possible at a high roll' : 'No knockout in one hit' };",
    "inputs": [
      {
        "name": "level",
        "type": "number",
        "default": 50,
        "min": 1,
        "max": 100,
        "step": 1,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "name": "power",
        "type": "number",
        "default": 80,
        "min": 0,
        "max": 250,
        "step": 1,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "name": "attack",
        "type": "number",
        "default": 120,
        "min": 1,
        "max": 999,
        "step": 1,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "name": "defense",
        "type": "number",
        "default": 100,
        "min": 1,
        "max": 999,
        "step": 1,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "name": "stab",
        "type": "select",
        "default": "yes",
        "options": [
          {
            "value": "yes"
          },
          {
            "value": "no"
          }
        ]
      },
      {
        "name": "effectiveness",
        "type": "select",
        "default": 1,
        "options": [
          {
            "value": 0
          },
          {
            "value": 0.25
          },
          {
            "value": 0.5
          },
          {
            "value": 1
          },
          {
            "value": 2
          },
          {
            "value": 4
          }
        ]
      },
      {
        "name": "targetHP",
        "type": "number",
        "default": 150,
        "min": 1,
        "max": 999,
        "step": 1,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      }
    ],
    "outputs": [
      {
        "name": "minDamage",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "maxDamage",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "averageDamage",
        "precision": 1,
        "unit": ""
      },
      {
        "name": "percentHP",
        "precision": 1,
        "unit": "%"
      },
      {
        "name": "stabMultiplier",
        "precision": 1,
        "unit": ""
      },
      {
        "name": "effectivenessMultiplier",
        "precision": 2,
        "unit": ""
      },
      {
        "name": "knockOut",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
