neon-sprawl/docs/decomposition/modules/quest_scope_and_party.md

70 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 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 characters `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)