Debug Terminal — Commands and Cheats - UQcsse3200/2026-studio-3 GitHub Wiki
Team 5 | Debug terminal wiring and cheat commands for fast manual testing | Related: Save/Load System · Debug Terminal Test Plan
The debug terminal (Terminal, KeyboardTerminalInputComponent, TerminalDisplay) already existed in the codebase, but was only ever wired into MainGameScreen — a screen no longer reachable in normal play. This meant the terminal was effectively dead: pressing F1 during an actual game session (map or battle) did nothing.
This work re-wires the existing terminal into the two screens players actually spend time in — BattleScreen and MapScreen — and adds a small set of cheat commands on top, so the team can test late-game content, specific bugs, or specific states without manually playing through a full run every time.
Press F1 on either the map or in battle to toggle the terminal open. Type a command (optionally with arguments) and hit Enter to run it. The terminal closes automatically after a successful command.
Commands are just Map<String, Command> entries on a Terminal component — see Terminal.addCommand(name, command). Adding a new one means implementing Command.action(ArrayList<String> args) and registering it where the terminal is created (BattleScreen.createUI() or MapScreen.createUi()).
The terminal accepts letters, digits, spaces, underscores, and hyphens as input — both matter since enum-based arguments (like ItemType names below) use underscores, and some newer string-ID arguments (like Chance encounter IDs) use hyphens.
graph TB
subgraph Screens["Screens (owners)"]
BattleScreen["BattleScreen"]
MapScreen["MapScreen"]
end
subgraph TerminalCore["Terminal Core"]
Terminal["Terminal<br/>(Component, holds command map)"]
KeyInput["KeyboardTerminalInputComponent<br/>(F1 toggle, keystrokes)"]
Display["TerminalDisplay<br/>(renders '> message' label)"]
end
subgraph Commands["Command implementations"]
DebugCmd["DebugCommand<br/>'debug on/off'"]
SkipCmd["SkipBattleCommand<br/>'skipbattle'"]
GoldCmd["GiveGoldCommand<br/>'givegold <amt>'"]
HealthCmd["SetHealthCommand<br/>'sethealth <amt>'"]
ItemCmd["GiveItemCommand<br/>'giveitem <ItemType>'"]
UnlockCmd["UnlockNodeCommand<br/>'unlocknode <id>'"]
ListCmd["ListNodesCommand<br/>'listnodes'"]
GotoCmd["GotoCommand<br/>'goto <floor> <roomtype>'"]
DiscoverCmd["DiscoverAllCardsCommand<br/>'discoverallcards'"]
end
subgraph GameSystems["Real game systems (cheats reuse, not fake)"]
BattleController["BattleController<br/>forceEnemiesDefeated()"]
Inventory["InventoryComponent<br/>addGold()"]
CombatStats["CombatStatsComponent<br/>setHealth()"]
ItemApplier["ItemEffectApplier<br/>applyItemEffect()"]
MapGraph["MapGraph<br/>connectNodes(), node state"]
MapSelection["MapSelectionController<br/>onNodeClicked()"]
CardDiscovery["CardDiscoveryService<br/>recordSeenAll()"]
end
BattleScreen -->|creates & attaches| Terminal
BattleScreen -->|attaches| KeyInput
BattleScreen -->|attaches| Display
MapScreen -->|creates & attaches| Terminal
MapScreen -->|attaches| KeyInput
MapScreen -->|attaches| Display
KeyInput -->|F1 toggles, keystrokes forwarded to| Terminal
Terminal -->|renders entered text via| Display
Terminal -->|processMessage looks up & runs| Commands
BattleScreen -.registers.-> DebugCmd
BattleScreen -.registers.-> SkipCmd
BattleScreen -.registers.-> GoldCmd
BattleScreen -.registers.-> HealthCmd
BattleScreen -.registers.-> ItemCmd
MapScreen -.registers.-> UnlockCmd
MapScreen -.registers.-> ListCmd
MapScreen -.registers.-> GotoCmd
MapScreen -.registers.-> DiscoverCmd
SkipCmd --> BattleController
GoldCmd --> Inventory
HealthCmd --> CombatStats
ItemCmd --> ItemApplier
UnlockCmd --> MapGraph
ListCmd --> MapGraph
GotoCmd --> MapGraph
GotoCmd --> MapSelection
DiscoverCmd --> CardDiscovery
-
debug on/debug off— toggles physics debug rendering (colliders). Pre-existing command. On the map screen, this also reveals node ID and floor labels above every node (see below).
-
skipbattle— instantly wins the current battle. Deals piercing damage (bypasses block/armour, same as a real killing blow) to every enemy, then lets the normal battle-outcome check fire naturally — this reuses the real win path (queueBattleOutcomeIfOver()), rather than faking a VICTORY transition directly. Required a small addition toBattleTransitions(PLAYER_TURN → ENEMIES_DEFEATED → VICTORY), since every other phase already allowed this transition but the idle player-turn phase didn't. -
givegold <amount>— adds gold to the player'sInventoryComponent. -
sethealth <amount>— sets the player's current health viaCombatStatsComponent. -
giveitem <ItemType>— applies an item's effect directly via the existingItemEffectApplier, without needing to win it as a battle reward (e.g.giveitem ENERGY_CRYSTAL). Takes anyItemTypeenum name, so new item types added later this sprint are automatically supported with no command changes.
-
unlocknode <id>— unlocks a specific node (LOCKED → AVAILABLE) and connects it to the player's current node. Flipping state alone isn't enough:MapGraph.moveToNode()also requires the target to be a real graph connection of the current node, not justAVAILABLE, otherwise the node visually reacts to a click but nothing happens. -
listnodes— logs every node's id, floor (height), room type, and state to the console/log output (not the in-game terminal display, which only shows the current typed input). -
goto <floor> <roomtype>— jumps directly to a node matching a given floor and room type (e.g.goto 3 combat,goto 5 elite,goto 2 campfire), going through the real click entry point (MapSelectionController.onNodeClicked()) rather than faking a screen transition — so the actual production encounter-selection logic runs exactly as it would from a real click. Skips nodes that are alreadyCOMPLETEDor the player's current position, so repeated calls on the same floor/type find a fresh match instead of silently failing on an already-visited node. Works for everyRoomTypethat exists on the current map, including Campfire and Elite — no per-room-type command was ever needed, since this just finds and clicks a matching node generically. -
discoverallcards— reveals every card in the library, marking each asSEENviaCardDiscoveryService.recordSeenAll(). Requested by Team 6 (Ray) to test the new card discovery UI without playing through a full run to naturally encounter every card (shop and chance encounters are currently the only discovery routes). Note: this only changesCardDiscoveryServicestate — to see the result, navigate to Main Menu → Library → Card Library afterward (the terminal isn't reachable from those screens).
Since map layouts (and node IDs/floors) regenerate on every new run, there's no fixed reference for "which ID is which node" or "which floor is this." Running debug on on the map screen shows each node's ID and floor/height directly above it on screen (e.g. 27 (h4) — node 27, floor 4), toggled off again by debug off. This is what makes unlocknode/listnodes/goto actually usable without digging through save files or logs.
-
Underscore input dropped:
KeyboardTerminalInputComponentoriginally only accepted letters, digits and space, silently dropping underscores. This meantItemTypenames likeENERGY_CRYSTALcouldn't actually be typed. Fixed by widening the accepted character set. -
Hyphen input remains unsupported:
KeyboardTerminalInputComponentcurrently accepts letters, digits, spaces and_, but not-. Therefore a future hyphenated command such asstart-eventcannot be exposed through the current terminal input until hyphen handling and its test are added. See Debug Terminal Test Plan. -
Terminal text hidden behind the hand:
TerminalDisplay's label could render behind newly-dealt hand cards — same root cause as the earlierCardEffectDebugDisplayz-order issue, since the hand gets rebuilt on the same stage every time a card is played. Fixed withlabel.toFront()on every draw while the terminal is open. - Terminal text unreadable: originally rendered in the skin's default black, invisible against the map/battle backgrounds. Now explicitly white.
-
Map nodes visually frozen after a state change without a screen transition:
MapNodeActor.checkNodeState()only ever ran once, at construction — it "worked" only by coincidence, since every real state change previously came bundled with a full screen rebuild (entering then returning from an encounter).goto/unlocknodemutate node state directly, with no screen transition, which exposed this: nodes wouldn't visually update at all. Fixed with anact()override that re-checks state every frame, and by resetting to baseline styling before applying each state's specific styling (the original switch only ever added dimming/enlarging, never restored it).
- Cheats are currently only wired into
BattleScreenandMapScreen— not the shop/event encounter screen. - Hyphenated input is currently rejected; use the documented command names only until the input contract is extended and tested.
- No precise deck-manipulation commands yet (
give-card <id>requested by Team 2, not yet built — no blocker,PlayerDeck.addCard(String cardId)already exists for it). -
GdxGame.startEvent(String)is available onmain, but thestart-event <eventId>terminal command was deferred and is not part of the submitted build. Integrating it later still requires hyphen input support, tests and review. -
listnodesoutput goes to console, not the in-game terminal — could be improved to print inline if that becomes annoying during testing.