34 KiB
Node System (节点系统)
Status: Revised — post-design-review fixes applied (edge divergence, economy, Boss scaling, Assembly Phase entry, Boss color, Coin sink, AC gaps) Author: SepComet + agents Last Updated: 2026-04-30 (post-review revisions: edge level variants, first-shop tiering, Boss nodesCompleted scaling, Assy Phase auto-enter, Boss VFX color, Coin sink clarification, AC gaps filled) Implements Pillar: Core game loop navigation — players drive their own path through the run
Overview
The Node System is the run-level navigation layer that structures a complete playthrough. A run consists of exactly 10 sequential nodes. The player advances through nodes one at a time, choosing which available node to tackle next. After each node resolves, the player enters a brief assembly phase to reconfigure their towers before committing to the next node.
Node types:
- Combat Node: Triggers a wave-based tower defense battle via
CombatNodeComponent. The player earns Gold (persistent run currency) and component drops based on performance. - Event Node: Presents a branching choice with risk/reward outcomes. No combat; purely decision-based.
- Shop Node: Opens the component store for purchasing upgrades between battles.
- Boss Node (Node 10): A combat node with higher difficulty and guaranteed valuable drops — the run's climax.
Currency note: This GDD distinguishes two currencies. Gold is the persistent run-level currency earned from combat nodes and spent at Shop nodes. Coin is a combat-internal currency earned per combat round and spent within a single combat encounter on tower building and other intra-combat actions — Coin does not persist between nodes and is exclusive to the CombatNode domain. The Coin sink is defined in the CombatNode design; Coin has no interaction with Gold or the shop system.
Node graph structure: The node graph is a linear track with one branch per node. At each node entry, the player is shown the available outgoing edge(s) and must choose which node to enter next. There is no convergence/merging of paths within a run — the player advances linearly, not across branching tracks. The two edges at each junction lead to the same node type but offer different level variants (distinct map layouts, enemy compositions, or environmental conditions) — creating strategic divergence through topology and threat profile rather than through node-type variety.
Node type generation: Node types follow a fixed sequence (not randomized) per run. The sequence for the default (Plain theme) is: Combat → Combat → Combat → Shop → Combat → Event → Combat → Shop → Combat → BossCombat. Events are restricted to positions 4–8 only. Future themes may define their own fixed sequences. Players cannot choose or reroll node types. The two outgoing edges from each node lead to distinct level variants of the next node type, not to different node types.
Player Fantasy
"I feel like a tactician executing a plan through hostile terrain — the route is set, but how I prepare and when I commit my forces determines whether I survive."
The Node System delivers the fantasy of tactical navigation under pressure. The player is a tactician with a fixed route ahead — they know what kinds of challenges await (the full node track and boss are visible at run start), but at each junction they choose which of two paths to commit to. The core feeling is the weight of tactical commitment: selecting a path means locking in your approach. You can see the Boss at Node 10 glowing at the end, and you know the full track from the start — but the question is whether the resources and tower builds you've chosen will be sufficient to reach it intact.
The player should feel:
- Preparing and adapting — using Assembly Phases to optimize tower builds based on known upcoming challenges; choosing path segments that complement the components in hand
- The weight of commitment — once you enter a node, the choice is locked; there's no undoing or backtracking within a run
- Building toward a climax — each node brings the player closer to the Boss; the 10-node arc creates mounting tension toward the run's inevitable crescendo
- Satisfaction when the plan holds — the run "reads" as a coherent story in retrospect: "I invested heavily in early towers, conserved resources mid-run, and deployed my best assembly for the Boss"
Reference: Into the Breach's "visible consequences of choices" feeling — the player can see what lies ahead (both edge destinations and their level variants) and must prepare accordingly. The Geometry TD node system achieves this through the fixed Boss at Node 10, the linear-but-choiced track structure where the two outgoing edges present different level variants of the next node, and the Assembly Phase where the player configures their towers for the known upcoming challenge. Resource timing and build optimization matter more than node-type gambling — but the specific level variant encountered is also shaped by the player's path choice.
Detailed Design
Core Rules
Run Structure
- A run consists of exactly 10 sequential nodes. Node 10 is always a Boss Combat node.
- Node types follow a fixed sequence per theme (see Node Type Generation above). The player cannot choose or reroll node types.
- The run graph is strictly forward-only: no backtracking, no skipping nodes, no retries of completed nodes.
Node Entry Flow 4. Player arrives at a node. The node resolves based on type:
- Combat / Boss:
CombatNodeComponent.StartCombat()is called by the Procedure layer. On victory, player receives Coin, component drops, and Gold. - Event: Branching choice presented. Player selects an option; risk/reward resolves immediately.
- Shop: Shop interface opens. Player buys/sells components. Player exits freely.
- Node resolves. Assembly Phase is automatically entered after every node resolves. Player interaction within it is optional — the "Ready" button can be clicked immediately to proceed, or the player may re-enter freely before selecting the next node. Assembly Phase is never skipped; it is a mandatory transit point, not a mandatory modification point.
- Assembly Phase: Player can swap any component on any tower, reorganize inventory, and review current stats. Player confirms "Ready" to proceed to node choice, or may re-enter Assembly Phase freely before selecting the next node.
- Assembly Phase ends (player-initiated or via "Ready" confirmation). The 2 outgoing edge destinations from the completed node are revealed (node types shown).
- Player selects one destination. The chosen edge is locked in. Player travels to the next node.
- Repeat steps 4–8 until Node 10 (Boss) is reached.
Combat Loss Rules
10. Any combat loss: Run ends in failure immediately. There is no continuation after a combat loss — the run concludes at the point of failure. This applies to both regular Combat nodes and the Boss node. Node is marked as RunNodeStatus.Exception in the run state on loss.
Data Persistence 11. Within a run: Inventory, Repository, Gold, Coin, Tower configs, visited node history, and active buffs/debuffs persist across nodes. 12. Between runs: All of the above reset to starting values. Only permanent meta-progression (unlocks, permanent upgrades) persists.
NodeComponent — Ownership and Interface
15. There is no NodeComponent class. Run-level orchestration is handled by the Procedure layer via RunStateAdvanceService and RunState.
16. The Procedure layer calls CombatNodeComponent.StartCombat() only after the Assembly Phase is confirmed complete.
17. CombatNodeComponent fires NodeCompleteEventArgs (with CombatWon field) after combat resolves. The Procedure layer receives this event and drives state transitions via RunStateAdvanceService.TryCompleteCurrentNode.
States and Transitions
| State | Description | Exits |
|---|---|---|
RunIdle |
Pre-run, at main menu. Player not yet in a run. | → NodeReveal on "Start Run" |
NodeReveal |
Outgoing edges from current node are displayed. Player makes a choice. | → NodeTransition on choice confirmed |
NodeTransition |
Player travels to the chosen destination node. | → NodeEntry |
NodeEntry |
Player arrives at the node. Node-type logic triggers (Combat/Event/Shop/Boss). | → AssemblyPhase on node resolved |
AssemblyPhase |
Full tower assembly enabled. Player may enter/exit freely. Player confirms "Ready" to proceed to node choice. | → NodeReveal (next node) or RunEnd (Boss completed) |
RunEnd |
Victory or failure screen. Stats recorded. Return to main menu. | → RunIdle |
Note: CombatNodeComponent manages its own internal Loading → RunningPhase → ... → Settlement state machine (per CombatNodeArchitecture.md). From the Node System's perspective, a Combat node entry is a single atomic transition: NodeEntry → AssemblyPhase on receiving the CombatVictory or CombatDefeat event.
Interactions with Other Systems
| System | Direction | Interface |
|---|---|---|
| CombatNodeComponent | Delegates to | StartCombat(CombatData), receives OnCombatVictory / OnCombatDefeat events |
| ShopSystem | Delegates to | ShopFormController.OpenShop(), receives OnShopClosed callback |
| EventSystem | Delegates to | EventNodeComponent.ProcessEvent(), receives OnEventResolved |
| TowerAssembly | Reads/writes | Tower config persists in NodeComponent run state; Assembly Phase reads current inventory |
| Inventory | Reads | Component drops from combat are added to inventory via InventoryComponent.AddItem |
| MapEntity / MapTopologyService | Reads | Combat nodes query MapTopologyService for path data to pass to CombatNodeComponent via MapData |
| Progression | Writes | On RunEnd, final stats (Gold, nodes completed, Boss killed) are written to Progression |
RunState (data container, owned by Procedure layer)
├── RunStateAdvanceService (state transition logic)
├── CombatNodeComponent (delegates combat entry)
├── ShopNodeComponent (opens Shop UI on Shop node)
├── EventNodeComponent (processes Event node choices)
└── TowerAssembly (read/written during Assembly Phase)
Note: There is no NodeComponent class. Orchestration is handled by the Procedure layer.
Formulas
Important note on completedLoopCount: This refers to the number of completed combat cycles within a single Boss node encounter — i.e., when a Boss fight loops (e.g., VictoryType requires surviving N rounds), each completed cycle increments the count. This is independent of the run's node count. The formula does NOT use nodesCompleted from the run state.
Gold earned per node completed, plus boss bonus:
TotalGold = Σ DRLevel.RewardGold(CompletedCombatNodes) + (HasDefeatedBoss ? BossBonus : 0)
Each Combat node's gold reward is determined by its linked level's DRLevel.RewardGold value. Event and Shop nodes do not award gold directly. The Boss node's own reward comes from its linked level (DRLevel.RewardGold at level index for Boss) plus the BossBonus.
| Variable | Symbol | Type | Range | Description |
|---|---|---|---|---|
| Combat nodes cleared | n | int | 0–6 | Number of non-boss combat nodes cleared (nodes 1, 2, 3, 5, 7, 9). Event and Shop nodes award 0 gold and are excluded from the sum. |
| Boss bonus | BossBonus | int | 200 | Flat bonus for defeating Boss (applied only if HasDefeatedBoss = true) |
Per-node gold (REVISED — economy rebalanced): After rebalancing, the illustrative values for the Plain theme sequence (Combat at L1, L2, L3, L1; Boss at L4) are:
| Node | Type | Level | Gold (illustrative) |
|---|---|---|---|
| 1 | Combat | Level 1 | 90 |
| 2 | Combat | Level 2 | 90 |
| 3 | Combat | Level 3 | 120 |
| 4 | Shop | — | 0 |
| 5 | Combat | Level 1 | 90 |
| 6 | Event | — | 0 |
| 7 | Combat | Level 2 | 90 |
| 8 | Shop | — | 0 |
| 9 | Combat | Level 3 | 120 |
| 10 | BossCombat | Level 4 | 300 + BossBonus(200) |
Output Range: 0 to 1100 (6×Combat=600 + BossBonus=200 + BossLevelGold=300) depending on how far the player progressed and whether Boss was defeated. Constraint: Plain theme places exactly one Event node at position 6. Events may only occupy positions 4–8. Combat nodes 1, 2, 3, 5, 7, 9 use the Plain cycle L1, L2, L3, L1, L2, L3. Shop tiering: The first shop (Node 4) offers only White and Green rarity components; Blue and above appear only from Node 8 onward.
2. Boss Difficulty Scaling
Boss difficulty scales with both the Boss node's own loop/round count and the number of non-boss nodes the player has completed in the run.
BossEffectiveHp = DRLevel.BaseHp × 2^(completedLoopCount) × (1 + 0.1 × nodesCompleted)
| Variable | Symbol | Type | Range | Description |
|---|---|---|---|---|
| Boss base HP | DRLevel.BaseHp | int | ≥ 1 | Fixed HP from level config (note: DRLevel only has BaseHp, not a separate BossBaseHp field). Floor of 1 applied at data load time. |
| Completed loop count | completedLoopCount | int | 0–31 | Number of combat rounds/cycles completed within the current Boss encounter — NOT the count of nodes completed in the run. When a Boss fight loops (e.g., VictoryType requires surviving N rounds), each completed cycle increments the count. Resets when a new Boss fight begins. Hard cap of 31 loops before BossEffectiveHp would reach int.MaxValue; implementation clamps at int.MaxValue. |
| Nodes completed | nodesCompleted | int | 0–9 | Number of non-boss combat nodes (nodes 1, 2, 3, 5, 7, 9) successfully completed this run. Does not include Shop or Event nodes. Resets each run. |
| Difficulty multiplier | (1 + 0.1 × nodesCompleted) | float | 1.0–1.9 | Run-progress multiplier. More nodes completed → harder Boss. Caps naturally at 1.9× (at 9 nodes completed). Does not exceed 2.0×. |
| Boss effective HP | BossEffectiveHp | int | ≥ 1 | Final boss HP |
Constraint: Players who lost early AND players who breezed through will face different Boss HP values at the same loop count — the run-progress multiplier differentiates them. A player with nodesCompleted=3 and completedLoopCount=0 faces BaseHp × 1.3; a player with nodesCompleted=9 and completedLoopCount=0 faces BaseHp × 1.9 at the same level.
Note: Formula extends EnemyConfigProvider.ResolveScaledEnemyBaseHp with a run-progress factor. The DRLevel fields used are: Id, LevelThemeType, BaseHp, StartCoin, VictoryType, VictoryParam, RewardGold.
Edge Cases
-
If Player loses Combat at any node: Run ends in failure immediately. No partial rewards are awarded. The run is complete at the point of failure.
-
If Player has 0 components entering Assembly Phase: Player cannot assemble or modify any towers. Assembly phase is effectively a no-op pass-through. Player proceeds to the next node with existing tower state unchanged.
-
If Player encounters two consecutive Shop nodes: Player has back-to-back purchase opportunities. If Gold is insufficient at Shop 1, no mitigation occurs — Shop 2 may also be unaffordable. No rule forces spending or guarantees affordability.
-
If Player encounters Shop Node 4 (first shop): Only White and Green rarity components are available. Blue and higher rarities are excluded from this shop. If the player's gold is insufficient for all available items, no additional items appear — the player may proceed with insufficient purchases.
-
If Player encounters Shop Node 8 (second shop): All rarity tiers (White through Red) are available. There is no tier restriction on the second shop.
-
If Player loses at Boss node: Run ends in failure immediately with no partial rewards. The Boss node awards no rewards on loss.
Dependencies
Upstream Dependencies (what Node System depends on)
| System | Type | Interface | Status |
|---|---|---|---|
| CombatNodeComponent | Hard | Fires NodeCompleteEventArgs with CombatWon field after combat resolves. Calls to CombatNodeComponent.StartCombat() enter combat. |
Implemented (Assets\GameMain\Scripts\CustomComponent\CombatNode\CombatNodeComponent.cs) |
| ShopSystem | Hard | Calls ShopNodeComponent.StartShop(); receives OnShopClosed callback. |
Designed (design/gdd/shop.md). ShopContext contract and buy/sell behavior are defined and consistent with Assembly Phase timing. |
| EventSystem | Hard | Calls EventNodeComponent.ProcessEvent(); receives OnEventResolved. |
Designed (design/gdd/event-system.md). EventContext contract and risk/reward resolution flow are defined and consistent with NodeEntry → AssemblyPhase atomic transition model. |
| TowerAssembly | Soft | Reads/writes tower configs during Assembly Phase. Tower state persists in NodeComponent run context. |
Designed (design/gdd/tower-assembly.md). TryAssembleTower() and TryDisassembleTower() interfaces are defined; Assembly Phase timing and inventory access patterns are consistent with this GDD. |
| Inventory | Soft | Reads component drops from combat; adds items via PlayerInventoryComponent.MergeInventory. |
Implemented |
| MapEntity / MapTopologyService | Hard | Reads path/topology data for combat map setup; assembles MapData passed to CombatNodeComponent. |
Implemented (see Assets\GameMain\Scripts\CustomComponent\Map\) |
| Progression | Soft | Writes final run stats (Gold, nodes completed, Boss killed) on RunEnd. |
Designed (design/gdd/progression.md). RecordRunEnd() interface is defined; all acceptance criteria involving Progression are now implementable. |
Downstream Dependents (what depends on Node System)
| System | Type | Interface | Status |
|---|---|---|---|
| Progression | Hard | Reads run completion data (Gold, nodes cleared, Boss defeat) from RunState on RunEnd. |
Designed (design/gdd/progression.md). Interface contract is defined. |
Bidirectional Consistency Check
CombatNodeComponent→ listed as upstream (Node System receives its events) ✅Progression→ downstream only; Node System writes to it ✅ShopSystem→ GDD exists; interface contract aligned ✅EventSystem→ GDD exists; interface contract aligned ✅TowerAssembly→ GDD exists; interface contract defined ✅
Provisional Assumptions
ShopSystemreceives aShopContextfrom the orchestrating component containing current Gold/Coin and run node indexEventSystemreceives anEventContextcontaining run state (node index)TowerAssemblyis called during Assembly Phase and writes back toRunState's inventory snapshot- There is no
NodeComponent— orchestration is handled by the Procedure layer viaRunStateAdvanceService
Tuning Knobs
All designer-adjustable values for the Node System. Changing these does not require code changes.
Run Structure
| Knob | Default | Safe Range | Extreme: Too Low | Extreme: Too High |
|---|---|---|---|---|
TotalNodesPerRun |
10 | 5–20 | Run feels too short; boss arrives too quickly | Run feels repetitive; pacing drags |
BossNodeIndex |
10 | = TotalNodesPerRun |
N/A | N/A |
OutgoingEdgesPerNode |
2 | 2–3 | Fewer choices reduces strategic depth | More choices may overwhelm UI/decision-making |
Boss Scaling
| Knob | Default | Safe Range | Extreme: Too Low | Extreme: Too High |
|---|---|---|---|---|
BossBonusGold |
200 | 100–500 | Boss reward feels trivial | Boss trivializes economy |
Assembly Phase
| Knob | Default | Safe Range | Extreme: Too Low | Extreme: Too High |
|---|---|---|---|---|
AssemblyPhaseIsMandatory |
true | true/false | Player skips assembly (reduces strategy depth) | N/A |
AssemblyPhaseHasTimeLimit |
false | false or 30–120s | N/A | Time pressure reduces quality of decisions |
Visual/Audio Requirements
VFX Event Specifications
| Event | Visual Effect | Audio Cue | Duration |
|---|---|---|---|
| Node Completion | Node pulses with type-color glow (1.0x → 1.1x → 1.0x), emits 8–12 geometric particles (triangles/diamonds) in radial burst | Soft ascending chime (C5-E5-G5), low volume | ~600ms |
| Choice Made | Selected edge animates from dashed to solid (300ms); unselected edge fades to 20% opacity | Subtle "lock-in" percussive click | ~400ms |
| Loss Suffered | Screen flashes red at 30% opacity for 150ms; failed node icon cracks/dims permanently; screen transitions to Run Failure screen | Low thud + dissonant minor-2nd tone | ~300ms |
| Boss Defeated | Full-screen golden particle shower (64+ hexagonal particles); Boss node explodes into geometric shards reforming as victory badge | Triumphant rising major chord fanfare (1.5s) | ~2000ms |
| Run Victory | All past nodes illuminate sequentially bottom-to-top (80ms each) forming a completed-path glow; Boss transforms into trophy/star icon; golden vignette | Extended C-E-G-C chord sustain + chime cascade | ~2500ms |
| Run Failure | Screen desaturates over 500ms; node track cracks along failed node; fade to dark with red tinge | Descending minor tone + deep bell | ~1500ms |
Color Palette
| Node Type | Color | Hex | Icon |
|---|---|---|---|
| Combat | Crimson Red | #FF4A4A |
Sword |
| Event | Royal Purple | #9B59B6 |
Question mark |
| Shop | Gold | #FFD700 |
Coin |
| Boss | Golden Crown | #FF8C00 |
Crown |
| Locked/Future | Slate Gray | #4A5568 |
— |
| Completed | Dimmed type color | 50% brightness | Checkmark |
| Failed | Desaturated + Red X | — | Broken node |
Node Visual States
| State | Treatment |
|---|---|
| Current | Full opacity, type color, white 3px border, pulse animation (1.0x–1.05x, 1.5s loop), outer glow ring |
| Completed | 40% opacity, grayscale tint, no glow, checkmark overlay |
| Failed | 30% opacity, desaturated, crack texture, red X overlay |
| Future/Locked | 25% opacity, no edges visible |
| Future/Revealed | 70% opacity, type color, dashed interactive edges |
| Boss | Full opacity, 1.3x scale, crown icon, amber/gold particle aura (#FF8C00) |
Track Layout
- Vertical orientation, Boss at top (fixed beacon glow), Node 1 at bottom
- Current node centered in viewport; past nodes slide up and compress (0.9x scale per node above)
- Edges: 2px type-colored lines, dashed when active, solid when locked
- All particle shapes: triangles, diamonds, hexagons only — no organic curves
Audio Style
- Sounds: clean sine/triangle waves — digital-mathematical, not organic
- SFX duration: 100–400ms typical
- Ambient: C major chord drone/pad during track exploration
- Boss entry: dedicated boss music stinger
Accessibility
- Color + iconography always paired (color alone never conveys type)
- Loss flash 150ms at 30% opacity — accompanied by a brief screen shake; an accessibility toggle in Settings allows this flash to be replaced with a slow fade (500ms) for players with photosensitive concerns
- Boss Defeated particle shower (64+ hexagonal particles) — an accessibility toggle in Settings reduces particle count to 16 for players with visual sensitivity
- Audio cues have visual alternatives (state changes, screen flashes)
- High-contrast mode: node border brightens to 4px white
- Colorblind differentiation: Failed state uses a distinct shape treatment (jagged/broken frame outline) in addition to desaturated color + red X, so it is distinguishable from Completed without relying on color perception. Boss node aura uses golden-orange (#FF8C00) rather than crimson to differentiate from Combat node red (#FF4A4A); crown icon and particle aura provide additional differentiation.
- Node state opacity minimum: Future/Locked state uses minimum 25% opacity (not 15%) so it remains visible rather than appearing as blank space.
- Inventory access: Player can view (but not modify) inventory and Gold/Coin balance from the Node Map Screen at any time. Modification is restricted to Assembly Phase only. This enables informed node choice decisions without violating assembly-phase-only build modification.
UI Requirements
Node Map Screen
Layout: Full-screen vertical scrollable node track.
- Boss node fixed at top with persistent beacon glow.
- Current node centered vertically.
- Past nodes stacked above (dimmed, compressed 0.9x per node).
- Future nodes hidden below fold.
Node Card (per node):
- Size: ~80×80px base, Boss 1.3x (104×104px)
- Content: type icon (sword/question/coin/crown), node index number
- Border: 3px white on current, type-colored on revealed, none on locked
- Background: type color fill
Edge Display:
- Lines connecting current node to 2 revealed destinations
- Dashed while unchosen, solid after selection
- Type-colored
Run Progress HUD:
- Top-left: Run index badge ("Run #3")
- Top-right: Gold counter and Coin counter (displayed separately with distinct icons; tooltip on hover explains each)
Node Choice Overlay
Trigger: Appears when entering NodeReveal state after Assembly Phase.
Content:
- Title: "Choose Your Path" (or equivalent)
- Two node cards displayed horizontally, each showing node type + type icon
- Cards highlight on hover; selection locks on click
- "Locked in" confirmation animation on selection
Constraints:
- No third option visible
- Player cannot advance without choosing
- ESC/Cancel not supported — choice is mandatory
Assembly Phase Screen
Trigger: Auto-enters after any node resolves.
Content:
- Tower slots (current tower configs, 3 component slots each)
- Inventory grid (all owned components)
- Repository grid (all stored components)
- Next Node Preview: The 2 outgoing edge destinations from the completed node are displayed on-screen during Assembly Phase, showing each destination's node type and index. This allows the player to optimize their tower build based on known upcoming challenges — matching the "preparing and adapting" Player Fantasy.
- "Ready" button (bottom-right, large, pulsing until confirmed)
Interactions:
- Drag components between inventory and tower slots
- Click "Ready" to confirm and advance
- No time limit in default configuration (tunable)
Empty State:
- When inventory is empty: tower slots show placeholder silhouettes (dotted outline) with "Empty" label
- "Ready" button is still present and functional when inventory is empty — it pulses to indicate action is available
- Repository grid shows empty state with "No stored components" message
Run End Screen
Trigger: Appears on RunEnd state.
Variants:
- Victory: Golden theme, Boss defeated badge, Gold total, nodes cleared, "Return to Menu" button
- Failure: Desaturated/red theme, "Run Failed" message, furthest node reached, "Return to Menu" button
No retry button — runs are single-attempt
Interaction Constraints
- No back button during node choice
- No undo after node selection is confirmed
- Mandatory commitment confirmation: A "This path cannot be undone." message must appear in the Node Choice Overlay before the player can confirm. This is not optional flavor text.
- ESC does not cancel Assembly Phase (must click "Ready")
- Player can view inventory and Gold/Coin balance from the Node Map Screen at any time; player can only modify inventory and tower builds during Assembly Phase
- Next node types visible during Assembly Phase: The 2 outgoing edge destinations are displayed on the Assembly Phase screen before the player clicks Ready, enabling informed build optimization
Acceptance Criteria
Run Structure
- GIVEN a new run, WHEN the player starts, THEN a 10-node track is generated with Node 10 as BossCombat, and node types follow the fixed sequence (Combat, Combat, Combat, Shop, Combat, Event, Combat, Shop, Combat, BossCombat) for the duration of the run.
- GIVEN the player is at NodeReveal, WHEN they see the outgoing edges, THEN exactly 2 destination nodes are displayed with their
RunNodeTypeenum values visible. The full track (all 10 nodes) is visible from the run start. - GIVEN the player has selected a node edge, WHEN they confirm, THEN the choice is locked, a modal dialog displays the text "This Path Cannot Be Undone" with a "Confirm" button, and previously visited nodes remain in Completed state and are not present in the NodeReveal choice set.
- GIVEN the player has completed Node N (N < 10), WHEN they are on the Node Choice Overlay or any subsequent screen, THEN no UI element, back button, or code path allows navigation back to Node N-1 or any previously completed node.
- GIVEN the player completes Node 10 (Boss), WHEN the run end resolves, THEN the run enters
RunEndstate and does not return to the node track or generate additional nodes.
Node Resolution
- GIVEN the player completes Combat node n, WHEN they win, THEN they receive Gold equal to
DRLevel.RewardGoldfor the linked level, plus component drops as defined by the level's component drop table. - GIVEN the player completes Event node, WHEN the event resolves, THEN the event's outcome modifiers (Gold delta, HP delta, buffs/debuffs) are reflected in the player's run state immediately, the Event UI is dismissed, and the transition to Assembly Phase begins within 2 seconds.
- GIVEN the player completes Shop node, WHEN they exit the shop, THEN all purchases and sales are committed to the player's inventory and the UI transitions to Assembly Phase within 2 seconds.
- GIVEN the player opens a Shop node, WHEN they click "Leave" without making any purchases or sales, THEN no changes are made to the player's inventory or Gold, and the UI transitions to Assembly Phase.
- GIVEN the player completes Shop node 4, WHEN they later reach Shop node 8, THEN Shop node 8 functions normally with the same rules; there is no special mitigation or bonus for consecutive shop nodes.
Combat Loss
- GIVEN the player loses Combat at any node (including Node 10), WHEN the loss is recorded, THEN the run ends immediately in failure. The run's Gold, Coin, Inventory, and TowerConfig are not written to Progression; the in-memory run state is cleared; and the player is placed on the RunEnd (Failure) screen.
- GIVEN the player loses at the Boss (Node 10), WHEN Node 10 resolves, THEN the Boss node does not fire
NodeCompleteEventArgswithCombatWon = true, and noDRLevel.RewardGoldorBossBonusis added to run state.
Boss
- GIVEN the player defeats the Boss, WHEN Node 10 resolves, THEN they receive the Boss level's
DRLevel.RewardGoldplusBossBonus = 200gold. - GIVEN the player faces the Boss, WHEN the Boss spawns, THEN
BossEffectiveHp = DRLevel.BaseHp × 2^(completedLoopCount) × (1 + 0.1 × nodesCompleted), wherecompletedLoopCountis the number of completed boss cycles andnodesCompletedis the count of non-boss combat nodes cleared this run.
Assembly Phase
- GIVEN the player is in Assembly Phase, WHEN the screen is displayed, THEN the 2 outgoing edge destinations from the completed node are visible on-screen, each showing its node type and index.
- GIVEN the player is in Assembly Phase, WHEN they click the "Ready" button, THEN the Assembly Phase ends, the Node Choice Overlay appears, and the player selects from the 2 already-revealed destinations.
- GIVEN the player has 0 components in inventory, WHEN they enter Assembly Phase, THEN the "Ready" button is enabled and clicking it proceeds to the next node without modification.
- GIVEN a node resolves (Combat victory, Event completed, Shop exited), WHEN the resolution completes, THEN Assembly Phase is entered automatically. The player is never required to take an action to trigger Assembly Phase entry.
- GIVEN the player is in Assembly Phase, WHEN they have not yet clicked "Ready", THEN the player may re-enter and modify tower configurations freely. The "Ready" button is the only mandatory action to proceed.
Data Persistence
- GIVEN a completed run ending in victory, WHEN the run ends, THEN a subsequent read of
Progression.GetRunHistory()returns an entry containing the Gold total, nodesCompleted count, and BossDefeated flag for this run, and the player is returned to main menu. - GIVEN a new run starts, WHEN the player begins, THEN Gold, Coin, Inventory, and Tower configs are reset to
DRRunConfig.StartGold,DRRunConfig.StartCoin, empty inventory, and default tower configs respectively.
Cross-System
- GIVEN the player completes a Combat node, WHEN they win, THEN component drops are added to the player's inventory before the Assembly Phase UI is shown.
- GIVEN the player completes a Combat node, WHEN
NodeCompleteEventArgswithCombatWon = trueis dispatched, THEN the transition to Assembly Phase begins within 2 seconds of the event.
Open Questions
1. Should Event Nodes Appear in the First 3 Nodes?
Status: ✅ RESOLVED — Option [C] adopted: Events restricted to positions 4–8. Node sequence updated accordingly (Events only at node 6 in Plain theme).
2. Does the Player See the Full Track at Run Start?
Status: ✅ RESOLVED — Option [A] adopted: Full track visible from run start. Player Fantasy updated to reflect this. All nodes visible, current node highlighted, past nodes dimmed.
3. Blocked Systems Before Node System Implementation
Status: ✅ RESOLVED — All blocking GDDs have been completed:
- Shop System GDD (
design/gdd/shop.md) — Status: Designed.ShopContextcontract and buy/sell behavior are defined. - Event System GDD (
design/gdd/event-system.md) — Status: Designed.EventContextcontract and risk/reward resolution flow are defined. - Progression GDD (
design/gdd/progression.md) — Status: Designed.RecordRunEnd()andGetLifetimeStats()interfaces are defined.