Added Read Me

This commit is contained in:
Brian Fertig 2026-04-12 08:47:21 -06:00
parent 9d77149b41
commit db258bdcae
1 changed files with 267 additions and 0 deletions

267
README.md Normal file
View File

@ -0,0 +1,267 @@
# Tyrants Edge
A browser-based deck-building card game built with Phaser 3. Command five factions across a tactical battlefield — deploy assault cards, trigger skill chains, and defeat your opponent's commander in turn-based 1v1 combat.
## Quick Start
**Requirements:** Python 3, a modern browser (Chrome/Firefox/Safari)
```bash
./start_web.sh
# or
python3 -m http.server 8000
```
Open `http://localhost:8000`. No build step — the game runs directly from source as ES modules. Refresh the page after any code change.
## Game Modes
| Mode | Description |
|------|-------------|
| **Campaign** | Five faction story campaigns, each with ~7 missions and lore. Defeat enemy commanders to unlock new campaigns and earn card rewards. |
| **Skirmish** | Standalone battles. Choose a card level (1–5) and difficulty (Easy / Medium / Hard / Legendary), then either pick a premade deck or draft one from a budget card pool. |
| **Deck Builder** | Construct custom decks: 1 commander + 3–10 assault cards, max 3 copies of any card. |
| **Collection** | Browse and filter your owned cards by faction and rarity. |
| **Store** | Spend gold on faction-specific booster packs (5 factions, 4 cards per pack). |
| **Fusion** | Sacrifice 3 cards of the same rarity to forge 1 card of the next rarity (common → rare → epic → legendary). |
## Architecture
Vanilla JavaScript with [Phaser 3](https://phaser.io/) (v3.90.0, loaded via CDN). No bundler, no npm, no build step.
### Scene Flow
```
BootScene → IntroScene → MainMenuScene
│
┌───────────────┼───────────────────┐
▼ ▼ ▼
CampaignSelectScene SkirmishSetupScene DeckBuilderScene
│ │
CampaignScene SkirmishDeckSelectScene
│ │
└───────────────┘
▼
BattleScene
│
BattleResultScene
```
**Other scenes:** `CollectionScene`, `StoreScene`, `FusionScene`
`BootScene` preloads all JSON data and card art, then initialises global managers before handing off to the intro video.
### Global Managers
Stored in Phaser's game registry; access anywhere with `this.registry.get(key)`.
| Key | Class | Purpose |
|-----|-------|---------|
| `cardManager` | `CardManager` | Card definitions and instance creation |
| `packManager` | `PackManager` | Booster pack opening and drop-rate logic |
| `save` | `SaveManager` | Versioned localStorage persistence |
| `deckManager` | `DeckManager` | Deck validation and construction |
| `tutorial` | `TutorialManager` | Tutorial stage progression tracking |
| `missions` | raw JSON | Campaign mission data |
### Source Layout
```
src/
├── game.js # Phaser config & scene list
├── combat/
│ ├── CombatEngine.js # Turn loop and phase resolution
│ ├── SkillProcessor.js # Skill effect evaluation
│ └── CombatAI.js # AI card selection
├── managers/
│ ├── CardManager.js
│ ├── PackManager.js
│ ├── SaveManager.js
│ ├── DeckManager.js
│ └── TutorialManager.js
├── objects/
│ ├── CardObject.js # Card rendering (Phaser Container)
│ ├── BattleField.js # Lane layout and positioning
│ ├── CardTooltip.js # Hover tooltip
│ └── HealthBar.js # Health/armor bar
├── scenes/ # One file per scene (14 total)
└── utils/
└── RNG.js # Seeded deterministic random
```
## Combat System
### Turn Phases
Each turn runs the following phases in order:
1. **Draw** — both sides draw up to a hand limit (MAX_HAND = 3)
2. **Deploy** — cards are placed into open lanes (MAX_LANES = 4)
3. **Activation** — `on_turn_start` skill triggers fire
4. **Rupture** — wound/DoT stacks deal damage
5. **Jam** — jammed cards are skipped this turn
6. **Commander Skills** — commander passive/active skills resolve
7. **Attack** — each lane attacks the opposing lane; skills fire on pre-attack/on-attack/on-kill triggers
8. **Cleanup** — dead cards are removed, state is prepared for next turn
`CombatEngine.js` maintains an **event queue** so the UI can animate each step sequentially without the logic blocking.
### Skills
`SkillProcessor.js` resolves all skill effects. Skills are attached to cards with an optional `value`, `trigger`, and `all` flag.
#### Skill Reference
| Category | Skills |
|----------|--------|
| **Offense** | `strike`, `swipe`, `pierce`, `wound`, `mortar`, `flurry`, `berserk` |
| **Control** | `jam`, `enfeeble`, `weaken` |
| **Defense** | `protect`, `counter`, `wall`, `armored`, `carapace` |
| **Support** | `heal`, `rally`, `siphon`, `drain`, `cleanse`, `sanctify` |
| **Special** | `burrow`, `molt`, `hive_link`, `evolve`, `legion`, `valor`, `tribute` |
#### Triggers
| Trigger | When it fires |
|---------|--------------|
| `preBattle` | Once, at the start of the match |
| `on_turn_start` | At the beginning of each turn |
| `preAttack` | Before this card attacks |
| `on_attack` | When this card attacks |
| `on_defend` | When this card is attacked |
| `on_kill` | When this card destroys an enemy |
| `passive` | Continuous effect |
### Win Conditions
- **Commander Kill** — reduce the opponent's commander health to zero
- **Overwhelm** — triggered when certain conditions are met (see overwhelm visual effect in `BattleScene`)
### Deterministic RNG
`RNG.js` provides a seeded pseudo-random number generator. Passing the same seed to `CombatEngine` and `CombatAI` produces an identical, replayable battle.
## Data Model
All game content lives in `data/` as JSON. No server needed — `BootScene` fetches these files directly.
### `cards.json`
104 cards across 5 factions. Each card supports multiple level tiers with independent stats and skills.
```json
{
"id": "imp_cmd_1",
"name": "Warlord Voss",
"faction": "imperial",
"type": "commander",
"rarity": "legendary",
"levels": [
{
"attack": 0,
"health": 30,
"armor": 2,
"delay": 0,
"skills": [
{ "name": "strike", "value": 4, "trigger": "on_attack" }
]
}
]
}
```
**Factions:** `imperial`, `raider`, `bloodthirsty`, `xeno`, `righteous`
**Types:** `commander`, `assault`
**Rarities:** `common`, `rare`, `epic`, `legendary`
### `missions.json`
37 missions across all campaigns.
```json
{
"id": "mission_001",
"name": "First Contact",
"chapter": 1,
"campaignId": "campaign_raider",
"enemyLevel": 1,
"opponent": {
"commander": "raider_cmd_1",
"cards": ["card_id", "..."]
},
"rewards": { "gold": 100, "cards": ["card_id"] }
}
```
### `campaigns.json`
5 faction campaigns. Each references an ordered list of mission IDs and a starter card reward.
### `packs.json`
5 faction packs at 400 gold each. Each pack has 4 card slots — 3 guaranteed commons and 1 weighted slot (35% common / 50% rare / 10% epic / 5% legendary).
### `skills.json`
Skill reference data (name, description, trigger, category). Skills are also defined inline on cards in `cards.json`.
### `skirmish_decks.json`
Predefined decks used in skirmish mode, annotated with difficulty and faction summary.
## Save Data
Stored in `localStorage` under the key `tyrants-edge-save`. The current schema is version 3; `SaveManager` handles forward migration automatically.
```json
{
"version": 3,
"gold": 300,
"level": 1,
"collection": { "card_id": 2 },
"decks": [
{
"id": "deck_1",
"name": "My Deck",
"commander": "imp_cmd_1",
"cards": ["card_id", "card_id", "..."]
}
],
"campaignProgress": {
"completedMissions": ["mission_001"],
"currentCampaign": "campaign_raider"
},
"unlockedCampaigns": ["campaign_raider"],
"tutorialProgress": { "completedStages": [1, 2] },
"starterDeckReceived": false
}
```
To reset save state, run in the browser console:
```js
localStorage.removeItem('tyrants-edge-save');
```
## Assets
```
assets/
├── fonts/ # RaiderCrusader (headers), Audiowide (body)
├── video/ # intro.mp4, menu_bg.mp4, campaign/mission backgrounds, forge video
├── audio/ # 6 battle music tracks, skill/action SFX, UI sounds
└── images/
├── cards/ # Card art (one image per card)
├── packs/ # Booster pack artwork
└── ui/ # vs icon, attack indicator, battle backgrounds, spritesheets
```
## Development Notes
- **No build step.** Edit any `.js` file and refresh the browser — ES modules are loaded directly.
- **No linting or test suite** is configured.
- **Phaser version** is pinned in `index.html` via CDN. Upgrade by changing the script URL.
- **Adding a card:** add an entry to `data/cards.json` and place the card art in `assets/images/cards/`. The card ID is used as the image key in `BootScene`.
- **Adding a skill:** implement the effect in `SkillProcessor.js` and add the reference entry to `data/skills.json`.
- **Adding a scene:** create the file in `src/scenes/`, then register it in `src/game.js`.
- **Animation timing:** stat changes must never appear before their animations. Use snapshot-before / refreshStatsOnly / restore-reapply patterns — see `feedback_animation_timing.md` in project memory.