# Game State Machine

> Scoreboard-based game state machine with the Kore OOP module - register states, transition between them, and react to state changes.

Updated 2026-10-07. Canonical: https://kore.ayfri.com/docs/oop/game-state-machine

The game state system uses a [scoreboard](https://minecraft.wiki/w/Scoreboard) to track the current state
and dispatches handlers when the state matches.

It is a good fit for lobbies, round systems, multi-phase boss fights, tutorials, or any flow that repeatedly switches
between a known set of named states.

> [!FOOTPRINT]
> - **Objectives:** `kore_state`, holding the state on `#game_state`.
> - **Storage:** none.
> - **Entities:** none.
> - **Forceloaded chunks:** none.
> - **Every tick:** no.
> - **Load and files:** `kore_state_init` creates the objective and sets the first state back on every load and `/reload`. `whenState` blocks become functions listed in `#kore:state_when_handlers`.

## Registering states

```kotlin
val states = registerGameStates {
	state("lobby")
	state("playing")
	state("ended")
}
```

This generates a **load function** that creates the `kore_state` objective and sets the initial state.

## Typical lifecycle

```kotlin
function("prepare_game") {
	states.transitionTo("lobby")
}

function("start_game") {
	states.transitionTo("playing")
}

function("finish_game") {
	states.transitionTo("ended")
}
```

Keeping transitions explicit like this makes it easier to reason about which setup code belongs to each phase.

## Transitioning and reacting

```kotlin
function("game_loop") {
	states.transitionTo("playing")

	states.whenState("playing") {
		say("The game is in progress!")
	}

	states.whenState("ended") {
		say("Game over!")
	}
}
```

## Game state actions

Helper functions integrate states with other OOP systems:

```kotlin
// only switches state if the cooldown has expired, so the transition cannot be spammed
states.transitionWithCooldown("playing", cooldown, player)

// runs the spawner every time the game enters this state
states.whenStateSpawn("playing", zombieSpawner, count = 3)

// starts the timer on entering this state
states.whenStateStartTimer("playing", timer, player)
```

## Best practices

- Keep the state list small and meaningful (`lobby`, `playing`, `ended`, etc.).
- Reserve `whenState(...)` for behavior that should only run in one phase.
- Use the integration helpers when a state change should also start a timer, consume a cooldown, or trigger a spawn.
