# 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.
