Skip to content

feat(ai): AI Rework v1.0: Enemy Command Selection#1289

Draft
innerthunder wants to merge 63 commits into
betafrom
ai-rework
Draft

feat(ai): AI Rework v1.0: Enemy Command Selection#1289
innerthunder wants to merge 63 commits into
betafrom
ai-rework

Conversation

@innerthunder

@innerthunder innerthunder commented Jul 17, 2025

Copy link
Copy Markdown
Contributor

What are the changes the user will see?

The Enemy AI's command selection algorithm has been completely rewritten, improving its decision-making in the following ways:

  • The AI now uses estimated damage calculations to inform its decision to switch out or use a move. It is now more likely to switch out if it can safely avoid a KO by doing so, and it's much less likely to switch out otherwise.
  • The AI generally weighs the effects of Status moves and the secondary effects of Attack moves more heavily when choosing a move. It also penalizes attacks with drawbacks and steep conditions (e.g. Focus Punch) more harshly. However, it should still prioritize moves that are forecasted to KO the player's Pokemon at all times.
  • Because variance is applied when scoring the move instead of during the final decision-making process, the AI should be much less likely to randomly choose an obviously useless or detrimental move action.
  • The AI's move targeting in double battles is generally improved. Several instances where the AI would erroneously target its ally with an attack or Status move in double battles have been fixed.

Why am I making these changes?

The existing Enemy AI is – to put it bluntly – terrible. There are several glaring issues with it that detract from the game's battle system:

  1. The AI values high-power attacks way too highly in most situations. This causes the AI to almost never use Status moves in the late game and, in some cases, spam moves with exploitable side effects or conditions such as Focus Punch and Giga Impact.
  2. The AI for Wild Pokemon doesn't eliminate useless or detrimental moves before it makes a weighted random move selection. As a result, if 1/4 of the Pokemon's moves are useless, it has a ~6% chance of selecting that move anyway.
  3. The enemy's HP ratio is too much of a factor in evaluating matchups, meaning that Trainer Pokemon can easily be coerced into switching out repeatedly while they're at low HP.
  4. When evaluating matchups, Pokemon are evaluated based on their base types and not the moves that are known to the AI. Enemy Pokemon may decide to switch even if they have a super-effective move against their opponent.
  5. Double battles are mostly an afterthought. The AI often attacks the wrong target, and sometimes even targets their own ally with negative effects.
  6. Several move effects don't have benefit scores implemented and thus cannot be evaluated by the AI. The scores that are implemented are often not implemented with targeting in mind, not scaled properly with respect to attacks, and/or not documented at all.
  7. The AI completely ignores ongoing field effects and other battle effects in its decision making. This is most notable with hazards like Stealth Rock, which are currently absurdly strong in key battles because of how frequently the Trainer can be baited into switching.

You get the idea. With the AI only having two real modes in its decision making – switching and attacking – there is a lot of wasted potential in the battle system.

What are the changes from a developer perspective?

All aspects of the Enemy AI's command selection have been rewritten, including:

  • the entire EnemyCommandPhase
  • related Pokemon and EnemyPokemon methods, including getNextMove and getMatchupScore
  • Move's score calculation methods
  • Effect Score functions for all Move Effect Attributes and other relevant Move Attributes
  • Condition Score functions for Move Conditions (which have also received major structural changes)

This PR also features a new suite of tests performing statistical analysis on the AI's command selection in different scenarios. These tests were made with new utils and matchers targeting EnemyPokemon and their command selection methods.

For more details on the algorithms involved, see the Poketernity Enemy AI Proposal.

For details on newly implemented Move Effect Scores, see the Effect Scores Sheet.

This PR has been developed incrementally with several Addendum PRs, all of which are listed below.

Addendum PRs:

Screenshots/Videos

How to test the changes?

pnpm test ai/

Checklist

  • ⚠️ If this is a PR for main (such as a hotfix), has the game version been updated (pnpm update-version:patch / pnpm update-version:minor?
  • Otherwise: I'm using beta as my base branch
  • There is no overlap with another PR?
  • The PR is self-contained and cannot be split into smaller PRs?
  • Have I provided a clear explanation of the changes?
  • Have I tested the changes manually?
  • Are all unit tests still passing? (pnpm test:silent)
    • Have I created new automated tests (pnpm test:create) or updated existing tests related to the PR's changes?
  • Have I provided screenshots/videos of the changes (if applicable)?
    • Have I made sure that any UI change works for both UI themes (dark and light)?

innerthunder and others added 30 commits January 26, 2025 12:40
* Add basic attack scoring functions

* Base code for matchup score

* Add `getAverageMatchupScore`

* Add effect score and total move score functions

* Minor comment edit

* Apply review suggestions + doc edits

* Revert change to wave index check for simulated moves
* Rewrite Enemy Command selection

* Fix runtime errors in tests

* Rewrite `forceEnemyToSwitch` util + more test fixes

* command selection no longer corrupts move targeting

* Add handling for counter-attacks and no valid targets

* Add override to prevent enemies from switching

* Add (temporary) ally target penalty

* Add new `enemy_command` test for non-KO state

* Update src/field/pokemon.ts

Co-authored-by: PigeonBar <56974298+PigeonBar@users.noreply.github.com>

* Add null check to `getMoveHistory`

* Update test/ai/enemy_command.test.ts

Co-authored-by: PigeonBar <56974298+PigeonBar@users.noreply.github.com>

* Update test/ai/enemy_command.test.ts

Co-authored-by: PigeonBar <56974298+PigeonBar@users.noreply.github.com>

* Fix missing null checks for `battle/turn/battleSummonData`

* Apply flx's suggestions

Co-Authored-By: flx-sta <50131232+flx-sta@users.noreply.github.com>

* Resolve leftover conflicts (encore test is flaky?)

---------

Co-authored-by: PigeonBar <56974298+PigeonBar@users.noreply.github.com>
Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
* Add property-based move score modifiers

* Add unit tests for priority + low accuracy

* Apply code review suggestions

* Address comments
…ons` (#463)

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: PigeonBar <56974298+PigeonBar@users.noreply.github.com>
Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com>
* Update and document `getEnemyMoveChoices`

* Create matchers for common AI tests

* Use matcher for all `enemy-command` tests

* Fix wave data object; fix import in `enemy-pokemon.ts`

* Fix Fusion Flare + Fusion Bolt test

* Update `FlinchAttr#getMoveChance` to match superclass

* Update `SecretPowerAttr#getMoveChance` to match superclass

* Apply review suggestions

Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>

* Use `coerceArray` for matcher helper

* "plurality" -> "majority"

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
* Add effect scores for ability-changing effects

* Apply review suggestions

Co-Authored-By: NightKev <34855794+DayKev@users.noreply.github.com>

* Add `ability-change.test`

* Add `switch-abilities` test

* Add `suppress-abilities` test

* Add `ability-copy` and `ability-give` tests

* Move ability lists to constants file

* Make numbers less magic

* Add `ai-constants.ts`

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Add effect scores for all arena tags

* Add effect scores for hazards and Pledge moves

* Add unit tests

* Apply review suggestions

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Temporarily fix Wide Guard et al.'s condition evaluation

* Reorganize AI test utils + docs

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
…1182)

* Rewrite Condition Score logic

* Convert more unresolvable conditions to `MoveConditions`

* Remove `MoveCondition#getUserBenefitScore`

* Fix scoring unit tests

* Add unit tests + minor fixes for condition score

* Resolve TODO in `targetMoveCopiableCondition`

* Apply review suggestions

Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>

* Make `MoveCondition.condition` read-only

* Update Focus Punch condition score

---------

Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
* Matchup Scores and EAS are now cached

* Simulated moves now have distinct `MoveIds`

* Fix `isNil` cache checks

* Add docs for simulated move ID assignment

* Add `ATTACK_SCORE_HP_THRESHOLD` constant

* Add remarks to `SIMULATED_MOVE` enums
Reimplement enemy Tera commands (simplified)
innerthunder and others added 7 commits August 4, 2025 13:39
…#1303)

* Add Effect Scores to `RemoveArenaTagsAttr` and `SwapArenaTagsAttr`

* Add Effect Score to `RemoveAllSubstitutesAttr`

* Add Effect Score to `RemoveBattlerTagAttr`

* Rename `AddBattlerTagIfBoostedAttr`

* Add tests for Defog

* Add Rapid Spin tests

* Add Tidy Up tests

* Add Court Change tests

* Fix incorrect/flaky tests

* Court Change no longer scores tags that expire on the same turn

* Remove `RemoveArenaTagsAttr` subclasses

* Add tests for Defog vs. screens

* Update test/ai/move-effect-scores/defog.test.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Add `StatusEffectAttr` effect score

* Add `MultiStatusEffectAttr` effect score

* Apply review suggestions

* Add effectiveness check for status moves + Spore scoring test

* Add Thunder Wave tests

* Add Will-O-Wisp tests

* Removed unintended chance rolls in `StatusEffectAttr` scoring

* small Will-O-Wisp test update

* Add Toxic tests

* Add type guard to account for new status effects in the future

Add missing return type for `StatusEffectAttr#getStatusEffectScore`

* Limit effectiveness check in `getMoveScore` to status moves

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
@innerthunder innerthunder changed the title [AI] AI Rework v1.0: Enemy Command Selection feat(ai): AI Rework v1.0: Enemy Command Selection Aug 15, 2025
innerthunder and others added 22 commits August 20, 2025 11:28
…es (#1324)

* Add scoring to `PsychoShiftEffectAttr`

* Add scoring to `HealStatusEffectAttr`

* Add scoring for `BypassSleepAttr`

* Add scoring for `PartyStatusCureAttr`

* Reorganize `PartyStatusCureAttr`

* Add Psycho Shift scoring tests

* Add Refresh test

* Add Snore test

* Update scoring for `HealStatusEffectAttr`

* Add Heal Bell tests

* Fix incorrect multipliers for chance-based effect scoring
* Add scoring for `HealAttr` + `HealOnAllyAttr`

* Add scoring for `HitHealAttr` and `HpSplitAttr`

* Add test coverage for `HealAttr`

* Add tests for Pollen Puff

* Add Drain Punch scoring tests

* Add Strength Sap and Pain Split scoring tests

* Apply review suggestions
* Rewrite Ally Target scoring logic

* Update helping-hand-attr.ts

* Rewrite `HealStatusEffectAttr` ally target scoring

* Fix broken docs link

* Update src/data/moves/move-attrs/move-attr.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Add scoring for `StatStageChangeAttr` + subclasses

* Add docs + adjust stat stage calculations for scoring

* Add Defiant/Competitive awareness against opponents

* Add ally Body Press awareness + unit tests for self-targeted boosts

* Add Charm, Screech, and Scary Face scoring tests

* Resolved TODO in Strength Sap test

* Add Belly Drum scoring test + bug fixes

* Fix failing Defog scoring tests

* Review suggestions + Update ATS method signature

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Add scoring restrictions for Defense and Evasion boosting

* Reduce complexity in `StatStageChangeAttr` scoring methods

* Convert `xEffectiveStatOptions` into global constants

* Remove redundant docs

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
…r` (#1341)

Move ability- and move-revealing utils to `FieldHelper`
* Add scoring for `StealPositiveStatsAttr`

* Add scoring for `CopyStatsAttr`

* Add scoring for `OrderUpStatBoostAttr`

* Add scoring for `AccupressureStatStageChangeAttr`

* Add scoring for `PostVictoryStatStageChangeAttr` and `InvertStatsAttr`

* Add scoring for `ResetStatsAttr`

* Add scoring for `SwapStatStagesAttr`

* Add scoring for `SwapStatAttr`

* Add scoring for `AverageStatsAttr` + remove `ShiftStatAttr` benefit scoring

* Add Spectral Thief scoring tests

* Add Psych Up scoring tests

* Add Acupressure scoring tests

* Add Fell Stinger scoring tests

* Add scoring tests for Topsy-Turvy, Haze, and Clear Smog

* Add scoring tests for moves with `SwapStatStagesAttr`

* Add Speed Swap scoring tests

* Add scoring tests for moves with `AverageStatsAttr`

* Rewrite Speed Swap scoring + review suggestions

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Add inverse tests for Topsy Turvy

* Add scoring for `ShiftStatAttr`

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Rewrite multi-target move scoring logic

* Add Earthquake scoring test

* Clean up code in `getOptimalMoveAction`
* Add scoring for post-target effects

* Add scoring for `SacrificialFullRestoreAttr`

* Add scoring for `RecoilAttr`

* Add scoring for `AddSubstituteAttr`

* Add Explosion scoring tests

* Add Mind Blown scoring tests

* Add Healiing Wish / Lunar Dance scoring tests

* Add Brave Bird scoring test

* Add same-turn Tera awareness to Burn Up scoring + tests

* Add Substitute scoring test + fix bug in MUS calculation

* Apply review suggestions

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
#1351)

* Add scoring + utils for weather-changing effects

* Add scoring + utils for terrain-changing effects

* Rename to `ChangeTerrainAttr` and `ChangeWeatherAttr`

* Add Terrain secondary effect scoring component

* Add Misty Terrain scoring test

* Add Electric Terrain scoring test

* Add Grassy Terrain scoring test

* Add Psychic Terrain scoring test

* Add Terrain removal tests for Defog scoring

* Add Sunny Day scoring tests

* Add Rain Dance scoring tests

* Add Sandstorm scoring test

* Add Snowscape scoring test

* Fix erroneous ability condition checks in weather/terrain scoring

* Fix imports

* Use `ReadonlySet` instead

* Add doubles + challenge test coverage (+ docs)
* Add base Effect Score modifier for charge moves

* Add Effect Scores for unscored charge attributes

* Add Solar Beam test + add bypass check to Sky Drop scoring

* Add Sky Drop scoring tests
* Reorganize type-changing attributes

* Add scoring for `ChangeTypeAttr` + subclasses

* `CopyBiomeTypeAttr` now extends `ChangeTypeAttr`

* Add scoring for `CopyTypeAttr`

* Add scoring for `AddTypeAttr`

* Add Soak scoring tests

* Add Conversion scoring tests + `FieldHelper.setSpeed`

* Add Reflect Type scoring tests

* Add Forest's Curse scoring tests

* Lint + apply review suggestions

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Affects the Enemy Pokemon and/or Trainer AI Refactor For refactoring code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants