- Delete portal_mode_manager.gd, portal_door.gd, portal_door.tscn - Strip all Tekton Doors logic from main.gd, player.gd, lobby.gd, lobby_room.gd, lobby_manager.gd, camera_context_manager.gd, music_manager.gd, tekton.gd, enhanced_gridmap.gd, playerboard_manager.gd, special_tiles_manager.gd - Remove TK enum (TEKTON_DOORS=2), mode_config schema, arena area - Update tests: 3 modes instead of 4 - Strip HowToPlay tab from main.tscn
26 KiB
Game Modes
Table of Contents
- Overview
- Architecture
- GameMode Enum & ModeConfig
- Session Flow (all modes)
- Core Managers (shared)
- Freemode
- Stop n Go
- Tekton Doors (Portal)
- Candy Pump Survival (Gauntlet)
- Scoring & Leaderboard
- Glossary
- File Index
Overview
Four game modes, each implementing the same core loop — players navigate a grid, collect tiles (Heart / Diamond / Star / Coin), match them to goals on a virtual 5x5 playerboard, and compete for score before the match timer expires.
| Mode | Enum Value | Display Name | Play Area | Gimmick |
|---|---|---|---|---|
| Freemode | FREEMODE = 0 |
"Freemode" | Variable | No restrictions, just goals + timer |
| Stop n Go | STOP_N_GO = 1 |
"Stop n Go" | 23x12 | GO/STOP phases, safe zones, scatter penalty |
| Tekton Doors | TEKTON_DOORS = 2 |
"Tekton Doors" | 14x14 | 4 rooms, portal doors swap connections every 15s |
| Candy Pump Survival | GAUNTLET = 3 |
"Candy Pump Survival" | 20x20 | Ground growth — candy slowly fills the arena |
Architecture
GameMode (enum/RefCounted)
├── .from_string() / .mode_to_string() / .is_restricted() / .get_all_modes()
│
├── ModeConfig (RefCounted)
│ └── SCHEMA with defaults, type-checking, min/max for each mode
│
├── GoalsCycleManager (Node, autoload?)
│ ├── 30s cycle timer
│ ├── Match timer (configurable 60-600s)
│ ├── Score tracking (player_scores, player_goal_counts)
│ ├── Goal completion: _process_goal_completion()
│ └── RPC sync: sync_player_score, sync_goal_count, sync_timer
│
├── GoalManager (Node)
│ ├── initialize_random_goals() — generates 9-slot goal patterns
│ ├── Speed tracking (completion_times, boost_multiplier)
│ └── generate_preset_goals() / get_goals_for_player()
│
├── PlayerRaceManager (per-player)
│ ├── goals: Array[int] (9 slots)
│ ├── playerboard: Array[int] (25 slots, 5x5)
│ ├── check_pattern_match() — core matching logic
│ └── DEPRECATED lap/finish-line stubs
│
├── PlayerboardManager (per-player)
│ ├── grab_item() / auto_put_item() / arrange operations
│ ├── _execute_grab() — server-authoritative grab validation
│ ├── HIDDEN_SLOTS (12 of 25 cells blocked)
│ ├── bot_try_grab_item() — AI grab logic
│ └── _check_and_refill_grid_if_needed() — scarcity refill
│
├── TurnManager (shared)
│ ├── next_turn() / end_current_turn()
│ └── turn_based_mode toggle
│
└── Mode-specific managers
├── StopNGoManager — phase transitions, safe zones, mission HUD
├── PortalModeManager — room partitions, portal doors, swap timer
└── GauntletManager — ground growth, phases, bubbles, smack
All mode managers live under /root/Main and connect to GoalsCycleManager signals for score / goal tracking.
GameMode Enum & ModeConfig
File: scripts/game_mode.gd (41 lines)
enum Mode { FREEMODE = 0, STOP_N_GO = 1, TEKTON_DOORS = 2, GAUNTLET = 3 }
| Static Method | Returns | Description |
|---|---|---|
from_string(mode: String) |
Mode |
Converts "Freemode"/"Stop n Go"/"Tekton Doors"/"Candy Pump Survival" to enum |
mode_to_string(mode: Mode) |
String |
Reverse of from_string |
is_restricted(mode: Mode) |
bool |
true for STOP_N_GO, TEKTON_DOORS, GAUNTLET |
get_all_modes() |
Array[String] |
Returns display names |
File: scripts/mode_config.gd (109 lines)
SCHEMA defines per-mode settings with type, default, min, max, allowed values:
| Mode | Settings |
|---|---|
| Freemode | match_duration (180s default), randomize_spawn (bool), enable_cycle_timer (bool), scarcity_mode (Normal/Aggressive/Chaos) |
| Stop n Go | match_duration, sng_go_duration (20s), sng_stop_duration (4s), sng_required_goals (8) |
| Tekton Doors | match_duration, doors_swap_time (15s), doors_refresh_time (25s), doors_required_goals (8) |
| Gauntlet | match_duration, gauntlet_growth_interval (3.0s), gauntlet_cells_per_tick (phase dict) |
| Method | Args | Returns |
|---|---|---|
get_defaults(mode) |
String | Dictionary of defaults for that mode |
validate_setting(mode, key, value) |
String, String, Variant | {"valid": bool, "error": String} |
validate_config(mode, config) |
String, Dictionary | {"valid": bool, "errors": Array} |
get_mode_settings(mode) |
String | Array of setting keys |
get_setting_schema(mode, key) |
String, String | Dictionary with type/default/min/max/allowed |
Session Flow (all modes)
- Lobby — players join, select mode + settings
- Game start —
main.gdcalls_setup_host_game()which:- Creates arena (gridmap resize + clear)
- Spawns mission tiles on Layer 1
- Calls mode manager's
start_game_mode()
- Countdown — brief timer then match begins
- Match active —
GoalsCycleManager.start_match()runs match timer + cycle timer - Per-cycle (30s):
- Players grab tiles from grid → place on 5x5 playerboard
- Match 3x3 pattern against 9-slot goals
- Complete goals → B1000 score + new goals + tiles randomize around player
- Cycle ends → board cleared, unmatched tiles scored at 10/tile match
- Match ends — final leaderboard sync
Core Managers (shared)
GoalManager (scripts/managers/goal_manager.gd, 108 lines)
Generates 9-slot goal arrays using tile IDs 7-10 (Heart=7, Diamond=8, Star=9, Coin=10) with -1 for no-goal slots (~3 nulls per set).
| Function | Returns | Description |
|---|---|---|
initialize_random_goals(size, min_value, max_value, null_count) |
Array |
Random goals with controlled null distribution |
generate_preset_goals(count) |
Array |
Pre-generates N goal sets for all players |
get_goals_for_player(player_index) |
Array |
Returns goals for a specific player slot |
mark_goal_start(player_id) |
void | Records timestamp for speed tracking |
mark_goal_complete(player_id) |
void | Records completion duration |
get_player_average_time(player_id) |
float |
Average completion speed |
get_global_average_time() |
float |
Average across all players |
get_boost_multiplier(player_id) |
float |
0.8-1.5x fill rate based on speed vs average |
reset() |
void | Clears all state |
GoalsCycleManager (scripts/managers/goals_cycle_manager.gd, 520 lines)
Central scoring and timer system. Emits signals consumed by mode managers, UI, and leaderboard.
| Signal | Payload |
|---|---|
cycle_started() |
— |
cycle_ended() |
— |
timer_updated(time_remaining) |
float |
score_updated(peer_id, new_score) |
int, int |
goal_count_updated(peer_id, count) |
int, int |
leaderboard_updated(sorted_scores) |
Array |
match_started() |
— |
match_ended() |
— |
global_timer_updated(time_remaining) |
float |
| Function | Description |
|---|---|
start_match(duration_seconds, start_cycles) |
Begins match timer, optionally starts first 30s cycle |
_on_match_end() |
Processes final scores, syncs to clients |
start_cycle() |
Begin 30s cycle, emit cycle_started |
on_goal_completed(player, time_remaining) |
Entry point — routes to server or optimistic local path |
_process_goal_completion(player, time_remaining) |
Server: award B1000 + time bonus, regen goals, randomize tiles |
regenerate_goals_for_player(player) |
Generate new 9-slot goal set, sync via RPC |
_randomize_tiles_around_player(player) |
Randomize 3x3 area around player on the grid |
_process_cycle_end_for_all_players() |
Clear all boards, convert matches to B10/tile |
add_score(peer_id, amount) |
Server: add arbitrary score points |
_update_leaderboard() |
Sort by score descending (or with SNG winner override) |
PlayerRaceManager (scripts/managers/player_race_manager.gd, 133 lines)
State holder per player. Core logic is check_pattern_match().
| Function | Description |
|---|---|
check_pattern_match() |
Returns true if any 3x3 sub-grid of 5x5 board matches 3x3 goals |
check_3x3_section(board, goals, start_row, start_col) |
Checks single 3x3 section |
_normalize_tile(tile) |
Converts holo tiles 11-14 → 7-10 for match comparison |
| Remaining functions | DEPRECATED lap/finish line stubs |
Playerboard Layout: 5x5 (indices 0-24). 13 cells are HIDDEN_SLOTS (cannot hold tiles). Only 12 usable slots arranged in an L-shape matching the HUD.
PlayerboardManager (scripts/managers/playerboard_manager.gd, 793 lines)
Handles grab, put, arrange operations with optimistic local updates + server-authoritative validation.
| Function | Description |
|---|---|
grab_item(grid_position) |
Grab tile from grid → place on board (auto-arrange) or consume as power-up |
_execute_grab(grid_pos, cell, item_id, expected_slot) |
Server-side validation + state update + sync |
_force_sync_to_client(cell, server_item) |
Revert client when server rejects grab |
auto_put_item() |
AI/bot: find best tile to remove from board |
find_best_goal_slot_for_item(item) |
Auto-arrange into best matching slot |
bot_try_grab_item() |
AI grab logic |
_check_and_refill_grid_if_needed(gridmap) |
Refill floor 1 via ScarcityController when empty |
TurnManager (scripts/managers/turn_manager.gd, 27 lines)
| Function | Description |
|---|---|
next_turn(players) |
Advance turn index, emit turn_changed |
end_current_turn() |
Emit turn_ended |
reset_turn() / reset() |
Clear state |
Freemode
No dedicated manager. Freemode relies entirely on the shared core managers (GoalsCycleManager, PlayerboardManager, etc.) with no mode-specific restrictions or gimmicks. Arena size is configurable via LobbyManager settings.
Settings effects:
enable_cycle_timerfalse → cycle never expires (board never auto-clears)scarcity_mode→ controls tile refill aggressionrandomize_spawn→ players start at random positions
Stop n Go
Manager: StopNGoManager (scripts/managers/stop_n_go_manager.gd, 1107 lines)
A 23x12 arena with two alternating phases:
Phase System
| Phase | Duration (default) | Behaviour |
|---|---|---|
| GO | 20s | Players move freely, collect tiles, complete goals |
| STOP | 4s | Players frozen if outside safe zone → tiles scattered |
When STOP begins:
- 3 dynamic safe zones spawn randomly (green tiles)
- All players outside safe zone get
_scatter_player_tiles()— board tiles scattered on grid - Power-up tiles (Speed=11, Ghost=14) spawn at 5 permanent locations
- Mission requirement: complete 8 goals before reaching finish (x=22)
When GO begins:
- Dynamic safe zones cleared
- All STOP freeze effects removed via
sync_stop_freeze(false)
Tile IDs
| ID | Meaning |
|---|---|
| 0 | Walkable floor |
| 2 | Safe zone (green) |
| 3 | Start/Finish line |
| 4 | Wall/obstacle |
| 15 | Lightning stone (decorative ancient rock) |
| 16 | Safe zone wall |
Arena
22x10 walkable area with two interior rooms with entrances:
- Room 1: (7,6) to (11,9) — 5x4 area with 4 door entrances
- Room 2: (15,1) to (19,5) — 5x5 area with 4 door entrances
HUD
- Center-bottom mission label: "GOALS (X/8)" or "ALL GOALS COMPLETE! REACH THE FINISH!"
- Traffic light stop timer (3 segments): all empty during GO, fills red during STOP phase
- Last 3 seconds of GO phase: segments light up one-by-one (countdown)
- VFX:
vfx_manager.play_go_animation()/play_stop_phase()
RPCs
| RPC | Direction | Description |
|---|---|---|
sync_phase(phase_name, duration) |
Authority → all | Broadcast GO/STOP phase change |
sync_arena_setup() |
Authority → remote | Sync 23x12 grid dimensions + obstacles |
sync_all_safe_zones_vfx() |
Authority → all | Trigger safe zone visual effects |
Key Functions (server-only unless noted)
| Function | Description |
|---|---|
start_game_mode() |
Server: setup arena, assign missions, start GO phase |
_start_phase(phase) |
Transition GO↔STOP, penalize players outside safe zone |
_setup_arena() |
Build 23x12 with obstacles + rooms |
_spawn_mission_tiles() |
Heart(7)/Diamond(8)/Star(9)/Coin(10) at 60% density |
_spawn_powerup_tiles() |
Speed(11)+Ghost(14) at 5 permanent locations |
_assign_missions() |
NO-OP (mission = achievement: collect 8 goals) |
activate_client_side() |
Client: show HUD, connect to GoalsCycleManager signals |
rotate_players_to_start() |
Force all players to face East (PI/2) |
can_rpc() |
Check multiplayer peer is connected |
Tekton Doors (Portal)
Manager: PortalModeManager (scripts/managers/portal_mode_manager.gd, 585 lines)
Actor: PortalDoor (scripts/portal_door.gd, 136 lines)
A 14x14 grid divided into 4 rooms (7x7 each) by cross-shaped wall partitions. Players move between rooms via portal doors that swap connections every 15 seconds.
Room Layout
Room 0 (NW) | Room 1 (NE)
x: 0-6 | x: 7-13
z: 0-6 | z: 0-6
--------------+--------------
Room 2 (SW) | Room 3 (SE)
x: 0-6 | x: 7-13
z: 7-13 | z: 7-13
Central divider: columns 6,7 and rows 6,7 are walls (tile ID 4).
Portal System
- 10 doors total (2 base per room + 2 randomly placed extras)
- Every 15s (
doors_swap_time):_randomize_connections()shuffles pairings - Each pair gets a color from
PORTAL_COLORS(Cyan/Magenta/Red/Green/Orange) - Validation ensures no pair connects doors in the same room
- 200ms anti-jitter cooldown per player in
handle_portal_interaction()
PortalDoor (actor)
| Property/Method | Description |
|---|---|
room_id |
Which room this door belongs to |
door_id |
Unique door index |
target_door_id |
Connected door (set by PortalModeManager) |
portal_color |
Color (set triggers set_portal_color) |
detection_area |
Area3D — body_entered triggers portal |
_on_body_entered(body) |
200ms cooldown, emit player_entered_portal |
spawn_offset |
Vector2i meta — nudge spawn position into room |
_adjust_indicator_position() |
Move GroundIndicator toward room interior |
Finish Room
- At 30s remaining on match timer, reveal
_spawn_finish_room() - Random 3x3 area converted to finish tiles (ID 3) in one room
- Player must be standing on finish tile AND have
doors_required_goalscomplete
Tile Refill
- Every 25s (
tile_refresh_time):_refresh_tiles()refills Floor 1 at 60% density - Uses
ScarcityModel.get_tile_weights()for weighted random selection - Avoids spawning under portal doors
HUD
- Center-bottom: "GOALS (X/8)" or "ALL GOALS COMPLETE! FIND THE FINISH ROOM!"
- Message broadcasts: "PORTALS SWITCHED!", "TILES REPLENISHED!"
- Warning: "A 3x3 Finish Zone has appeared in Room N!"
RPCs
| RPC | Direction | Description |
|---|---|---|
sync_portal_data(data) |
Authority → local | Sync connections + colors to all clients |
sync_portal_configs(door_configs) |
Via main | Broadcast door positions/rotations |
Key Functions
| Function | Description |
|---|---|
initialize(p_main, p_gridmap) |
Create swap timer + tile refresh timer, connect signals |
start_game_mode() |
Setup arena, randomize connections, start timers |
setup_arena_locally() |
Resize to 14x14, build room walls, spawn portal doors |
_randomize_connections() |
Shuffle door pairings, assign colors, validate same-room rule |
handle_portal_interaction(player, door) |
Teleport player to connected door + offset |
_spawn_finish_room() |
Convert random 3x3 area to finish tiles |
check_win_condition(player_id, pos) |
Check finish tile + mission complete |
_refresh_tiles() |
Refill floor 1 items with scarcity weights |
sync_to_client(peer_id) |
Sync portal connections to late-joining client |
get_spawn_points() |
Returns 4 spawn positions (one per room quadrant) |
Candy Pump Survival (Gauntlet)
Manager: GauntletManager (scripts/managers/gauntlet_manager.gd, 1825 lines)
A 20x20 arena where sticky candy (pink) slowly grows from the edges inward over 3 phases. Players must navigate shrinking safe zones, avoid sticky tiles, and use the "Smack" ability to temporarily clear candy.
Phase System
| Phase | Start | Duration | Cell Growth (per tick) | Description |
|---|---|---|---|---|
| OPEN_ARENA (0) | 0s | 60s | 4-6 | "Outer Pressure" — candy pushes from perimeter |
| ROUTE_PRESSURE (1) | 60s | 60s | 6-8 | "Middle Pressure" — corridors tighten |
| SURVIVAL_ENDGAME (2) | 120s | 60s | 8-10 | "Inner Survival" — center fills in |
Each phase transition shrinks the arena bounds by removing outer layers (via _shrink_arena()).
Growth Algorithm
Each tick (every growth_interval = 3s):
- Detect movement buffers — identify critical corridor cells (#083)
- Generate candidates — all SAFE cells scored by formula:
CandidateScore = LayerPriority + StickyNeighbor + InwardPressure + PlayerPressure + ClusterGrowth + CampingPressure + RandomNoise(-20..+20) + MovementBuffer + PathSafety + Repetition - Weighted selection — pick
_cells_this_tick()cells via roulette wheel - Path safety check —
_apply_path_safety()ensures no player gets fully trapped - Telegraph — amber warning overlay appears for 1s (cells still passable)
- Apply — cells convert to permanent STICKY (pink overlay on Layer 2)
Scoring Components
| Score Component | Range | Description |
|---|---|---|
_score_layer_priority |
-40..+60 | Phase weight by ring (outer/middle/inner) |
_score_sticky_neighbor |
0..+64 | +8 per adjacent sticky cell (cap +64) |
_score_inward_pressure |
0..+30 | Push inward, scales with phase |
_score_player_pressure |
-50..+20 | 2-4 cells away +20; under player -50 (+10 in final 30s) |
_score_cluster_growth |
0..+25 | +15 expansion, +25 bridge between clusters |
_score_camping_pressure |
0..+60 | Per-region: >5s +20, >8s +40, >10s +60 |
_score_movement_buffer |
-40..0 | Hidden corridor buffers + player proximity floor |
_score_path_safety |
-100..0 | Soft penalty if selection would strand a player |
_score_repetition |
-30..0 | Penalty for cells near last tick's selection |
Cell States
| State | Meaning | Passable? |
|---|---|---|
| SAFE | Normal floor | Yes |
| TELEGRAPHED | Amber warning (1s) | Yes |
| STICKY | Permanent candy overlay | No (slows) |
| BUBBLE_GROWING | Candy bubble expanding | No |
| BLOCKED | NPC zone / permanent obstacle | No |
Candy Bubble System (#082)
Anti-camping hazard: grows 1x1 → 3x3 sticky area.
| Phase | Max Bubbles |
|---|---|
| OPEN_ARENA | 0 (disabled) |
| ROUTE_PRESSURE | 2 |
| SURVIVAL_ENDGAME | 3 |
| Property | Value |
|---|---|
| Grow duration | 2.75s |
| Explosion radius | 1 (3x3) |
| Recent memory | 4 positions |
| Anti-stack radius | 3 (no bubbles within 3 of recent) |
Camping Detection (#073)
Players tracked in 4x4 regions. Time accumulates while player stays in same region, resets on region change. Drives camping pressure in candidate scoring.
Movement Buffers (#083)
Hidden per-cell penalties on critical corridor cells (chokepoints where removing the cell would isolate part of the arena). Decay over time and phase transitions so arena can still close in.
Smack Mechanic
| Property | Value |
|---|---|
| Cooldown | 8s |
| Charge window | 3s |
| Effect | Clears nearby sticky? (consumes charge) |
Per-player cooldown/charge tracked in smack_cooldowns / smack_charged Dictionaries. Pink modulate during charge window, white on cooldown.
Arena NPC
Candy Pump NPC at center (9,9) in a 3x3 blocked zone. Visual-only in v2 (projectile logic removed). Scattered projectiles still spawned for visual effect during telegraph phase.
Slow-Mo
- Triggered conditionally, duration 4s
Engine.time_scale = 0.25(1/4 speed)- Restored to 1.0 in
_exit_tree()
Spawn Points
| Player Count | Positions |
|---|---|
| 4 | 4 corners: (1,1), (18,1), (1,18), (18,18) |
| 5-6 | 4 corners + top-mid (10,1) + bottom-mid (10,18) |
| 7-8 | 4 corners + all 4 mid-edges |
RPCs
| RPC | Direction | Description |
|---|---|---|
sync_phase(phase_index, phase_name) |
Authority → local | Phase change broadcast |
sync_arena_setup() |
Authority → remote | Arena dimensions + layout |
sync_growth_telegraph(cells) |
Authority → local | Show amber warning on selected cells |
sync_growth_apply(cells) |
Authority → local | Convert telegraphed to sticky |
consume_smack(pid) |
Any peer → local | Smack consumption + animation |
sync_stop_freeze |
(inherited from player.gd) | Freeze/unfreeze player |
Key Functions
| Function | Description |
|---|---|
initialize(main, grid) |
Connect to GoalsCycleManager |
start_game_mode() |
Activate client side, start OPEN_ARENA phase |
_setup_arena() |
Build 20x20, spawn Candy Pump NPC |
_process_growth_tick() |
One growth cycle: score → select → telegraph → apply |
_generate_candidates() |
Score all SAFE cells |
_calculate_candidate_score(pos, player_cells) |
Full formula with 10 components |
_select_cells_weighted(candidates, count) |
Roulette-wheel selection |
_apply_path_safety(selected) |
Filter: ensure no player stranded |
_try_spawn_bubble() |
Anti-camping bubble spawn attempt |
_update_camp_tracking(delta) |
Per-player region residency timer |
_detect_movement_buffers() |
Identify critical corridor chokepoints |
_shrink_arena() |
Remove outer arena layers on phase change |
_spawn_mission_tiles() |
Heart/Diamond/Star/Coin at 60% density |
get_spawn_points(player_count) |
Return spawn positions by player count |
has_smack_charged(pid) / consume_smack(pid) |
Smack mechanic |
_spawn_telegraph_highlight(pos) |
Amber glow visual (2-stage: build-up + flash) |
_spawn_impact_particles(targets) |
Candy splash particles on sticky impact |
_check_all_players_trapped() |
Re-evaluate sticky traps after growth apply |
Scoring & Leaderboard
| Action | Points |
|---|---|
| Complete goal pattern (match 3x3) | B1000 + time bonus |
| Tile match at cycle end (per tile) | B10 |
| Time bonus formula | int(time_remaining * TIME_BONUS_MULTIPLIER) — currently 0 (flat 1000) |
Leaderboard sorted descending. Stop n Go special case: winner (first to reach finish) placed at top regardless of score.
Leaderboard signal payload:
[{"peer_id": int, "score": int}, ...]
Glossary
| Term | Definition |
|---|---|
| Goal | 3x3 pattern (9 slots, some -1 for null) player must match on their playerboard |
| Playerboard | 5x5 virtual grid (12 usable slots, 13 hidden) per player |
| Tile | Grid item on Floor 1: Heart(7), Diamond(8), Star(9), Coin(10) |
| Holo Tile | Power-up tiles: Speed(11), Ghost(14) — consumed on pickup, not placed on board |
| Cycle | 30-second scoring round; ends with board clear + point conversion |
| Sticky | Permanent pink overlay on Gauntlet floor cells — blocks/slows movement |
| Telegraph | Amber 1-second warning before a cell becomes sticky |
| Safe Zone | Green tiles in Stop n Go STOP phase — only safe tile type |
| Portal | Colored door connecting rooms in Tekton Doors |
| Scarcity | Tile refill model controlling spawn weights based on mode config |
| Smack | Gauntlet ability: clear nearby sticky (8s cooldown, 3s charge window) |
| Camping | Player staying in same 4x4 region >5s, attracts growth pressure |
| Movement Buffer | Hidden chokepoint corridor that growth algorithm avoids sealing early |
| Chebyshev Distance | `max( |
File Index
| File | Lines | Role |
|---|---|---|
scripts/game_mode.gd |
41 | Mode enum + helper functions |
scripts/mode_config.gd |
109 | Schema-driven per-mode settings |
scripts/managers/goal_manager.gd |
108 | Goal generation + speed tracking |
scripts/managers/goals_cycle_manager.gd |
520 | Timer, scoring, cycle control |
scripts/managers/player_race_manager.gd |
133 | Per-player state: goals, board, pattern matching |
scripts/managers/playerboard_manager.gd |
793 | Grab/put/arrange operations |
scripts/managers/turn_manager.gd |
27 | Turn-based flow |
scripts/managers/stop_n_go_manager.gd |
1107 | Stop n Go phase system, safe zones, HUD |
scripts/managers/portal_mode_manager.gd |
585 | Tekton Doors room layout, portals, tiles |
scripts/managers/gauntlet_manager.gd |
1825 | Candy Pump Survival growth, phases, smack |
scripts/portal_door.gd |
136 | PortalDoor actor — detection, teleport, visuals |
scripts/managers/goals_cycle_manager.gd |
(shared) | Also referenced by gauntlet signal connections |
scripts/managers/camera_context_manager.gd |
... | Camera mode changes per game mode? |
scripts/managers/player_movement_manager.gd |
... | Movement restrictions per mode |