Epistolary / Found Document
Mechanic governing epistolary / found document behavior, establishing rules for player interaction, feedback, and progression within this system.
Overview
Epistolary / Found Document is a fundamental game mechanic that provides meaningful choices and consequences for player actions. Designers must carefully balance the system's depth against its learning curve, ensuring that new players can engage while experienced players find room for mastery. Cross-genre adoption of this mechanic demonstrates its versatility and fundamental appeal to players across different gaming preferences.
Game Examples
First-Person Shooters
First-Person Shooters use this mechanic where players react to emergent situations to survive increasingly difficult challenges. Player choice meaningfully affects outcomes, resulting in exploration incentives.
Tactical Shooters
Tactical Shooters use this mechanic where players coordinate with teammates to discover hidden content. The mechanic respects player time and investment, resulting in long-term engagement.
Space Simulators
Space Simulators use this mechanic where players plan their approach to optimize their strategy. The system rewards both skill and knowledge, resulting in satisfying progression.
Pros & Cons
Advantages
- Enables strategic player expression
- Creates meaningful strategic decisions for players
- Supports several viable strategies and approaches
- Provides long-term collection objectives for dedicated players
Disadvantages
- Creates potential for cheese strategies by experienced players
- Increases network requirements significantly
- May create an entry barrier for new players
Implementation Patterns
Story Engine
Optimized pattern for epistolary / found document that minimizes per-frame computation cost.
class EpistolaryFoundDocumentHandler {
currentNode: string = "greeting";
flags: Set<string> = new Set();
getDialogue() {
const node = DIALOGUE_TREE[this.currentNode];
return {
text: node.text,
choices: node.choices.filter(c =>
!c.requires || c.requires.every(f => this.flags.has(f))
)
};
}
choose(choiceIndex: number) {
const node = DIALOGUE_TREE[this.currentNode];
const choice = node.choices[choiceIndex];
if (choice.setsFlag) this.flags.add(choice.setsFlag);
this.currentNode = choice.next;
return this.getDialogue();
}
}NPC Scheduler
A modular approach to epistolary / found document that separates concerns and enables easy testing.
class EpistolaryFoundDocumentHandler {
currentNode: string = "greeting";
flags: Set<string> = new Set();
getDialogue() {
const node = DIALOGUE_TREE[this.currentNode];
return {
text: node.text,
choices: node.choices.filter(c =>
!c.requires || c.requires.every(f => this.flags.has(f))
)
};
}
choose(choiceIndex: number) {
const node = DIALOGUE_TREE[this.currentNode];
const choice = node.choices[choiceIndex];
if (choice.setsFlag) this.flags.add(choice.setsFlag);
this.currentNode = choice.next;
return this.getDialogue();
}
}Story Engine
Core implementation pattern for handling epistolary / found document logic with clean state management.
class EpistolaryFoundDocumentProcessor {
currentNode: string = "opening";
flags: Set<string> = new Set();
getDialogue() {
const node = DIALOGUE_TREE[this.currentNode];
return {
text: node.text,
choices: node.choices.filter(c =>
!c.requires || c.requires.every(f => this.flags.has(f))
)
};
}
choose(choiceIndex: number) {
const node = DIALOGUE_TREE[this.currentNode];
const choice = node.choices[choiceIndex];
if (choice.setsFlag) this.flags.add(choice.setsFlag);
this.currentNode = choice.next;
return this.getDialogue();
}
}