# 2.0 Refactor — Editor Setup Checklist The 2.0 code landed on `2.0_design_refactor` and compiles clean, but the new systems are **data- and scene-driven**. Nothing runs until the assets below exist and the scene objects are wired. Work top to bottom — each section depends on the ones above it. Sections are in **dependency order** — every asset a step references has been created by an earlier step. Scene wiring comes last, once there is something to assign. --- ## 0. Assets vs. scene objects The single most useful distinction when hunting for a field: - **`ScriptableObject` → a file in the Project window.** `WaveDefinition`, `WaveGroup`, `PhaseDefinition`, `RunDefinition`, every ability, every card, every upgrade group. - **`MonoBehaviour` → a component on a scene GameObject.** Only four: `RunState`, `WaveVote`, `EnemyUpgradePool`, `EnemyAbilityPool`. Scene components hold *references* to assets, never the other way round — `RunState` in the scene points at the `RunDefinition` asset on disk. Where the assets live, under `Assets/_Project/Definitions/`: | Asset type | Folder | |---|---| | Abilities | `RunDefinitions/EnemyAbilities/` | | Enemy-buff cards + upgrade groups | `RunDefinitions/Draft/EnemyDraft/` | | Player draft options | `RunDefinitions/Draft/PlayerDraft/` | | Wave groups, phases, run | `RunDefinitions/RunStructure/` | | Individual waves | `RunDefinitions/Waves/` | | Enemy types | `Enemies/` | | Gold + enemy scaling configs | `RunDefinitions/` | --- ## 1. Enemy-buff cards Two asset layers, because network identity and phase gating are separate concerns. **Abilities** (`TD/Enemy Abilities/…`) — what a buffed enemy *does*: - Split On Death — already exists; **re-check its fields**, they changed. It now has `SplitCount`, `HpPercent`, `SpeedPercent`, `ScalePercent`, `LivesCostPercent`, `FlightHeightPercent`, `ScatterRadius`. - Flight, Blink, No Bounty, Gold Theft — new, need assets creating. **Cards** (`TD/Enemy Upgrades/…`) — what players vote on: - One `Ability Card` per ability above, each pointing at its `EnemyAbilityDefinition`. - One `Double Up Card` (vote-meta; grants no ability). **Groups** (`TD/Enemy Upgrades/Upgrade Group`) — the unit of phase gating: Cut groups by *when a card should become available*, not by what it does, since a group is what you drag between phases: `EUG_Phase1_Basics`, `EUG_Phase2_Nasty`, and so on. Availability accumulates — phase 2 lists both Basics and Nasty. For MVP, one group holding every card is fine. > A card must be in **both** the pool (§4, network identity) and a group (phase gating) to ever be > offered. Pooled-but-ungrouped is silently never offered — that's how you park an authored card > you aren't ready to use. Grouped-but-unpooled logs a warning and is skipped. > > Keep a card in only **one** group per phase. Two referenced groups holding the same card give it > two independent shots at the draw, effectively doubling its rate. --- ## 2. Run structure Build bottom-up: 1. **`WaveGroup`** assets (`TD/Run/Wave Group`) — bags of weighted `WaveDefinition` entries. Weights are **relative** 0–1 and default to 1 (equal odds). A zero weight warns inline and means the wave can never be drawn. 2. **`PhaseDefinition`** (`TD/Run/Phase Definition`) — `WaveGroups`, `BossGroups`, and `EnemyUpgradeGroups` (the groups authored in §1). 3. **`RunDefinition`** (`TD/Run/Run Definition`) — `WavesPerCycle` (5), `CyclesPerPhase` (3), and the `Phases` array. **MVP needs one phase.** The `RunDefinition` inspector shows a live validation panel and a per-phase capacity readout. Get it green before pressing play. ### The constraint that will bite A phase must supply **`WavesPerCycle` waves with DISTINCT enemy types**. Enemy buffs are keyed to a wave slot, so two slots sharing an enemy type would make "which wave did this buff apply to" ambiguous. Ten waves in a pool is *not* enough if they only use three enemies. The inspector reports distinct-type count per phase; the draw fails loudly at match start otherwise. Ten wave definitions and ten enemy definitions already exist, so the content floor is met — but check the type spread. --- ## 3. Scene objects (both `9Player` and `Main`) Everything these reference now exists. Two new GameObjects need a `NetworkObject`; one doesn't. | GameObject | Component | NetworkObject? | Assign | |---|---|---|---| | `RunState` | `RunState` | **Yes** | The `RunDefinition` asset from §2. | | `WaveVote` | `WaveVote` | **Yes** | Nothing — `Options Per Vote` defaults to 3. | | `EnemyUpgradePool` | `EnemyUpgradePool` | No | Every **card** asset from §1 into `options`. | Also update the pool that already exists: - **`EnemyAbilityPool`** — add every **ability** asset from §1 to its `abilities` array. Its `noAbilityWeight` field is **gone** (abilities are voted in now, not rolled per enemy). `WaveManager` **no longer has a `waveDefinitions` array** — that field is gone. Its two new serialized fields are `Draft Time Seconds` (30) and `Vote Time Seconds` (25). > Both new NetworkBehaviours are scene objects, so they must be present *before* the host starts. > > `EnemyUpgradePool.options` array order **is** each card's network id. Appending is safe; > inserting or reordering desyncs a host from clients running a different build. --- ## 4. Gold config `GoldConfig.Waves` is now **`GoldConfig.Encounters`**, indexed by global encounter number and counted continuously across the whole run — cycles do **not** reset it. One phase of 5 waves × 3 cycles + a boss needs **16 entries**. Missing entries pay zero for that encounter. Entries no longer reference a `WaveDefinition`. Payout is a property of *run position*, not of which wave was drawn — encounter 3 pays encounter 3's rates whatever spawns in it. The inspector labels each element `Encounter N` and projects per-encounter and cumulative earnings against `PreviewEnemiesPerEncounter`, a preview-only figure that nothing at runtime reads. > The existing asset's `Waves` data migrates automatically on first import > (`[FormerlySerializedAs]`) — but it holds 10 entries and one phase needs 16, so the last six > encounters (including the boss) pay nothing until they're authored. --- ## 5. Enemy scaling Create an **`EnemyScalingConfig`** (`TD/Enemy Scaling Config`) and assign it to `WaveManager` alongside the `GoldConfig`. Without it every enemy spawns at a flat 100 HP and difficulty never progresses — the run is playable but meaningless. Three numbers, no per-encounter table: | Field | Default | Meaning | |---|---|---| | `BaseHpBudget` | 5000 | Total enemy health encounter 1 presents, **per player zone** | | `GrowthPerEncounter` | 1.18 | +18% per encounter → budget doubles roughly every 4 | | `BossHpMultiplier` | 6 | Extra multiplier on a boss encounter | **Health is a budget, divided.** Per-enemy HP is the encounter's budget split across the wave's enemy count, then skewed by the type's `HpMultiplier`. This is what lets waves be drawn at random: a 150-strong swarm and an 8-strong elite pack in the same slot present the same total threat. Enemy count becomes a *texture* knob, not a difficulty one. > **`EnemyDefinition.MaxHp` no longer exists.** It's `HpMultiplier` now — a deviation from budget, > not hit points. All ten definitions have been re-authored into a 0.7–1.35 band by archetype > (golems tanky/slow, ents fragile/quick, drake fastest and flimsiest). **These are placeholder > values — tune them.** > > `MoveSpeed` stays absolute and is deliberately never scaled by run progress. Escalating speed > compounds with escalating health and invalidates tower balance mid-run; fast-vs-slow is a fixed > character trait. Escalation is carried by health and the voted buffs. --- ## 6. Player prefab Add **`PlayerTowerUpgrades`** to `Player.prefab`, alongside `PlayerTowerDeck` / `PlayerDraft`. Without it, tower-upgrade draft options can't apply and the Upgrade buttons never appear. --- ## 7. Enemy prefabs Any enemy that should be able to carry wave buffs needs an **`EnemyAbility`** component on its root. `WaveManager` logs a warning naming the prefab if a buffed wave spawns an enemy without one. `SplitOnDeath` and any size-changing buff need the prefab's **`NetworkTransform` to sync scale**, or minions render full-size on remote peers. --- ## 8. Tower upgrade trees 1. Author upgraded towers as ordinary `TowerDefinition` assets and add them to `TowerPlacementManager.towerDefinitions` (**not** to `startingDeck`). 2. Wire the tree by filling each parent's `UpgradePaths` array with its children. 3. Each upgrade node's **`GoldCost` is its upgrade price** — upgrade nodes are never placed directly, so the field is free to mean that. 4. **Footprint must match the parent.** A differently-sized upgrade is rejected: the tower's occupied/unwalkable tiles are stamped at its current size, and converting would leave the grid describing a shape the tower no longer has. 5. Create a `TD/Draft/Tower Upgrade Option` per node (`BaseTower` → `UpgradedTower`) and add it to `DraftPool`. Prerequisites need no explicit list — a node is offered only once its parent is reachable (in the deck, or itself unlocked). Existing `TowerUpgradeDraftOption` assets **changed meaning**: they used to swap the deck entry, they now unlock an upgrade node. Re-check any that exist. --- ## Phase boundaries reset the board When a boss dies and a new phase is drawn, **every built tower is destroyed with no refund** — players rebuild their maze from scratch each phase. Nothing to wire; it runs automatically off `RunAdvance.NextPhase`. - Queued and in-progress builds **are** refunded — those towers were never delivered, so eating the gold would just punish having a build queued when the boss happened to die. - Shelved build sites are cleared too, so no ghosts outlive the maze. - A system message names the loss in chat, since an entire maze vanishing needs a stated cause. - The final phase's boss ends the run instead, so no wipe happens there. --- ## Known gaps - **Upgraded towers keep the parent's mesh.** Switching the definition changes stats immediately (`TowerCombat` re-reads it every tick) but not the model — visual swap is an art task. - **No 3-player map yet.** `MatchRules.MaxPlayers` is 3 and slot allocation caps there, but `9Player` is still the only authored level. - **Tower vulnerability is not built** — Savage, Mind Control, AOE EMP, Fart Miasma and Dummy all need towers to be damageable/disableable, which doesn't exist. Deferred by agreement. - **Relics** untouched, as agreed.