Suggestion General Ability to attach custom observers to simulated battles

Users who are viewing this thread


The goal

The goal is to have a mod be able to track the results of a simulated battle as it progresses - similar to how a mod might use MissionBehavior to track kills and such in a non-simulated battle. (For my particular use case, I'm trying to keep track of when individual soldiers in the player's party die)

Current state

There's an existing interface, IBattleObserver which has a TroopNumberChanged method gives the basic information necessary:

public interface IBattleObserver
  void TroopNumberChanged(
    BattleSideEnum side,
    IBattleCombatant battleCombatant,
    BasicCharacterObject character,
    int number, int numberKilled, int numberWounded, int numberRouted, int killCount, int numberReadyToUpgrade);
    // other methods omitted

However, there can only be one IBattleObserver attached to the BattleSimulation at one time - (i.e. the one used to drive the Scoreboard VM, usually), so AFAIK there's no clean way for a mod to attach its own IBattleObserver. (For a not clean way... see below)

It'd be nice if BattleSimulation allowed multiple IBattleObserver's to be attached, or maybe there's some other way mods could be given access to this information.


Current workaround

The workaround I'm using right now is to override BattleSimulationGauntletView with a subclass to get access the to BattleSimulation and replace the IBattleObserver with a wrapped one. If there's a better way of doing this currently, that'd be great.

public class BattleSimulationOverride : BattleSimulationGauntletView {
    private readonly BattleSimulation _battleSimulation;

    public BattleSimulationOverride(BattleSimulation battleSimulation)
        : base(battleSimulation) {
        _battleSimulation = battleSimulation;

    protected override void CreateLayout() {
        // Wrap the BattleObserver here, after it's been set by SPScoreboardVM.Initialize
        _battleSimulation.BattleObserver =
            new BattleObserverWrapper(_battleSimulation.BattleObserver);
public class BattleObserverWrapper : IBattleObserver {
    private readonly IBattleObserver _wrappedObserver;

    public BattleObserverWrapper(IBattleObserver wrappedObserver) {
        _wrappedObserver = wrappedObserver;

    public void TroopNumberChanged(/* args */) {
        _wrappedObserver.TroopNumberChanged(/* args */);
        // Mod logic here

    // other methods wrapped as well
Top Bottom