# Game State Management in PHPDTS: How State Transitions Work

> **The PHPDTS engine uses a global `$gamestate` variable evaluated on every request to cycle through six distinct phases, from idle preparation to final combo showdown, triggered by time-based checkpoints, player counts, and are...

- Repository: [Nemo Ma/phpdts](https://github.com/amarillonmc/phpdts)
- Tags: architecture
- Published: 2026-02-24

---

**The PHPDTS engine uses a global `$gamestate` variable evaluated on every request to cycle through six distinct phases, from idle preparation to final combo showdown, triggered by time-based checkpoints, player counts, and arena capacity limits.**

The `amarillonmc/phpdts` repository implements a deterministic state machine that drives the battle royale lifecycle. At the heart of this **game state management** system lies the global `$gamestate` variable declared in [`include/common.inc.php`](https://github.com/amarillonmc/phpdts/blob/main/include/common.inc.php), which is checked and updated inside the main request loop to ensure continuous match progression across stateless HTTP requests.

## The Global State Variable and Core Architecture

All state persistence relies on the **`$gamestate`** global variable. The engine initializes this value at the start of each request via `load_gameinfo()` in [`include/init.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/init.func.php) (line 165), which deserializes the stored value from [`gamedata/gameinfo.php`](https://github.com/amarillonmc/phpdts/blob/main/gamedata/gameinfo.php). When a match ends, `gameover()` in [`include/system.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/system.func.php) (line 260) resets this variable to **0**.

The state machine executes inside a guarded block that excludes chat scripts to prevent high-frequency polling from triggering spurious transitions:

```php
if(CURSCRIPT !== 'chat') {
    // State transition logic runs here (lines 64-260)
}

```

## State Values and Their Meanings

The engine defines six discrete integer states that represent distinct match phases, each set at specific lines within [`include/common.inc.php`](https://github.com/amarillonmc/phpdts/blob/main/include/common.inc.php):

- **0** – **Idle/Game Over**: No active match. Initialized by `load_gameinfo()` at line 165 and reset by `gameover()` at line 260.
- **10** – **Preparation**: Countdown window before the match starts. Set at lines 68–70 when `$now > $starttime - $startmin*60`.
- **20** – **Active Battle**: Normal gameplay phase. Set at lines 82–84 once `$now >= $starttime`.
- **30** – **Stop Activation**: Entry is closed and the arena stops expanding. Set at lines 102–104 when capacity or player limits are reached.
- **40** – **Combo Mode**: Accelerated "continuous battle" phase. Set at lines 124–131 or 133–140 based on survivor counts or death thresholds.
- **50** – **End of Combo**: Terminal state assigned in `gameover()` at line 260 immediately before resetting to **0**.

## State Transition Logic in the Main Loop

The transition logic resides in [`include/common.inc.php`](https://github.com/amarillonmc/phpdts/blob/main/include/common.inc.php) and evaluates conditions sequentially on every non-chat request.

### Transition 0 → 10: Entering Preparation

When the system is idle, it checks against the pre-game timer:

```php
if(!$gamestate){
    if(($starttime) && ($now > $starttime - $startmin*60)){
        $gamestate = 10;   // preparation phase (lines 68-70)
    }
}

```

### Transition 10 → 20: Match Start

Once the preparation countdown completes, the battle phase begins:

```php
if($gamestate == 10 && $now >= $starttime){
    $gamestate = 20;       // active battle (lines 82-84)
}

```

### Transition 20 → 30: Stop Activation

During active battle, the engine monitors arena capacity (`$areanum`) and valid participant counts (`$validnum`):

```php
if($gamestate == 20){
    if(($validnum <= 0) && $areanum >= $arealimit*$areaadd){
        gameover(...);               // not enough players → end
    } elseif(($areanum >= $arealimit*$areaadd) || ($validnum >= $validlimit)){
        $gamestate = 30;            // stop new entrants (lines 102-104)
    }
}

```

If valid participants drop to zero while the arena is full, `gameover()` terminates the match immediately rather than transitioning to state 30.

### Transition 30 → 40: Entering Combo Mode

Combo mode activates via two alternative survival checks at lines 124–140:

```php
// Check 1: Few survivors remaining
if($gamestate < 40 && $gamestate > 20 && $alivenum <= $combolimit){
    $gamestate = 40;                // combo because few survivors
}

// Check 2: Death count exceeds threshold
if($gamestate < 40 && $gamestate >= 20 && $combonum && $deathnum >= $combonum){
    $gamestate = 40;                // combo because deaths exceed threshold
}

```

### Transition 40 → 0: Game Conclusion

While in combo mode (state 40) or end-of-combo (state 50), the engine checks for a single survivor:

```php
if($gamestate >= 40){
    $result = $db->query("SELECT pid FROM {$tablepre}players WHERE hp>0 AND type=0");
    $alivenum = $db->num_rows($result);
    if($alivenum <= 1){
        gameover();                 // line 260: resets $gamestate to 0
    }
}

```

## Anti-AFK Protection Within Combo State

State 40 includes automated AFK detection that runs continuously to prevent idle stalling:

```php
if($gamestate >= 40 && $now > $afktime + $antiAFKertime*60){
    antiAFK();                      // resets AFK timer
}

```

The `antiAFK()` function in [`include/system.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/system.func.php) refreshes timestamps to keep the final showdown moving.

## Supporting Functions and Persistence Layer

State persistence and helper logic are modularized across specific files:

- **`load_gameinfo()`** in [`include/init.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/init.func.php) (line 165) deserializes `$gamestate` from [`gamedata/gameinfo.php`](https://github.com/amarillonmc/phpdts/blob/main/gamedata/gameinfo.php) at request start.
- **`gameover()`** in [`include/system.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/system.func.php) (line 260) resets `$gamestate` to **0**, records the winner, and clears temporary data.
- **`antiAFK()`** in [`include/system.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/system.func.php) manages idle protection during state 40.
- **`init_ruleset_override()`** and **`load_ruleset_override_functions()`** in [`include/ruleset_override.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/ruleset_override.func.php) enable custom rule sets to modify transition thresholds.

## Configuration and Custom Rule Sets

Default thresholds governing **game state transitions** are defined in [`gamedata/system.php`](https://github.com/amarillonmc/phpdts/blob/main/gamedata/system.php):

- **`$startmin`** – Minutes before `starttime` to enter preparation (state 10).
- **`$arealimit`** and **`$areaadd`** – Arena expansion limits triggering state 30.
- **`$validlimit`** – Minimum valid participants required for stop activation.
- **`$combolimit`** – Alive player threshold entering combo mode.
- **`$antiAFKertime`** – Minutes allowed before AFK protection fires.

The [`include/ruleset_override.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/ruleset_override.func.php) file allows server administrators to inject custom logic, overriding variables like `$combolimit` or `$validlimit` without altering the core state machine in [`include/common.inc.php`](https://github.com/amarillonmc/phpdts/blob/main/include/common.inc.php).

## Summary

- The **PHPDTS game state management** system relies on a global `$gamestate` variable persisted in [`gamedata/gameinfo.php`](https://github.com/amarillonmc/phpdts/blob/main/gamedata/gameinfo.php) and evaluated on every non-chat request.
- Six discrete integer states (0, 10, 20, 30, 40, 50) represent the complete match lifecycle from idle preparation through combo finale.
- Transitions trigger based on **time-based checkpoints** (start timers), **player-count thresholds** (valid participants and survivors), and **arena capacity limits** (arealimit calculations).
- The `gameover()` and `antiAFK()` functions in [`include/system.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/system.func.php) handle terminal state cleanup and idle protection.
- Custom rule sets via [`include/ruleset_override.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/ruleset_override.func.php) allow modification of transition logic without core code changes.

## Frequently Asked Questions

### How does PHPDTS persist game state between HTTP requests?

The engine saves the `$gamestate` variable to [`gamedata/gameinfo.php`](https://github.com/amarillonmc/phpdts/blob/main/gamedata/gameinfo.php) at the end of each request cycle. At the start of every subsequent request, `load_gameinfo()` in [`include/init.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/init.func.php) (line 165) deserializes this file back into the global scope, ensuring continuity across the stateless HTTP protocol.

### What happens if the player count drops to zero during active battle?

If `$validnum` reaches zero while the arena has expanded beyond its limit (`$areanum >= $arealimit*$areaadd`), the transition logic in [`include/common.inc.php`](https://github.com/amarillonmc/phpdts/blob/main/include/common.inc.php) (lines 102–104) immediately invokes `gameover()`. This resets `$gamestate` to 0 and terminates the match early due to insufficient participants.

### Can server administrators modify the state transition thresholds?

Yes. While default values reside in [`gamedata/system.php`](https://github.com/amarillonmc/phpdts/blob/main/gamedata/system.php), administrators can implement custom logic through [`include/ruleset_override.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/ruleset_override.func.php). The `init_ruleset_override()` and `load_ruleset_override_functions()` hooks allow modification of variables like `$combolimit` and `$validlimit` without altering the core state machine in [`include/common.inc.php`](https://github.com/amarillonmc/phpdts/blob/main/include/common.inc.php).

### Why does the state machine exclude the chat script?

The guard clause `if(CURSCRIPT !== 'chat')` prevents the state transition logic from executing during chat polling requests. This optimization reduces database load and prevents premature state advances caused by high-frequency AJAX chat updates that do not represent actual game actions.