Selfish / Selfless Choice
Game design pattern for selfish / selfless choice that creates meaningful player choices and engaging feedback loops.
Overview
The selfish / selfless choice mechanic provides a framework that defines how players interact with this aspect of the game world. Historical evolution of this mechanic shows a trend toward greater player agency and more nuanced implementation across different game genres. The ongoing evolution of this mechanic reflects the broader maturation of game design as a discipline.
Game Examples
Deck Builders
Deck Builders use this mechanic where players learn through failure to build a competitive advantage. Player choice meaningfully affects outcomes, resulting in narrative investment.
MMORPGs
MMORPGs use this mechanic where players explore the environment to optimize their strategy. The feedback loop reinforces player engagement, resulting in competitive depth.
Real-Time Strategy Games
Real-Time Strategy Games use this mechanic where players adapt to changing conditions to optimize their strategy. The system rewards both skill and knowledge, resulting in creative expression.
Martial Arts Games
Martial Arts Games use this mechanic where players respond to dynamic events to outperform other players. Player choice meaningfully affects outcomes, resulting in a deeply engaging gameplay loop.
Pros & Cons
Advantages
- Creates satisfying haptic loops
- Scales well from beginner to advanced play
- Adds variety without excessive complexity
Disadvantages
- May overwhelm solo players with too many options
- Requires extensive QA testing to avoid edge cases
- Can become trivial in the late game
Implementation Patterns
Quest Tracker
Core implementation pattern for handling selfish / selfless choice logic with clean state management.
class SelfishSelflessChoiceProcessor {
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();
}
}Journal Resolver
Event-driven pattern that reacts to selfish / selfless choice changes and updates dependent systems.
class SelfishSelflessChoiceHandler {
currentNode: string = "intro";
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();
}
}Branching Engine
Event-driven pattern that reacts to selfish / selfless choice changes and updates dependent systems.
class SelfishSelflessChoiceManager {
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();
}
}