Let's create an interactive storytelling system that can work alongside our existing APIs:
// interactiveStorytelling.js
const { StoryElement } = require('./storyElements');
class Choice extends StoryElement {
constructor(id, text, consequences) {
super(id, { text, consequences });
}
execute(context) {
this.properties.consequences.forEach(consequence => consequence(context));
}
}
class InteractionPoint extends StoryElement {
constructor(id, description, choices) {
super(id, { description, choices });
}
addChoice(choice) {
this.properties.choices.push(choice);
}
getChoices() {
return this.properties.choices;
}
}
class InteractiveStoryManager {
constructor(storyGenerator) {
this.storyGenerator = storyGenerator;
this.currentInteractionPoint = null;
}
createInteractionPoint(id, description, choices) {
return new InteractionPoint(id, description, choices.map(c => new Choice(c.id, c.text, c.consequences)));
}
setCurrentInteractionPoint(interactionPoint) {
this.currentInteractionPoint = interactionPoint;
}
getCurrentChoices() {
return this.currentInteractionPoint ? this.currentInteractionPoint.getChoices() : [];
}
makeChoice(choiceId) {
const choice = this.currentInteractionPoint.getChoices().find(c => c.id === choiceId);
if (choice) {
choice.execute(this.storyGenerator.context);
this.currentInteractionPoint = null;
return true;
}
return false;
}
generateInteractiveStoryBeat() {
if (this.currentInteractionPoint) {
return {
type: 'interaction',
content: this.currentInteractionPoint.properties.description,
choices: this.getCurrentChoices().map(c => ({ id: c.id, text: c.properties.text }))
};
} else {
const beat = this.storyGenerator.generateStoryBeat();
if (Math.random() < 0.3) { // 30% chance of generating an interaction point
const interactionPoint = this.generateInteractionPoint(beat);
this.setCurrentInteractionPoint(interactionPoint);
return {
type: 'interaction',
content: interactionPoint.properties.description,
choices: this.getCurrentChoices().map(c => ({ id: c.id, text: c.properties.text }))
};
}
return beat;
}
}
generateInteractionPoint(beat) {
// This is a simplified version. In a real implementation, you'd generate meaningful choices based on the current story state.
const choices = [
{ id: 'choice1', text: 'Option A', consequences: [ctx => { /* Apply consequences */ }] },
{ id: 'choice2', text: 'Option B', consequences: [ctx => { /* Apply consequences */ }] },
];
return this.createInteractionPoint('interaction1', beat.content, choices);
}
}
module.exports = {
Choice,
InteractionPoint,
InteractiveStoryManager
};
Now, let's integrate this with our enhanced story generator:
// interactiveStoryGenerator.js
const EnhancedStoryGenerator = require('./enhancedStoryGenerator');
const { InteractiveStoryManager } = require('./interactiveStorytelling');
class InteractiveStoryGenerator extends EnhancedStoryGenerator {
constructor(genreExtension) {
super(genreExtension);
this.interactiveManager = new InteractiveStoryManager(this);
}
generateStoryBeat() {
return this.interactiveManager.generateInteractiveStoryBeat();
}
makeChoice(choiceId) {
return this.interactiveManager.makeChoice(choiceId);
}
getCurrentChoices() {
return this.interactiveManager.getCurrentChoices();
}
}
module.exports = InteractiveStoryGenerator;
Here's how you might use the interactive story generator:
// usage.js
const InteractiveStoryGenerator = require('./interactiveStoryGenerator');
const ScienceFictionExtension = require('./genres/scienceFiction');
const generator = new InteractiveStoryGenerator(ScienceFictionExtension);
// Initialize the story
generator.initializeStory(
'Galactic Frontier',
{ setting: 'Space Colony' },
[{ name: 'Captain Alex', backstory: 'Veteran space explorer', traits: ['brave', 'resourceful'] }],
[{ name: 'Alpha Centauri B', type: 'star system', properties: { planets: 3 } }],
[{ name: 'First Contact', description: 'Discovering alien life', plotPoints: [/* ... */] }]
);
// Generate story beats
let beat = generator.generateStoryBeat();
console.log(beat.content);
while (true) {
if (beat.type === 'interaction') {
console.log('Choose an option:');
beat.choices.forEach(choice => console.log(`${choice.id}: ${choice.text}`));
// In a real application, you'd get user input here
const choiceId = 'choice1'; // Simulating user choice
generator.makeChoice(choiceId);
}
beat = generator.generateStoryBeat();
console.log(beat.content);
// Add some condition to break the loop
}
With our interactive storytelling features in place, we can move on to other areas of improvement. What would you like to focus on next?