NEVER Do (Expert Anti-Patterns)
Order & Determinism
NEVER recalculate turn order every action; strictly sort once per round or ONLY when a speed-relevant stat changes to prevent O(n log n) lag.
NEVER use random tie-breaking for initiative; strictly use a secondary static attribute (Agility, ID, or persistent "luck") for deterministic replays.
NEVER modify an active turn-order queue while iterating it; strictly iterate over a
duplicate()or apply queue modifications after the loop.NEVER broadcast global turn state changes using immediate
call_group(); strictly usecall_group_flags(SceneTree.GROUP_CALL_DEFERRED, ...)to prevent frame spikes when notifying hundreds of units.NEVER rely on the Node hierarchy as the source of truth; strictly use a Dictionary board state for logical grid coordinates.
Logic & Action Economy
- NEVER deduct Action Points (AP) before validation; strictly call
can_perform_action(cost)before applyingcurrent_ap -= costto prevent exploits. - NEVER hardcode phase transitions (
if phase == 0); strictly use an enum + match or a dedicated State Machine for Draw/Main/End phases. - NEVER emit "Turn Ended" before internal cleanup; strictly reset AP and tick status effects BEFORE signaling the next turn.
- NEVER use exact floating-point equality (
==) for AP checks; strictly use>=oris_equal_approx()for robust comparisons.
Tactical Grid & UI
- NEVER use generic
AStar2Dfor tile grids; strictly useAStarGrid2Dfor 10x faster pathfinding and native diagonal handling. - NEVER forget to call
update()onAStarGrid2Dafter changing obstacle states; if you toggleset_point_solid(), the grid MUST refresh before the next query. - NEVER lock the main thread with
whileloops for input; strictly use the await keyword or signals to yield execution back to the Tree. - NEVER handle turn decisions with
is_action_pressed(); strictly useis_action_just_pressed()for discrete, frame-locked menu input. - NEVER skip turn timeouts in networked games; strictly implement a server-side timer with a default "pass" action to prevent griefing. See Networked Turn Timeout golden path below.
Decision Tree — Pick a Turn Model
| Need | Choose | MANDATORY script |
|---|---|---|
| Discrete rounds (chess / tactics / card phases) | Round + initiative queue + AP phases | turn_system_patterns.gd |
| Continuous gauges (FF-style ATB) | Per-actor gauge fill in _process |
active_time_battle.gd |
| Timeline / CTB with interrupts & prediction | Event timeline + predictive UI | timeline_turn_manager.gd |
Do NOT invent a fourth model inline. Read the matching script before coding.
Expert Components (scripts/)
- turn_system_patterns.gd — Match-based phase machines, UndoRedo,
AStarGrid2Dboard helpers. - active_time_battle.gd — ATB gauges, pause-on-ready, async action handoff.
- timeline_turn_manager.gd — Timeline / CTB with interrupts and pre-visualization.
- turn_predictor.gd — Simulate ATB gauges for timeline UI preview.
- combat_stats_resource.gd — Deterministic damage preview Resource for hover UI.
TurnManager Autoload — Interface Contract Only
Keep the Autoload thin. Do not paste full queue math here — implement in the script chosen above.
# turn_manager.gd (AutoLoad) — contract only
extends Node
signal turn_started(combatant: Node)
signal turn_ended(combatant: Node)
signal round_ended
signal turn_timed_out(combatant: Node) # multiplayer: server default-pass
func start_combat(participants: Array[Node]) -> void: pass
func end_turn() -> void: pass
func request_pass(combatant: Node) -> void: pass # default action on timeout
Networked Turn Timeout (Golden Path)
Referenced from NEVER: server owns the clock; clients never decide "pass."
- On
turn_started, server starts a one-shotTimer/SceneTreeTimer(authoritative). - On timeout: server calls
request_pass(current)(or auto-end-turn), then emitsturn_timed_out. - Clients only render the countdown; never mutate the turn queue locally.
- Pair with godot-multiplayer-networking for host-auth RPC.
Action Points (Contract)
func can_perform_action(cost: int) -> bool:
return current_action_points >= cost
func perform_action(cost: int) -> bool:
if not can_perform_action(cost):
return false
current_action_points -= cost
return true
Phases: prefer enum Phase { DRAW, MAIN, END } + match, or route to godot-state-machine-advanced. Full ATB / timeline math lives in the MANDATORY scripts — do not duplicate Elite snippets here.
Deep recipes (on demand)
LLM-ignorance rule: if a general agent would not know it before reading, it lives here or in
scripts/— never delete, only move.
| Topic | Reference |
|---|---|
| ATB / prediction / previews | elite-turn-patterns.md |
Reference
Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing work to a peer domain — do not preload the whole lattice.
Official Documentation
- Idle and Physics Processing — When turn ticks belong in
_processvs_physics_processvs pure event steps. - Using signals — Turn-start / turn-end / unit-acted events without polling gauges.
- Resources — Initiative/speed stats as Resources for sim and UI prediction.
- Singletons (Autoload) — TurnManager ownership boundaries.
- GDScript basics —
awaitsequencing for multi-phase turns. - Object — Signal connect flags for turn bus listeners.
- SceneTree — Pausing gameplay while menus resolve turn choices.
- Timer — Optional realtime turn clocks without busy loops.
- Tween — Animating ATB gauges and turn handoff juice.
- AnimationPlayer — Action animations that must finish before the next turn.
- MultiplayerAPI — Authoritative turn order in networked matches.
- JSON — Deterministic turn replay / seed logs for balance labs.
Related Skills
Prerequisites
- godot-project-foundations — Scene and Autoload placement for TurnManager.
- godot-signal-architecture — Turn bus contracts (signals up, commands down).
- godot-resource-data-patterns — Speed/initiative Resources shared with combat/UI.
- godot-autoload-architecture — Lifecycle of a global turn orchestrator.
Complements
- godot-state-machine-advanced — Per-unit states nested under turn phases.
- godot-combat-system — Actions resolved inside a granted turn.
- godot-rpg-stats — Speed/AGI feeding ATB gauges.
- godot-ability-system — Cooldowns measured in turns, not wall-clock only.
- godot-tweening — Gauge fill and handoff presentation.
- godot-multiplayer-networking — Host-auth turn order and lockstep.
Downstream / consumers
- godot-genre-action-rpg — ATB/turn hybrids in ARPG/JRPG-adjacent combat.
- godot-genre-card-game — Card turns and priority windows.
- godot-genre-rts — Discrete orders in strategy loops.
- godot-monte-carlo-balancer — Simulate turn matrices for speed/action fairness.
Master
- godot-master — Library router and mirrored module entry for turn systems.