# Quest scope and party rules

This doc fixes **solo vs party** quest behavior: where `QuestStepState` lives, who gets credit, who can turn in, and how open-world vs instanced scope is handled. It complements [E7.M1 — QuestStateMachine](E7_M1_QuestStateMachine.md), [E7.M2 — RewardAndUnlockRouter](E7_M2_RewardAndUnlockRouter.md), and [E8.M1 — PartyAndMatchAssembly](E8_M1_PartyAndMatchAssembly.md).

---

## Persistence: per-character by default

- **Authoritative state** for a quest is stored **per character** (`QuestStepState` keyed by character / player id, plus quest id and any run id if replays exist).
- There is **no** single shared “party quest row” in the prototype model; party play is expressed by **synchronizing advances** across multiple per-character states when content opts in (see below).

**Rationale:** Avoids orphan state when members leave the party, keeps abandon/reset rules simple, and matches “solo-friendly” progression with optional co-op credit.

---

## Quest modes (content-driven)

Express in **`QuestDef`** (or equivalent content) — exact field names are for the content schema when added:

| Mode | Behavior |
|------|----------|
| **Solo (default)** | Objectives and completion use **only** the acting character. No read of [E8.M1](E8_M1_PartyAndMatchAssembly.md) `PartyState`. |
| **Party credit** | When an objective completes, the server evaluates **eligible party members** and advances **each** eligible character’s `QuestStepState` **idem**potently (same step transition, no double-apply). Eligibility rules are data-driven, e.g. in zone, within distance of completer, alive, was in party when step started—minimum set TBD per quest in content. |
| **Leader-only turn-in (optional)** | If set, only the **party leader** (per authoritative `PartyState`) may trigger the final hand-in / complete interaction; otherwise **any** character in completable state may turn in. |

**Starting / accepting:** Each character **accepts** the quest individually unless content defines a rare “party accepts as one” flow (defer unless needed); prototype can require all intended recipients to accept the same quest id.

---

## Party dependency

- **Party credit** and **leader-only turn-in** require server-authoritative **party membership** from [E8.M1 — PartyAndMatchAssembly](E8_M1_PartyAndMatchAssembly.md).
- **Milestone ordering:** Solo quests ship without E8.M1. **Party-credit** quests are **gated** until E8.M1 (or a minimal stub that returns “solo only”) exists; document in slice plans.

---

## Rewards: E7.M2

- After completion, **rewards are granted per character** with **idempotent** keys (e.g. `(character_id, quest_id, completion_epoch_or_counter)`).
- If **party credit** advanced multiple characters to completion in one logical event, **each** receives their bundle per `QuestRewardBundle` rules (same bundle vs per-role bundles—content choice).

---

## Open world vs instances (prototype)

- **Prototype default:** Objectives live in **shared zones** ([E4.M1](E4_M1_ZoneGraphAndTravelRules.md)); no separate quest instance id required.
- **Instanced steps (later):** When dungeon / private instance exists, bind objectives to an **`instance_id`** (or shard key) so credit does not leak across instances. Wire when instance module and E4 handoff slices define the authoritative instance handle.

---

## Edge cases (explicit)

- **Member leaves party mid-quest:** Per-character state **freezes** at last server-advanced step unless `QuestDef` defines abandon-on-leave. No implicit merge of two solo runs into one party run.
- **Disband:** Same as leave for remaining members; leader-only turn-in re-evaluates on next `PartyState` update.

---

## Telemetry

- Emit `quest_step_complete` / `quest_complete` **per character** credited; optional correlation id linking party-synchronized advances for funnel debugging.

---

## Related docs

- [E7.M1 — QuestStateMachine](E7_M1_QuestStateMachine.md)
- [E7.M2 — RewardAndUnlockRouter](E7_M2_RewardAndUnlockRouter.md)
- [E8.M1 — PartyAndMatchAssembly](E8_M1_PartyAndMatchAssembly.md)
- [Module dependency register — cross-cutting: quests and party](module_dependency_register.md#cross-cutting-quests-and-party)
