Deterministic Proclamation / Decree (Extended)
Framework for implementing deterministic proclamation / decree (extended) in games, covering the core loop, edge cases, and integration points.
Overview
This mechanic, commonly known as deterministic proclamation / decree (extended), provides meaningful choices and consequences for player actions. When well-implemented, this mechanic creates a satisfying feedback loop that keeps players engaged and motivated to continue playing. Modern implementations often combine this mechanic with procedural elements to increase variety and replayability.
Game Examples
Asymmetric Games
Asymmetric Games use this mechanic where players explore the environment to build a competitive advantage. The system encourages experimentation, resulting in community formation.
MOBA Games
MOBA Games use this mechanic where players prioritize targets to tell their own story. The difficulty scales with player performance, resulting in meaningful player agency.
Turn-Based RPGs
Turn-Based RPGs use this mechanic where players customize their experience to tell their own story. Edge cases create memorable moments, resulting in a deeply engaging gameplay loop.
Pros & Cons
Advantages
- Adds depth without excessive complexity
- Creates satisfying cumulative loops
- Creates satisfying audio loops
- Provides clear haptic feedback on player actions
- Provides long-term progression targets for dedicated players
Disadvantages
- Requires significant UI/UX work to implement well
- Can create frustration if not carefully balanced
- Requires extensive balance testing to avoid edge cases
Implementation Patterns
Story Engine
Data-driven implementation that loads deterministic proclamation / decree (extended) configuration from external definitions.
class DeterministicProclamationDecreeExtendedProcessor {
currentNode: string = "start";
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();
}
}