# Dungeon Raids

## Overview
Dungeon Raids are timed, global PvE gate events. They are **not** player-created: the server automatically spawns a dungeon gate, players sign up with `.join dungeon raid`, and then each participant runs their own copied dungeon path using their active team.

This system is separate from **Tower Dungeon**:
- **Dungeon Raid** = timed global event, chat signup, up to 6 players, each player fights their own copied sequence.
- **Tower Dungeon** = sidebar-first squad climb with real-time combat, checkpoints, and Tower Tokens.

## Commands

| Command | What it does | Notes |
|---|---|---|
| `.join dungeon raid` | Joins the currently open gate | Only works while a gate is open |
| `.admin01 dungeon open` | Force-spawns a dungeon gate | Admin-only testing command |

## Core Mechanics

### Spawn cadence
- Gate spawn interval: **every 4 hours**
- Signup/join window: **3 minutes**
- Max participants: **6**
- Gate announcements are broadcast to: `general`, `general-2`, `chat`, `guilds`, `battle`, `gambling`, `trading`, `off-topic`

The next scheduled spawn time is stored in `event_state` under `next_dungeon_spawn_at`.

### Rank weights and requirements

| Rank | Spawn Weight | Enemy Tiers | Min Level | Entry Cost |
|---|---:|---|---:|---:|
| D | 15% | Uncommon / Rare / Epic | 2 | 1,000 coins |
| C | 35% | Rare / Epic / Mythic | 5 | 2,000 coins |
| B | 25% | Epic / Mythic / Legendary | 10 | 3,000 coins |
| A | 15% | Mythic / Legendary / Fabled | 20 | 4,000 coins |
| S | 10% | Legendary / Fabled / Gods | 30 | 5,000 coins |

### Join checks and fee timing
At **join time**, the code checks:
- the gate is open,
- you are not already in the gate,
- the raid is not full,
- your level and coins meet the rank requirements.

At **raid start**, the code checks requirements **again** and only then deducts the entry fee. Ineligible players are skipped.

## Dungeon Structure

### Wave layout
Each generated dungeon contains:

| Segment | Enemy Count |
|---|---:|
| Wave 1 | 60 |
| Wave 2 | 70 |
| Wave 3 | 100 |
| Boss | 1 |

### Enemy distribution in multiplayer
The full wave is generated once, then split across players **round-robin**.

Example with 4 players:
- Player 1 gets enemies at indices `0, 4, 8, ...`
- Player 2 gets `1, 5, 9, ...`
- Player 3 gets `2, 6, 10, ...`
- Player 4 gets `3, 7, 11, ...`

Each player also gets their **own cloned boss entity**, so boss combat is not shared HP.

### Enemy builds
The generator creates enemy pools from 5 preset build templates per animal:

| Enemy build | Weapon |
|---|---|
| Level 10 | `DGR3` (Fabled Dagger) |
| Level 15 | `SCY3` (Fabled Scythe) |
| Level 25 | `SWD3` (Fabled Sword) |
| Level 28 | `HMR3` (Fabled Hammer) |
| Level 29 | `SWD3` (Fabled Sword) |

### Boss generation
The boss is built from the **highest tier** allowed by the dungeon rank.

Boss rules:
- Uses the evolved form if the base animal can evolve.
- Level is fixed at **50**.
- HP multiplier: **1.5x to 2.0x**.
- ATK multiplier: **1.08x to 1.14x**.
- Boss weapon: random **Fabled weapon**.
- Reward logic still treats the boss as the **base animal** for drop naming purposes.

## Combat Rules
- Dungeon Raid uses `simulateDungeonEncounter()` from `server/dungeonBattle.js`.
- This is **not** the Tower real-time engine.
- Player team HP and mana state carry forward through that player's full sequence.
- If all of a player's animals die, that player's run ends immediately.
- Enchantment usage is consumed after the raid path resolves.

## Rewards

### Final-blow coin reward
Only players who both **clear** and land the boss **final blow** get the rank coin reward.

| Rank | Coins |
|---|---:|
| D | 5,000 |
| C | 10,000 |
| B | 20,000 |
| A | 40,000 |
| S | 100,000 |

### Wave animal drops
Wave drops are rolled per player during that player's run.

| Wave | Drop Chance |
|---|---:|
| Wave 1 | 50% |
| Wave 2 | 70% |
| Wave 3 | 90% |

Rules:
- Maximum **3 animals** per raid.
- The dropped animal is chosen from a random enemy in that wave.
- Inserted drops are stored as normal `animals` rows.
- Dungeon animals are inserted with `trade_locked=1` by default.

### Evolution stone roll
The dungeon rolls **one shared stone** for the entire raid, then gives it to one random player who cleared.

The code does this in two steps:
1. choose one random eligible stone type for the rank,
2. roll that stone's chance.

#### Effective stone outcomes by rank

| Rank | Possible outcomes |
|---|---|
| D | 60% Mythic, otherwise none |
| C | 30% Mythic, 15% Legendary, 55% none |
| B | 20% Mythic, 10% Legendary, 6.67% Fabled, 63.33% none |
| A / S | 15% Mythic, 7.5% Legendary, 5% Fabled, 2.5% Gods, 70% none |

### Other clear rewards
On a successful clear, the code also rolls:
- **10%** chance for a Sacrificial Diamond (`material: SDMND`)
- **10%** chance for a crate/lootbox reward path

## MVP Logic
The intended MVP sort order is:
1. highest damage,
2. fastest clear time,
3. final blow.

The ranking function in `mvpSystem.js` does support that ordering.

## Database / Storage Details

### Persistent state
- `event_state.next_dungeon_spawn_at` stores the next scheduled gate spawn time.
- `messages.rich_data` stores the published dungeon result payload for chat history.
- `users.dungeon_wins` increments on successful clears.
- `users.highest_dungeon_damage` stores personal best damage.
- Awarded stones/diamonds are stored in `inventory`.
- Dropped animals are inserted into `animals`.

### Non-persistent state
The active open gate itself is in memory only:
- current open gate
- participant list
- join countdown

A server restart during an open signup window will lose that gate.

## Limitations / Code-Behavior Notes
- The live code is **4 hours / 3 minutes**, not the older 5-hour / 60-second behavior found in stale docs.
- The crate/lootbox reward path in `commitRewards()` still tries to update `users.weapon_crates` / `users.lootboxes`, but those columns do not exist in the live `users` schema. That reward path appears legacy and likely fails to grant the reward correctly.
- `runPlayerDungeon()` preserves `pendingAnimals` when a player dies, but `executeRaid()` only commits those drops for `r.cleared`, so failed players do **not** actually receive previously earned wave drops.
- `computeMvp()` expects `completionTimeMs`, but `executeRaid()` does not pass that field into the MVP input object. In practice, the current MVP calculation is effectively damage-first with final-blow fallback, not a working time tie-break.

## Strategic Tips / Balance Notes
- Bring a fully prepared active team before joining; once the raid starts, your copied path uses whatever active team setup the server reads then.
- More players reduce each player's enemy count per wave because of round-robin splitting.
- Because the boss is cloned per player, one player's failure does not directly lower another player's boss HP.
- Rank A/S are the only ranks that can ever produce a Gods stone roll.
- Dungeon Raids remain the main evolution-stone source wired into evolution/crafting help text, even though the reward implementation has a few legacy edges.