Back to Hub

TeraRaidCalc: Type Matchups as a Scoring Problem

TeraRaidCalc type comparison view TeraRaidCalc stat analysis screen

The problem

Tera Raids in Pokémon Scarlet and Violet punish lazy team choices. I kept doing mental arithmetic for type effectiveness, tera overrides, and bulk - so I turned the problem into code.

The goal was quick raid prep: rank a shortlist of counters before I burned a raid sandwich, not build a full competitive VGC simulator.

Pokemon Battle Types Explained

Every Pokémon has one or two types. When you attack, the move's type is checked against the defender's types on a chart: super effective (2×), not very effective (½×), or no effect (0× from immunities). Dual-types multiply those modifiers, which is why a Water move into Grass/Dragon feels different from Water into pure Grass.

STAB (same-type attack bonus) is the quiet multiplier people forget in raid panic. When a Pokémon uses a move that matches one of its own types, damage gets a 1.5× boost. That is why a high Attack stat on the "right" offensive type matters as much as raw super effectiveness on paper.

Immunities are hard zeros, not small penalties. Ground cannot hit Flying; Electric cannot hit Ground in the classic loop. In raids those edges show up as wasted turns if you bring a counter that looks good on a chart but cannot damage the boss at all.

Tera Raid bosses add a tera type on top of their base typing. Terastalizing can change which moves are super effective against them and which resistances they keep from their original types. A Fire Tera Charizard is not the same threat model as base Fire/Flying - the calculator has to score against both layers.

The scoring model

Instead of a single "super effective" lookup, the app ranks candidates with several signals:

  • Type effectiveness against both original and tera types
  • Defensive bulk (HP, Defense, Sp. Defense)
  • Offensive potential (Attack, Sp. Attack) and STAB potential
  • Speed tier advantages and immunity interactions

React and TypeScript keep the UI responsive while the scoring logic stays in plain functions I can reason about and adjust. A chart tells you one matchup; a score sorts ten Pokémon you already own.

What I learned

Domain rules explode quickly. Tera types rewrite matchups; immunities zero out entire categories; speed ties matter for support roles. Encoding game knowledge in data structures is harder than drawing type charts on paper.

There is no universal "best" counter without context - raid level, your box, and whether you need bulk or burst all shift the ranking. The tool reflects that by sorting, not declaring a single winner.

What I'd improve next

Move-based recommendations, event raid presets, and offline caching of Pokémon data so the app works without repeated API calls.

Source code