Does maxing your account — Lv 40 held items, gold emblems, X Attack — let you knock people out before they evolve, regardless of which Pokémon you play? Enemy builds are unobservable in-game, so this answers it with a model: a damage / time-to-KO engine built from current, validated unite-db data and the game's verified damage formula, run across the full 95-Pokémon roster — base moves, Lv5/7 upgrades, enhanced forms, multi-hit, and execute included.
- 📉 Maxed investment adds ~53% to pre-evo burst (≈ a third less time-to-KO overall, and closer to half for pure auto-attackers) — and it holds regardless of Pokémon.
- 🔧 Which lever? Of that gain: items ~57%, X Attack ~32%, emblems ~11% — and emblem rarity barely matters (no-emblems → gold is +4.6% burst; bronze → gold is ~1%). Emblems are optimized over the real 762-emblem set as realistic 6-damage + 4-bulk pages (colors, grades, tradeoffs).
- 🧪 Validated: computed move damage matches Game8 within 0.4% across base moves and upgrades (Cinderace Pyro Ball exactly 1774). 28 tests green.
- 🤔 Honest limit: raw combat power barely predicts the community tier (Spearman +0.06). The model nails "who hits hardest pre-evo" — but "who's actually good in ranked" is range, mobility, CC, objectives, and scaling, which it deliberately doesn't model.
Brute-forces every legal 3-item combo × emblem template per Pokémon (a maxed account), ranking offense by burst and sustained DPS (CDR-aware), tanks/supports by effective HP with shields up:
"Best by modeled combat metric" — see the meta check below for how much that actually predicts viability. Shields are counted "up" (situational).
The chart above is Lv 5 (pre-evo), the level the offensive study uses (where unite-db's move
data is Game8-validated). But survivability is pure stats available at every level, and tanks
come online late — so Lv 5 under-rates them. Re-running the same optimizer at Lv 15 (full
build) — python src/optimize.py --level 15 — reshuffles the board, most dramatically for
Defenders:
The best Defender flips Articuno → Goodra (Goodra is last at Lv 5 but first at Lv 15; Blastoise climbs #13 → #3), and the best Supporter swaps Wigglytuff → Meganium. Offense moves too (Speedster burst Leafeon → Darkrai; All-Rounder Pawmot → Feraligatr). The slope chart makes the defensive churn explicit — identical metric, only the level changes:
Faithfulness: Lv 15 uses the same validated engine — base + Lv 5/7 upgrade moves are Game8-checked (e.g. Pyro Ball), while Lv 11/13 enhanced forms are modeled from unite-db (not in the Game8 sample). The defensive ranking is pure stats, so it's unaffected by that caveat.
It isn't one unit — it's whatever metric the Best by column names, computed against a fixed reference dummy (an un-invested Cinderace at Lv 5) and reported for the build that maximizes it (brute-forced over every legal 3-item combo × emblem page):
| Best by | Score = | computed in |
|---|---|---|
| Burst | post-mitigation damage of casting every kit move once (best Lv 5 form, with X Attack) + autos landing in a 2.0 s window | optimize.burst_damage |
| DPS | auto-attack DPS + Σ(move damage ÷ effective cooldown), CDR-aware | optimize.sustained_dps |
| Eff. HP | raw damage needed to drop the build (avg of physical/special) + shield HP | optimize.survivability |
It's an argmax, not a stat: burst and DPS are optimized independently, so a Pokémon's two rows can list different builds. Scores are not comparable across rows (damage over ~2 s vs damage-per-second vs hit points). And it's a modeled score — the meta check shows it barely tracks real viability (Spearman +0.06).
Of the +53% burst that investment adds over base stats (Lv 4, averaged over 69 offensive mons): items ~57%, X Attack ~32%, emblems ~11%. The emblem-rarity sweep shows the jump is just having a page at all (none → bronze +3.6%); bronze → gold is ~1%. (Emblem pages are a real optimization over unite-db's 762 emblems — colors, grades, and stat tradeoffs — built as realistic 6-of-the-damage-color + 4-bulk pages, not glass-cannon stacks; emblems come out even smaller this way, so the conclusion is robust.) Practical takeaway: upgrade your held items first; emblems are a small edge and their rarity is close to noise.
Basic attacks only (the cleanest lever view), maxed attacker vs. an un-invested squishy:
| @ Lv 3 | un-invested | maxed | reduction |
|---|---|---|---|
| Cinderace | 24 hits / 21.5 s | 13 hits / 10.4 s | 46% / 52% |
| Zeraora | 18 hits / 15.9 s | 11 hits / 8.7 s | 39% / 45% |
| Pikachu | 24 hits / 21.5 s | 13 hits / 10.4 s | 46% / 52% |
(Autos are 100% stat-scaled, so investment helps them most; abilities carry a big flat/level base, so investment is diluted there — which is why the combined effect is ~+53%, not ×2.)
No — Spearman +0.06. Modeled combat power does not predict unite-db's community tier (best for Defenders +0.51, where bulk is the job; even slightly negative for Attackers). This is the most important guardrail in the project: the engine is accurate (validated vs Game8) but measures one narrow thing. "Who's actually good" depends on range, mobility, CC, objective control, and late-game scaling — none of which this models.
- Stats, moves & emblems — unite-db raw JSON (
/pokemon.json,/stats.json,/emblems.json): the Mathcord-sourced data its site loads — 95 mons + 762 emblems. Its pages are JS-rendered (unreadable to a fetcher); the/*.jsonendpoints are raw. The full move kit (base +upgrades+enhanced_+ multi-hit + execute + per-level penetration/CDR) and real emblem pages (colors / grades / stat tradeoffs) are derived from it. Cached indata/unite_db_*.json. - Held/battle items + emblems — Game8 (Lv40 tables, emblem rarity + color sets), patch v1.21.1.8 (2026-05-14).
- Damage formula — reference engine
Stephen-Choi/...: mitigationfloor(atk × 600/(600+Def))+ attack-speed buckets, taken verbatim. (It is stale on rebalanced moves, e.g. Electro Ball — so unite-db, validated vs Game8, is the trusted source.) - Validated:
src/validate.pyreproduces Game8's published move totals within 0.4% (Pyro Ball = 1774 exactly) across base + upgrade moves and multiple levels. 28 tests cover the formula, Blastoise 35%, attack-speed buckets, Muscle Band cap, the move formula, the Game8 cross-check, and the input-provenance proofs below. - Inputs are provable —
src/validate_inputs.pyproves every value that feeds a score traces to its source, in two ways. Provenance (strong, 100% coverage):data/pokemon.json(every mon's attack + per-level stats — 95 mons × levels) anddata/moves.json(every cooldown — 750 base/upgrade/enhanced forms) are exactly reproducible from the cached raw unite-db JSON, so each value equals its source, not a hand-edited copy. Cross-check / snapshot: held items match a Game8 Lv 40 snapshot (each tagged with its Game8 archive id) and are verified to be applied inmake_build; emblems use the intact 762-emblem set with color bonuses that cap correctly and page stats that re-sum from the named emblems; the X Attack multipliers in the pure engine equaldata/battleitems.json. (Magnitude cross-checks of raw numbers live invalidate.py; item/emblem/X-Attack values are locked to patch v1.21.1.8 — re-run the pipeline to refresh from source.)
pip install -r requirements.txt
python -m pytest tests/ -q # 28 tests
python src/validate.py # #1 move damage vs Game8
python src/validate_inputs.py # #1b prove each score input (stats/cooldowns/items/emblems/X Attack) traces to source
python src/optimize.py # Phase 2 per-role optimizer + charts + CSV
python src/optimize.py --level 15 # full-build (Lv 15) variant of the per-role charts
python src/decomposition.py # #2 lever decomposition + emblem-rarity sweep
python src/defensive_items.py # per-item HP/Def/Sp.Def -> effective-HP breakdown + chart
python src/defensive_ranking.py # best tank/support: Lv 5 vs Lv 15 rank shift (slope chart)
python src/meta_validation.py # #5 model vs community tier
python src/emblems.py # exact named emblem pages -> data/emblem_pages.txt
python src/abilities.py # pre/post-evo burst combos
python src/analysis.py # Phase 1 auto-attack hits-to-KO
# Refresh data from unite-db (re-cache + regenerate the derived files):
python src/fetch_unitedb.py ; python src/parse_unitedb_moves.py ; python src/build_pokemon_from_unitedb.pydata/ unite_db_*.json (source) · pokemon.json / moves.json (generated) ·
helditems / battleitems / emblems.json (Game8)
src/ stats.py · damage.py (engine) · builds.py · emblems.py (emblem optimizer) ·
abilities.py (full-kit combat) · optimize.py (Phase 2) · decomposition.py ·
meta_validation.py · validate.py · validate_inputs.py · analysis.py ·
fetch_unitedb / parse_unitedb_moves / build_pokemon_from_unitedb (pipeline)
tests/ engine, move-formula, and Game8-validation tests
figures/ exported charts
- ✅ Engine (full kit, CDR, penetration, shields) · ✅ validated vs Game8 · ✅ per-role optimizer · ✅ lever decomposition · ✅ meta validation.
- Modeled at Lv 5 by default (upgrades begin coming online); the engine handles any level —
python src/optimize.py --level 15renders the full-build variant (and the board reshuffles). - Not modeled: melee boosted (every-3rd) basics, crit-damage scaling (Scope Lens with high Attack), and CC (a stun lets the full combo land uncontested — often the real reason you get knocked out). Shields are counted "up" (situational). The burn-DoT ratio on a couple moves differs ~2× from Game8 (a small secondary component).
- Biggest caveat (measured, not assumed): combat power weakly predicts viability (Spearman +0.06). Treat the per-role tables as "hardest-hitting pre-evo," not a tier list.
MIT. An unofficial fan project — not affiliated with or endorsed by The Pokémon Company, Nintendo, or TiMi Studios. Game data is sourced from unite-db and Game8 for analysis; all trademarks belong to their respective owners.











