First pass at full refactor to 2.0 design

Restructures the game around the cyclical run loop from Game Design Doc V2:
5 waves = a cycle, 3 cycles = a phase, each phase ends in a boss.

- New TD.Gameplay.Waves: WaveGroup / PhaseDefinition / RunDefinition author the
  run as draggable weighted pools; RunState owns phase/cycle position, the drawn
  wave slots, and the per-slot enemy buff sets. WaveManager's flat wave array is
  gone -- it now only runs the encounter RunState points at.
- New TD.Gameplay.EnemyUpgrades: the post-wave enemy-buff vote, with public
  live-replicated ballots so the HUD can show who voted for what.
- Inter-wave flow is now strictly sequential: draft -> vote -> build, each stage
  ending early once every player has acted.
- Enemy abilities inverted from per-instance random rolls to deterministic,
  stacking per-wave-slot sets. Six cards ship: Split (reworked), Flight, Blink,
  No Bounty, Gold Theft, Double Up.
- Tower upgrades are a two-step tree: a draft pick unlocks a node, gold converts
  an already-placed tower in place.
- Boss encounters flag their enemies and drive a boss HP bar.
- Player cap reduced to 3 via MatchRules.MaxPlayers.
- GoldConfig is now keyed by global encounter number rather than wave index.

Compiles clean; NOT yet verified in-engine. Editor wiring still required --
see Docs/2.0_Setup_Checklist.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Matt F 2026-07-30 17:45:11 -07:00
parent 7e5c3a8279
commit 4892d7253d
64 changed files with 4023 additions and 344 deletions

129
Docs/2.0_Setup_Checklist.md Normal file
View file

@ -0,0 +1,129 @@
# 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.
---
## 1. Scene objects (both `9Player` and `Main`)
Three new scene objects are required. Two are plain MonoBehaviours; one needs a `NetworkObject`.
| GameObject | Component | NetworkObject? | Notes |
|---|---|---|---|
| `RunState` | `RunState` | **Yes** | Assign the `RunDefinition` asset from §3. |
| `WaveVote` | `WaveVote` | **Yes** | `Options Per Vote` defaults to 3. |
| `EnemyUpgradePool` | `EnemyUpgradePool` | No | Fill `options` with every card asset from §2. |
`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.
---
## 2. 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.
Add every ability asset to the scene's existing `EnemyAbilityPool`.
Its `noAbilityWeight` field is **gone** (abilities are voted in now, not rolled).
**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).
Then: add every card to `EnemyUpgradePool.options`, and group them into one or more
`EnemyUpgradeGroup` assets for phase gating.
---
## 3. Run structure
Build bottom-up:
1. **`WaveGroup`** assets (`TD/Run/Wave Group`) — bags of weighted `WaveDefinition` entries.
Weights are **relative** 01 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`,
`EnemyUpgradeGroups`.
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.
---
## 4. Gold config
`GoldConfig.Waves` is now indexed by **global encounter number**, 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.
---
## 5. 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.
---
## 6. 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.
---
## 7. 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.
---
## 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.