Skip to main content

BattleManager

The MonoBehaviour that drives a single monster battle. BattleManager is a thin coordinator: the real work is split across 15+ sibling modules (each its own MonoBehaviour on the same GameObject) and the turn flow is driven by BattleStateMachine. This is the Source-tier map of that architecture.

battle manager

The manager owns the sequence, not the rules. Each module answers about its own concern and the state machine decides what gets asked next.

Namespace: OpenMon.MCE.Battle

SDK vs. Source surface

For most integrations you do not talk to BattleManager directly — you observe battles through the read-only IBattleSystem SDK interface (events, current state). The members below are internal (module accessors) or the concrete BattleManager API used from within the engine assembly (OpenMon.MCE.Runtime), i.e. the Source tier. Reach for them when you extend battle logic, not to read state from your game code.

Class shape​

[RequireComponent(typeof(BattleStateMachine))]
[RequireComponent(typeof(BattleManagerBattlersModule))]
// ...one RequireComponent per module...
public class BattleManager : OpenMonBehaviour<BattleManager>, IBattleManager, IPlayerDataReceiver
{
// Module accessors (internal — resolved from sibling components):
internal BattleManagerBattlersModule Battlers { get; }
internal BattleManagerHealthModule BattlerHealth { get; }
internal BattleManagerMovesModule Moves { get; }
internal BattleManagerCaptureModule Capture { get; }
internal BattleManagerAIModule AI { get; }
// ...BattlerStats, BattlerSwitch, Rosters, Scenario, Statuses,
// Characters, Animation, Audio, Megas...

// Public battle state:
public BattleType BattleType;
public EnemyType EnemyType;
public bool IsBattleOver;
public int TurnCounter { get; }
public byte BattleSpeed { get; }
public bool CanPlayerRun { get; }

public void SubscribeToBattleInitialized(Action callback);
public void SubscribeToBattleFinished(Action<BattleResultParameters> callback);
public void TickTurn();
public void FinishBattle();
public BattleMonsterSprite GetMonsterSprite(BattlerType type, int index);
}

Every module derives from the shared base BattleManagerModule<T>, which exposes the same set of sibling-module accessors so modules can call into each other:

public abstract class BattleManagerModule<T> : OpenMonBehaviour<T>
where T : BattleManagerModule<T>
{
protected BattleManager BattleManager { get; }
protected BattleManagerBattlersModule Battlers { get; }
protected BattleManagerHealthModule BattlerHealth { get; }
// ...same accessors as BattleManager...
}

Module index​

Each battle behaviour is one MonoBehaviour next to BattleManager, required via [RequireComponent]. The five below are the ones you touch when extending battles; the rest handle presentation and bookkeeping.

ModuleAccessorResponsibility
BattleManagerBattlersModuleBattlersBattler lookup, sprites, forms, running away
BattleManagerHealthModuleBattlerHealthHP changes, faint detection and processing
BattleManagerMovesModuleMovesExecuting moves, accuracy
BattleManagerCaptureModuleCaptureCapture attempts
BattleManagerAIModuleAIPer-roster AI strategies
BattleManagerBattlerStatsModuleBattlerStatsStat stages, friendship on start
BattleManagerBattlerSwitchModuleBattleManagerBattlerSwitchSending battlers in/out
BattleManagerRostersModuleRostersRoster preparation, faint checks
BattleManagerScenariosModuleScenarioWeather, terrain, scenario setup
BattleManagerStatusesModuleStatusesStatus conditions
BattleManagerCharactersModuleCharactersTrainer characters
BattleManagerAnimationModuleAnimationBattle intro/flow animation
BattleManagerAudioModuleAudioBattle audio
BattleManagerMegaModuleMegasMega / giga form changes

Public state & callbacks​

BattleType​

The kind of battle in progress (single, double, etc.).

Type: BattleType

EnemyType​

Whether this battle is against Wild monsters or a Trainer.

Type: EnemyType

IsBattleOver​

true once the battle has resolved.

Type: bool

TurnCounter​

Number of turns that have passed this battle.

Type: int (read-only)

BattleSpeed​

The animation speed-up factor for this battle, taken from the battle configuration.

Type: byte (read-only)

CanPlayerRun​

true when the enemy is Wild and no fighting enemy battler is an alpha.

Type: bool (read-only)

SubscribeToBattleInitialized(Action callback)​

Register a callback fired once the battle has finished initializing.

SubscribeToBattleFinished(Action<BattleResultParameters> callback)​

Register a callback fired when the battle ends, receiving a BattleResultParameters (battle type, who won, captured monster, respawn flag).

TickTurn()​

Advance the turn counter and clear LastSuccessfulMoveThisTurn. Called by the state machine at the start of each turn.

FinishBattle()​

Build the BattleResultParameters and raise the battle-finished callback.

GetMonsterSprite(BattlerType type, int index)​

Get the on-screen BattleMonsterSprite for a battler slot. Overloads accept a Battler or a (BattlerType, int) tuple.

Returns: BattleMonsterSprite.

Battlers module​

BattleManagerBattlersModule — resolving battlers to/from indices and their sprites.

GetBattlerFromBattleIndex(BattlerType type, int battleIndex)​

Get the Battler at a battle index for a side.

Returns: Battler.

GetTypeAndIndexOfBattler(Battler battler)​

Reverse lookup: the (BattlerType Type, int Index) of a battler.

Returns: (BattlerType Type, int Index).

GetBattlersFighting(BattlerType type)​

All battlers currently fighting on a side. A parameterless overload returns both sides.

Returns: List<Battler>.

IsBattlerFighting(BattlerType type, int battlerIndex)​

Whether the given slot has a battler actively fighting.

Returns: bool.

ChangeForm(BattlerType battlerType, int index, ...)​

Coroutine that changes a battler's form mid-battle (regional/mega/transform). Several overloads exist for the different form-change triggers.

Returns: IEnumerator.

RunAway(BattlerType type, int index, bool playAnimation, bool bypassAllyChances = false)​

Coroutine that attempts to flee the battle.

Returns: IEnumerator.

Health module​

BattleManagerHealthModule — HP mutation and faint handling.

ChangeLife(Battler battler, Battler user, int amount, Move userMove = null, bool playAudio = true, bool forceSurvive = false, bool isSecondaryDamage = false, bool ignoreAbilities = false, Action<int, bool> finished = null)​

The canonical way to apply damage or healing to a battler in battle. Runs the on-hit animation and audio, triggers abilities, and reports (appliedAmount, fainted) through finished. Overloads accept battler indices instead of Battler references.

Returns: IEnumerator.

CheckFaintedBattlers()​

Coroutine that detects battlers whose HP hit zero this step.

Returns: IEnumerator.

ProcessFaintedBattlers()​

Coroutine that plays faint animations and resolves the fainted battlers.

Returns: IEnumerator.

GetNumberOfFainted(BattlerType battlerType, int battlerIndex)​

Count of fainted monsters in a roster.

Returns: int.

Moves module​

BattleManagerMovesModule — executing moves.

PerformMove(BattlerType type, int index, List<(BattlerType Type, int Index)> targets, int moveIndex)​

Perform the move in slot moveIndex (0–3 for the four move slots, 4 for Struggle) against the given targets, running the full effect pipeline.

Returns: IEnumerator.

ForcePerformMove(BattlerType type, int index, ...)​

Force a specific move to execute (used by move effects that call other moves).

Returns: IEnumerator.

LastSuccessfullyPerformedMove​

The last move that resolved successfully.

Type: Move

Capture module​

BattleManagerCaptureModule — capturing wild monsters.

TryCaptureMonster(int index, Ball ball)​

Coroutine that runs a capture attempt against the enemy battler at index with the given Ball. No-ops (and logs) against trainers or when more than one enemy is fighting.

Returns: IEnumerator.

AI module​

BattleManagerAIModule — the pluggable per-roster AI.

PlayerControlsFirstRoster​

Whether the human player controls the first ally roster.

Type: bool

AllyAIs / EnemyAIs​

The BattleAI strategy assigned to each roster on each side.

Type: List<BattleAI>

GetAI(BattlerType type, int index)​

Get the BattleAI controlling a given roster.

Returns: BattleAI.

BattleAI (strategy base)​

AI strategies subclass the abstract BattleAI ScriptableObject (OpenMon.MCE.Battle.AI). Built-in strategies include RandomBattleAI, PerformEffectiveMove, PerformRandomMove and MLBattleAI (ML-Agents driven).

public abstract class BattleAI : MonsterDatabaseScriptable<BattleAI>
{
public abstract IEnumerator RequestPerformAction(MCESettings settings,
BattleManager battleManager, BattlerType type, int inBattleIndex,
Action<BattleAction> callback);

public abstract int RequestNewMonster(MCESettings settings,
BattleManager battleManager, BattlerType type, int inBattleIndex,
List<Battler> forbiddenBattlers);

public virtual void OnBattlerFainted(BattleManager battleManager,
BattlerType ownType, int ownIndex, BattlerType faintedType, int faintedIndex);

public virtual void OnBattleEnded(BattlerType ownType, int ownIndex,
BattlerType winners, BattleManager battleManager);
}

To add a custom AI, subclass BattleAI, implement RequestPerformAction (pick the action for the turn) and RequestNewMonster (pick a replacement after a faint), then assign the asset to a battle template.

BattleStateMachine​

BattleStateMachine (a [RequireComponent] sibling) drives the turn loop. BattleManager.Construct starts battle initialization; once ready it calls:

GetCachedComponent<BattleStateMachine>().StartBattleLoop();

StartBattleLoop()​

Begin the coroutine that runs the ordered turn loop (gather actions → order by priority → resolve → check faints → next turn) until IsBattleOver.

Extending a battle​

using System.Collections;
using OpenMon.MCE.Battle;
using OpenMon.Foundation.Behaviours;

namespace MyGame.Battle
{
// A custom module lives on the same GameObject as BattleManager and reaches the
// other modules through the shared base class.
public class MyBattleHookModule : BattleManagerModule<MyBattleHookModule>
{
public IEnumerator HalveEnemyLead()
{
Battler lead = Battlers.GetBattlerFromBattleIndex(BattlerType.Enemy, 0);
int damage = (int)(lead.CurrentHP / 2);

// Route HP through the health module so animations/abilities still fire.
yield return BattlerHealth.ChangeLife(lead, lead, -damage);
}
}
}