Battle Core
The Battle class is the heart of SimpleJRPG — a plain C# instance that orchestrates combat through lifecycle methods, combat verbs, and events.
Battle Lifecycle
Start()
public void Start(List<ICombatant> combatants, ITurnSystem turnSystem)
Initializes the battle. Pass in your list of combatants and a turn system implementation. Internally, this method:
- Stores the combatants and turn system references.
- Resets the turn counter and battle history.
- Calls
turnSystem.Init(combatants)so the turn system can set up its internal state. - Sets
StatetoBattleState.WaitingForCommands. - Fires the
OnBattleStartevent.
Start() will silently return if the battle state is anything other than NotStarted. You cannot restart a battle instance — create a new one.
EndBattle()
public void EndBattle(BattleState result)
Ends the battle with the given outcome. Pass BattleState.Victory, BattleState.Defeat, or BattleState.Fled. This method:
- Sets
Stateto the given result. - Clears
CurrentActor. - Creates a
BattleResultcontaining the outcome, total turns taken, surviving combatants, and the full battle history. - Fires the
OnBattleEndevent with the battle instance and the resulting state.
If the battle has already ended (state is Victory, Defeat, or Fled), calling EndBattle() again does nothing.
Turn Flow
BeginNextTurn()
public ICombatant BeginNextTurn()
Advances to the next turn. Asks the turn system for the next actor via GetNextActor(), increments the turn counter, sets state to Executing, and fires OnTurnStart. Returns the actor whose turn it is, or null if no actor is available.
Can only be called when state is WaitingForCommands or Executing.
EndTurn()
public void EndTurn()
Ends the current turn. Fires OnTurnEnd, notifies the turn system via OnTurnEnd(), clears CurrentActor, then automatically calls CheckBattleEnd(). If the battle hasn't ended, state returns to WaitingForCommands.
Can only be called when state is Executing.
State Machine
The battle progresses through a simple state machine. All transitions are driven by the methods described above.
Fled is reached via Flee(), which calls EndBattle(BattleState.Fled) directly — it can happen from any active state, not just after CheckBattleEnd().
Combat Verbs
Combat verbs are the imperative methods you call to make things happen in battle. You do the math — we orchestrate the result.
DealDamage
public void DealDamage(ICombatant source, ICombatant target, int amount,
string damageType = "", string element = "", bool isCrit = false)
Deals damage to a single target. The flow is:
- Fires
OnBeforeDamagewith aBeforeDamageEvent. Subscribers can modifyAmount,DamageType,Element,IsCrit, or setCancel = trueto prevent the damage entirely. - If not cancelled, calls
target.TakeDamage(amount)with the (potentially modified) amount. - Fires
OnDamageDealtwith the finalDamageEvent. - If the target is no longer alive, automatically fires
OnKOand notifies the turn system.
There is also a group overload that accepts IList<ICombatant> targets and fires OnGroupDamageDealt after processing all individual hits.
Heal
public void Heal(ICombatant source, ICombatant target, int amount)
Heals a single target. The flow mirrors damage:
- Fires
OnBeforeHealwith aBeforeHealEvent. Subscribers can modifyAmountor setCancel = true. - If not cancelled, calls
target.Heal(amount). - Fires
OnHealedwith the finalHealEvent.
Group overload available — fires OnGroupHealed after all individual heals.
Kill
public void Kill(ICombatant target, ICombatant killer = null)
Forces a KO regardless of the target's current HP. Calls target.TakeDamage(int.MaxValue), then fires OnKO and notifies the turn system. Does nothing if the target is already dead. This bypasses the before-event system — there is no OnBeforeDamage for Kill.
Revive
public void Revive(ICombatant target, int hpAmount)
Revives a dead combatant by calling target.Heal(hpAmount), then notifies the turn system via OnActorAdded() so the revived combatant is re-inserted into the turn order. Fires OnRevived. Does nothing if the target is already alive.
Status & Buff
ApplyStatus / RemoveStatus
public void ApplyStatus(ICombatant source, ICombatant target, string statusId, int duration = -1)
public void RemoveStatus(ICombatant target, string statusId)
ApplyStatus fires OnStatusApplied with a StatusEvent containing the source, target, status ID string, and optional duration. RemoveStatus fires OnStatusRemoved with the target and status ID. Both have group overloads that fire OnGroupStatusApplied.
The statusId is a pass-through string — Battle doesn't know or care what "Poison" or "Blind" means. Your system decides.
ApplyBuff / RemoveBuff
public void ApplyBuff(ICombatant source, ICombatant target, string buffId, float amount, int duration = -1)
public void RemoveBuff(ICombatant target, string buffId)
ApplyBuff fires OnBuffApplied with a BuffEvent containing source, target, buff ID, numeric amount, and optional duration. RemoveBuff fires OnBuffRemoved. Group overloads fire OnGroupBuffApplied.
Same pass-through philosophy — buffId and amount are yours to interpret. "ATK_UP" with amount 1.5 could mean +50% attack, or 1.5 flat — your call.
Flee
public void Flee(ICombatant who)
Fires OnFled with the fleeing combatant, then immediately calls EndBattle(BattleState.Fled). The battle ends — no further actions are possible.
Whether the flee attempt succeeds is your game's decision. Only call Flee() after you've already determined the attempt was successful. If you want a chance-based flee, do your roll first, and only call this if it passes.
CheckBattleEnd
public bool CheckBattleEnd()
Checks whether the battle should end based on which teams still have living combatants. Returns true if the battle ended, false otherwise.
The logic:
- Team 0 = player team. All other team numbers are considered enemies.
- If no enemies are alive (only team 0 remains) —
EndBattle(BattleState.Victory). - If no team 0 members are alive —
EndBattle(BattleState.Defeat).
CheckBattleEnd() is called automatically at two points: inside EndTurn(), and inside HandleKO() (which fires whenever a combatant dies from DealDamage or Kill). You typically don't need to call it yourself, but you can if you want to check mid-turn.