Battle AI
MCE uses a pluggable strategy pattern for battle AI. Every AI is a BattleAI ScriptableObject, and the built-in ones are designed to be chained: each strategy tries to do its one thing and hands the decision to its Fallback AI when it cannot.
The AI never drives the battle — it answers one question, "what would this trainer do now", and the battle loop decides when to ask. That separation is what lets any battle use a different strategy without touching the turn flow.
Architecture
BattleAI (namespace OpenMon.MCE.Battle.AI) has two things to answer:
RequestPerformAction-- the battler's turn. The AI calls back with aBattleAction, a small struct describing what to do: the battler (BattlerTypeandIndex), the actionType(Move,Switch,ItemorRun), whether to trigger the Mega form (TriggerMegaForm) and the numericParameters(which move and which target, which item, which monster).RequestNewMonster-- which monster of the roster to send in after one fainted.
It also has two optional hooks, OnBattlerFainted and OnBattleEnded (the ML AI uses them for rewards).
A chain is just assets pointing at assets:
MegaOrGigaIfCan ──Fallback──▶ SwitchToEffectiveMonster ──Fallback──▶ PerformEffectiveMove ──Fallback──▶ PerformRandomMove ──Fallback ──▶ RandomBattleAI
Each link looks at the situation; if its condition is met it answers, otherwise it asks its fallback. RandomBattleAI is the end of every chain: it has no fallback.
Built-In AI Strategies
All of them are created from Assets > Create > MCE > Battle > AI > ....
| Asset | What it does | Settings |
|---|---|---|
| RandomBattleAI | Chooses a random action between a random move and switching to a random monster. Meant as the ultimate fallback. | -- |
| PerformRandomMove | Performs a random move, or falls back if none is available. | Fallback |
| PerformEffectiveMove | Performs the most powerful effective damaging move it has: anything above the threshold counts as effective; among effective moves it prefers multi-target ones, then more power. Falls back when there is no effective move or the chance roll fails. | EffectivenessThreshold (default 1), Chance (0-1), Fallback |
| SwitchToEffectiveMonster | Switches to a party member that has an effective move, with some randomness. It also chooses which monster to send in after a faint. | EffectivenessThreshold, SwitchingChance (0-1), Fallback |
| UseBattleItems | Uses battle items under certain conditions (healing items below an HP threshold, listed items); falls back otherwise. | UseIfAvailable, UseOnOwnIfAvailable, HPThreshold, HPHealItems, Fallback |
| MegaOrGigaIfCan | Asks its fallback for the action, then flags it to change to the Mega or giga form if the battler can. | Fallback |
| IfWildWithRunChanceRun | If the monster is wild and its species has a chance to run, runs when the roll succeeds; otherwise passes on. | Fallback |
| MLBattleAI | Lets a trained ML-Agents brain decide (see below). | AgentPrefab, Fallback |
Choosing the AI of a Battle
Each roster of a battle is controlled by one BattleAI:
- For ordinary encounters -- wild fights and trainer fights launched by the CommandGraph nodes
SingleWildFight,DoubleWildFightandSingleTrainerFight-- theBattleLauncherasset uses its Default AI field. Point it at the head of the chain you want. - To give a battle its own strategy, use a
BattleTemplate(Create > MCE > Battle > Template): its AIs array holds oneBattleAIper roster, next to the rosters, characters, bags and the rest of the battle's parameters. TheFightFromTemplatenode launches it. - From code,
BattleLauncher.LaunchBattle(...)takes the array of AIs directly.
Example chains (the AI you assign to the BattleLauncher or the template is the first one listed):
Easy (Route 1)
PerformRandomMove → RandomBattleAI
Medium (Gym puzzle)
MegaOrGigaIfCan → PerformEffectiveMove → PerformRandomMove → RandomBattleAI
Hard (Champion)
MegaOrGigaIfCan → UseBattleItems (HP below 25%) → SwitchToEffectiveMonster → PerformEffectiveMove → PerformRandomMove → RandomBattleAI
Writing Your Own AI (Source and Studio Editions)
Subclass BattleAI, implement the two abstract methods and give your class a [CreateAssetMenu]:
using System;
using System.Collections;
using System.Collections.Generic;
using OpenMon.MCE.Battle;
using OpenMon.MCE.Battle.AI;
using OpenMon.MCE.Configuration;
using UnityEngine;
[CreateAssetMenu(menuName = "MyGame/AI/Always Struggle", fileName = "AlwaysStruggle")]
public class AlwaysStruggle : BattleAI
{
[SerializeField] private BattleAI Fallback;
public override IEnumerator RequestPerformAction(MCESettings settings, BattleManager battleManager,
BattlerType type, int inBattleIndex,
Action<BattleAction> callback)
{
// Ask the next link of the chain, then adjust what it answered.
BattleAction action = default;
yield return Fallback.RequestPerformAction(settings, battleManager, type, inBattleIndex,
answer => action = answer);
callback(action);
}
public override int RequestNewMonster(MCESettings settings, BattleManager battleManager,
BattlerType type, int inBattleIndex, List<Battler> forbiddenBattlers) =>
Fallback.RequestNewMonster(settings, battleManager, type, inBattleIndex, forbiddenBattlers);
}
The protected helper GenerateActionForMove(...) builds the BattleAction (move slot and valid target) for a chosen Move, and the static GetEnemies(battleManager, type) returns the opposing battlers that are fighting. See the BattleManager API for the module that owns the AIs.
ML-Agents Integration
MCE includes an experimental ML-Agents-based AI.
MLBattleAI
Uses Unity ML-Agents to make decisions with a trained neural network.
- Difficulty: Variable (depends on training)
- Use Case: End-game trainers, competitive AI, research
- Setup: Requires the
com.unity.ml-agentspackage and theMCE_ML_AGENTSscripting define; the ML code lives in its own assembly (OpenMon.MCE.ML)
For every battler the AI spawns an MCEAgent from its Agent Prefab, writes a vector of observations (the code documents 630 integers: the scenario, the statuses of both sides, the four active battlers and the rest of the roster, each battler described by species, form, level, IVs/EVs, ability, HP, status, moves and PP, held item, stat stages and volatile statuses) and asks the brain for discrete decisions that it translates into a BattleAction. Rewards are given when a monster faints (a share of -10 when your own faints, a share of +100 when an opponent faints). Choosing which monster to send in after a faint is not learned: it goes to the Fallback.
Training the AI
Training runs OUTSIDE Unity, with the standard ML-Agents toolchain. MCE gives you the agent, the observations and the rewards; the trained model is yours to produce.
- Install the Python side in a virtual environment:
pip install mlagents - Write a configuration for the behaviour your agent prefab declares, following the ML-Agents configuration reference
- Run
mlagents-learn <your-config>.yaml --run-id=<a name>, then press Play in Unity when it says it is waiting - Watch it with
tensorboard --logdir results - Export the trained model (
.onnxfile) - Assign the model to your agent prefab
The engine's own repository keeps wrappers for these steps (MLAgentsInstall.ps1, RunMLTraining.ps1,
ViewMLResults.ps1 and MLAgentsConfig/) in its root folder. They are maintainer tooling and are NOT part of any
package, so they are not in what you received: the steps above are the ones to follow.
ML-Agents is a separate package with its own Python dependencies. The core MCE battle system works without it. Only install ML-Agents if you plan to use neural network-based AI.
AI Difficulty Guidelines
| Difficulty | AI Chain | Where to Use |
|---|---|---|
| Very Easy | RandomBattleAI only | Wild encounters |
| Easy | PerformRandomMove | Early routes, youngsters |
| Medium | PerformEffectiveMove (type aware) | Gym trainers, rivals |
| Hard | Mega + items + switching + effective moves | Gym leaders, Elite Four |
| Neural | MLBattleAI with a trained model | Competitive, challenge modes |
Best Practices
- Match AI to narrative context. A random bug catcher should not play like the Champion.
- Test AI against player teams of similar level. Unbalanced AI feels unfair.
- Build chains from the small strategies. They are easier to maintain than one monolithic AI.
- Always end a chain with
RandomBattleAI(orPerformRandomMovebacked by it) so the AI can never get stuck without an answer. - Do not over-optimize AI for early trainers. Players need to learn the system before facing smart opponents.