BattleState class. The BattleManager node owns the current state and triggers transitions.
This design makes each phase independently testable and easy to extend without touching unrelated logic.
State diagram
Class hierarchy
All battle states share a common base. The inheritance chain is:BaseState is a generic state base that provides a controlled_node property. BattleState specialises it with a typed manager property that gives every state direct access to the BattleManager:
manager without coupling states to each other.
The five states
BattleStart — setup
BattleStart — setup
File:
assets/battle/states/start.gdBattleStart runs once at the beginning of every match. Its job is to build
the initial game world before any player or bot acts.Responsibilities:- Calls
MusicManager.play_music("battle")to start the battle music - Calls
manager.setup_player()— creates the human player fromPlayerStats, builds their deck - Calls
manager.setup_bots()— creates 1–3 bots with random decks, shuffles turn order - Calls
manager.setup_ui()— refreshes player stats panel, seeds hand display, hides end UI - Calls
manager.setup_world()— disables dice viaBattleWorld
| Condition | Next state |
|---|---|
| Human player goes first | BattleTurn |
| A bot goes first | BattleLoop |
BattleLoop — bot turns
BattleLoop — bot turns
File:
assets/battle/states/loop.gdBattleLoop handles all automated (bot) turns. It runs without player
interaction and loops until it is the human’s turn or the round ends.Responsibilities:- Determines whose turn is next in the turn order
- Rolls the dice for the active bot
- Selects a rock for the bot to move to
- Chooses a card from the bot’s hand and plays it
- Advances the turn counter
| Condition | Next state |
|---|---|
| Next in turn order is a bot | Stays in BattleLoop (loops) |
| Next in turn order is the human | BattleTurn |
| No turns remain in the round | BattleReferee |
BattleTurn — human turn
BattleTurn — human turn
File:
assets/battle/states/turn.gdBattleTurn is the interactive phase where the human player takes their
action. The scene waits for input at each step.Responsibilities:- Enables the 3D dice — the player clicks it to roll
- Highlights valid rock positions based on the dice result
- Moves the player character to the chosen rock
- Reveals the player’s hand and enables card selection
- Plays the selected card
- Passes the turn when the card has been played
| Condition | Next state |
|---|---|
| Next in turn order is a bot | BattleLoop |
| Next in turn order is the human | Stays in BattleTurn |
| No turns remain in the round | BattleReferee |
BattleReferee — round resolution
BattleReferee — round resolution
File:
See Battle mechanics for the card comparison rules that
this state enforces.
assets/battle/states/referee.gdBattleReferee runs after all players have taken their turns in a round.
It evaluates the cards played, applies damage, and decides whether the match
continues.Responsibilities:- Collects every card played during the round
- Compares cards according to elemental rules and card values
- Applies damage to the appropriate players
- Removes defeated players (those whose health reaches zero)
- Determines whether the match should continue
| Condition | Next state |
|---|---|
| 2 or more players remain, new round | BattleLoop or BattleStart (re-setup) |
| Only 1 player remains | BattleEnd |
BattleEnd — results
BattleEnd — results
File:
assets/battle/states/end.gdBattleEnd is the terminal state. It runs once after BattleReferee
determines a winner.Responsibilities:- Calculates the final player ranking based on elimination order
- Displays the end screen with results (winner, placements)
- Waits for the player to press the back button
| Condition | Next state |
|---|---|
| Player presses back / exit | Returns to start menu via SceneManager |
How BattleManager drives transitions
TheBattleManager node holds a reference to the current active state. States do not transition themselves — they call a method on manager to request a transition, passing the name or reference of the next state. This keeps the state graph easy to audit in one place.
Adding a new state
Follow these steps to introduce a new phase to the battle:Create the state script
Add a new GDScript file under
assets/battle/states/. Extend BattleState
and implement the enter(), exit(), and update() methods inherited from
BaseState.Register the state in BattleManager
Open
assets/battle/battle_manager.gd (or the scene file) and add your new
state as a child node or an exported variable, following the same pattern as
the existing five states.Define the transitions
In the states that should lead to your new state, add a call to
manager.transition_to(manager.state_my_phase) at the appropriate point.
Update any state that your new state should transition to as well.Related pages
Battle manager
The node that owns the state machine and drives transitions between states.
Battle mechanics
Player-facing rules that the Referee state enforces.
Architecture overview
How the state machine fits into the broader codebase design.
Card system
How cards are defined and what data the Referee state reads.