feat: Modularize scenario system and fix game mode configuration

Major Features:
- Extract scenario data from gameModeManager.js into individual files
- Create modular scenario loading system with browser compatibility
- Fix timed challenge and score target configuration options

� New Scenario Files:
- src/data/scenarios/index.js - Scenario loader and registry system
- src/data/scenarios/training-regimen.js - Personal Training Academy
- src/data/scenarios/dress-up-photo.js - Photography Studio scenario
- src/data/scenarios/creative-tasks.js - Creative Arts Academy
- src/data/scenarios/punishment-session.js - Disciplinary training

 Improvements:
- Removed 1976+ lines of embedded scenario data from gameModeManager.js
- Added browser-compatible module system using window.scenarioRegistry
- Fixed configuration dropdowns for timed and score target modes
- Enhanced game.js with proper event handling for custom inputs
- Added comprehensive logging and debugging capabilities

 Technical Changes:
- Updated gameModeManager.js to include config options in dynamic HTML
- Fixed event listener targeting for custom time/score inputs
- Added scripts for scenario extraction and management
- Maintained backward compatibility with existing game.js scenarios

 Benefits:
- Game content now easily editable in separate files
- Modular system allows easy addition/removal of scenarios
- Clean separation between game logic and content
- Improved maintainability and organization
This commit is contained in:
dilgenfritz 2025-10-28 06:41:01 -05:00
parent 3a57f1ce71
commit 5b3920ff0a
13 changed files with 1260 additions and 2001 deletions

View File

@ -1082,6 +1082,17 @@
</div>
<script src="src/data/gameData.js"></script>
<!-- Scenario System -->
<script src="src/data/scenarios/index.js"></script>
<script src="src/data/scenarios/training-regimen.js"></script>
<script src="src/data/scenarios/dress-up-photo.js"></script>
<script src="src/data/scenarios/creative-tasks.js"></script>
<script src="src/data/scenarios/punishment-session.js"></script>
<!-- Test Script (temporary) -->
<script src="test-scenarios.js"></script>
<!-- Statistics Modal -->
<div id="stats-modal" class="modal" style="display: none;">
<div class="modal-content">

View File

@ -0,0 +1,48 @@
const fs = require('fs');
const path = require('path');
// Read the current gameModeManager.js
const filePath = path.join(__dirname, '..', 'src', 'core', 'gameModeManager.js');
const content = fs.readFileSync(filePath, 'utf8');
// Find the start of getScenarioData method and the start of getScenarioFromGame method
const lines = content.split('\n');
let startRemoval = -1;
let endRemoval = -1;
// Find where the problematic data starts
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim() === 'return this.getScenarioFromGame(scenarioId);' && startRemoval === -1) {
startRemoval = i + 1; // Start removing after this line
}
if (lines[i].trim().includes('if (window.gameData && window.gameData.mainTasks)')) {
endRemoval = i - 1; // Stop removing before this line
break;
}
}
console.log(`Found removal range: lines ${startRemoval + 1} to ${endRemoval + 1}`);
if (startRemoval !== -1 && endRemoval !== -1 && startRemoval < endRemoval) {
// Remove the problematic lines
const cleanedLines = [
...lines.slice(0, startRemoval),
' }',
'',
' /**',
' * Get scenario data from the current game.js implementation',
' */',
' getScenarioFromGame(scenarioId) {',
' // This accesses the scenarios currently defined in game.js',
...lines.slice(endRemoval + 1)
];
const cleanedContent = cleanedLines.join('\n');
fs.writeFileSync(filePath, cleanedContent, 'utf8');
console.log('Fixed gameModeManager.js by removing orphaned scenario data');
console.log(`Removed ${endRemoval - startRemoval + 1} lines`);
} else {
console.log('Could not find proper removal boundaries');
console.log(`Start: ${startRemoval}, End: ${endRemoval}`);
}

View File

@ -0,0 +1,88 @@
/**
* Scenario Extractor Utility
* Analyzes gameModeManager.js to find scenario boundaries and extract them
*/
const fs = require('fs').promises;
const path = require('path');
async function analyzeScenarios() {
const filePath = path.join(__dirname, '..', 'src', 'core', 'gameModeManager.js');
const content = await fs.readFile(filePath, 'utf8');
const lines = content.split('\n');
console.log('🔍 Analyzing scenario structure in gameModeManager.js...\n');
// Find key markers
let scenarioMapStart = -1;
let additionalScenariosStart = -1;
let scenarioMapEnd = -1;
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (line.includes('const scenarioMap = {')) {
scenarioMapStart = i;
console.log(`📍 scenarioMap starts at line: ${i + 1}`);
}
if (line.includes('const additionalScenarios = {')) {
additionalScenariosStart = i;
console.log(`📍 additionalScenarios starts at line: ${i + 1}`);
}
if (line.includes('Object.assign(scenarioMap, additionalScenarios);')) {
scenarioMapEnd = i;
console.log(`📍 Scenario data ends at line: ${i + 1}`);
}
}
// Find individual scenarios
console.log('\n🎯 Individual Scenarios Found:');
const scenarioPattern = /^\s*'(scenario-[^']+)':\s*{/;
for (let i = scenarioMapStart; i < scenarioMapEnd; i++) {
const line = lines[i];
const match = line.match(scenarioPattern);
if (match) {
const scenarioId = match[1];
console.log(` - ${scenarioId} at line ${i + 1}`);
// Find the end of this scenario (look for closing brace at same indent level)
const indent = line.search(/\S/);
let endLine = -1;
let braceCount = 0;
for (let j = i; j < scenarioMapEnd; j++) {
const currentLine = lines[j];
// Count braces
for (const char of currentLine) {
if (char === '{') braceCount++;
if (char === '}') braceCount--;
}
// If we're back to the original indent level and braces are balanced
if (j > i && braceCount === 0 && currentLine.trim().endsWith('},')) {
endLine = j;
break;
}
}
if (endLine > 0) {
console.log(` └─ ends at line ${endLine + 1} (${endLine - i + 1} lines)`);
}
}
}
console.log('\n✅ Analysis complete!');
console.log(`📝 Total scenario data spans lines ${scenarioMapStart + 1} to ${scenarioMapEnd + 1}`);
}
// Run if called directly
if (require.main === module) {
analyzeScenarios().catch(console.error);
}
module.exports = { analyzeScenarios };

View File

@ -1959,37 +1959,53 @@ class TaskChallengeGame {
}
initializeGameModeListeners() {
console.log('🎮 Initializing game mode listeners...');
const gameModeRadios = document.querySelectorAll('input[name="gameMode"]');
gameModeRadios.forEach(radio => {
radio.addEventListener('change', () => this.handleGameModeChange());
console.log(`🎮 Found ${gameModeRadios.length} game mode radio buttons`);
gameModeRadios.forEach((radio, index) => {
console.log(`🎮 Radio ${index}: ${radio.id} (${radio.value})`);
radio.addEventListener('change', () => {
console.log(`🎮 Radio changed: ${radio.value}`);
this.handleGameModeChange();
});
});
// Add listeners for dropdown changes (if elements exist)
const timeLimitSelect = document.getElementById('time-limit-select');
if (timeLimitSelect) {
console.log('⏱️ Found time limit select, adding listener');
timeLimitSelect.addEventListener('change', () => {
console.log('⏱️ Time limit select changed');
this.handleTimeLimitChange();
});
} else {
console.log('⚠️ Time limit select not found');
}
const scoreTargetSelect = document.getElementById('score-target-select');
if (scoreTargetSelect) {
console.log('🏆 Found score target select, adding listener');
scoreTargetSelect.addEventListener('change', () => {
console.log('🏆 Score target select changed');
this.handleScoreTargetChange();
});
} else {
console.log('⚠️ Score target select not found');
}
// Add listeners for custom input changes (if elements exist)
const customTimeInput = document.getElementById('custom-time-input');
if (customTimeInput) {
customTimeInput.addEventListener('input', () => {
const customTimeValue = document.getElementById('custom-time-value');
if (customTimeValue) {
customTimeValue.addEventListener('input', () => {
this.handleCustomTimeChange();
});
}
const customScoreInput = document.getElementById('custom-score-input');
if (customScoreInput) {
customScoreInput.addEventListener('input', () => {
const customScoreValue = document.getElementById('custom-score-value');
if (customScoreValue) {
customScoreValue.addEventListener('input', () => {
this.handleCustomScoreChange();
});
}
@ -2004,45 +2020,63 @@ class TaskChallengeGame {
this.gameState.gameMode = selectedMode;
}
console.log(`🎮 Game mode changed to: ${selectedMode}`);
// Show/hide configuration options based on selected mode (if elements exist)
const timedConfig = document.getElementById('timed-config');
const scoreTargetConfig = document.getElementById('score-target-config');
// Hide all configs first
if (timedConfig) {
timedConfig.style.display = selectedMode === 'timed' ? 'block' : 'none';
timedConfig.style.display = 'none';
}
if (scoreTargetConfig) {
scoreTargetConfig.style.display = selectedMode === 'score-target' ? 'block' : 'none';
scoreTargetConfig.style.display = 'none';
}
// Update game state with selected values
if (selectedMode === 'timed') {
// Show appropriate config
if (selectedMode === 'timed' && timedConfig) {
timedConfig.style.display = 'block';
console.log('⏱️ Showing timed configuration options');
this.handleTimeLimitChange();
} else if (selectedMode === 'score-target') {
} else if (selectedMode === 'score-target' && scoreTargetConfig) {
scoreTargetConfig.style.display = 'block';
console.log('🏆 Showing score target configuration options');
this.handleScoreTargetChange();
}
console.log(`Game mode changed to: ${selectedMode}`, this.gameState);
console.log(`Game state updated:`, {
gameMode: this.gameState.gameMode,
timeLimit: this.gameState.timeLimit,
scoreTarget: this.gameState.scoreTarget
});
}
handleTimeLimitChange() {
const timeLimitSelect = document.getElementById('time-limit-select');
const customTimeInput = document.getElementById('custom-time-input');
if (!timeLimitSelect) return; // Exit if element doesn't exist
if (!timeLimitSelect) {
console.log('⚠️ Time limit select element not found');
return;
}
const selectedValue = timeLimitSelect.value;
console.log(`⏱️ Time limit selection: ${selectedValue}`);
if (customTimeInput) {
if (selectedValue === 'custom') {
customTimeInput.style.display = 'block';
console.log('⏱️ Showing custom time input');
this.handleCustomTimeChange();
} else {
customTimeInput.style.display = 'none';
this.gameState.timeLimit = parseInt(selectedValue);
console.log(`⏱️ Time limit set to: ${this.gameState.timeLimit} seconds`);
}
} else if (selectedValue !== 'custom') {
this.gameState.timeLimit = parseInt(selectedValue);
console.log(`⏱️ Time limit set to: ${this.gameState.timeLimit} seconds`);
}
}
@ -2050,36 +2084,45 @@ class TaskChallengeGame {
const scoreTargetSelect = document.getElementById('score-target-select');
const customScoreInput = document.getElementById('custom-score-input');
if (!scoreTargetSelect) return; // Exit if element doesn't exist
if (!scoreTargetSelect) {
console.log('⚠️ Score target select element not found');
return;
}
const selectedValue = scoreTargetSelect.value;
console.log(`🏆 Score target selection: ${selectedValue}`);
if (customScoreInput) {
if (selectedValue === 'custom') {
customScoreInput.style.display = 'block';
console.log('🏆 Showing custom score input');
this.handleCustomScoreChange();
} else {
customScoreInput.style.display = 'none';
this.gameState.scoreTarget = parseInt(selectedValue);
console.log(`🏆 Score target set to: ${this.gameState.scoreTarget} points`);
}
} else if (selectedValue !== 'custom') {
this.gameState.scoreTarget = parseInt(selectedValue);
console.log(`🏆 Score target set to: ${this.gameState.scoreTarget} points`);
}
}
handleCustomTimeChange() {
const customTimeInput = document.getElementById('custom-time-input');
if (customTimeInput) {
const minutes = parseInt(customTimeInput.value) || 15;
const customTimeValue = document.getElementById('custom-time-value');
if (customTimeValue) {
const minutes = parseInt(customTimeValue.value) || 15;
this.gameState.timeLimit = minutes * 60; // Convert minutes to seconds
console.log(`Custom time limit set to ${minutes} minutes (${this.gameState.timeLimit} seconds)`);
}
}
handleCustomScoreChange() {
const customScoreInput = document.getElementById('custom-score-input');
if (customScoreInput) {
const score = parseInt(customScoreInput.value) || 300;
const customScoreValue = document.getElementById('custom-score-value');
if (customScoreValue) {
const score = parseInt(customScoreValue.value) || 300;
this.gameState.scoreTarget = score;
console.log(`Custom score target set to ${score} points`);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,169 @@
/**
* Creative Tasks Scenario
* Creative expression and artistic challenges
*/
const scenarioData = {
text: "Creative Expression Challenge",
difficulty: "Medium",
interactiveData: {
title: "Creative Arts Academy",
steps: {
start: {
type: 'choice',
mood: 'artistically_inspiring',
story: "Welcome to the Creative Arts Academy. Your creative instructor reviews various art stations. 'Creative expression while aroused produces unique and powerful results. Different artistic mediums channel arousal differently. Which form of creative expression calls to you?'",
choices: [
{
text: "Written creative expression",
type: "writing",
preview: "Use arousal to fuel creative writing",
effects: { arousal: 10, control: 10 },
nextStep: "creative_writing_path"
},
{
text: "Performance and movement art",
type: "performance",
preview: "Express arousal through physical performance",
effects: { arousal: 15, control: 5 },
nextStep: "performance_art_path"
},
{
text: "Visual arts and drawing",
type: "visual",
preview: "Create visual art while aroused",
effects: { arousal: 12, control: 8 },
nextStep: "visual_art_path"
},
{
text: "Mixed media artistic creation",
type: "mixed_media",
preview: "Combine multiple art forms while aroused",
effects: { arousal: 12, control: 8 },
nextStep: "mixed_media_path"
}
]
},
creative_writing_path: {
type: 'action',
mood: 'literary',
story: "Your instructor provides writing materials. 'Creative writing allows deep exploration of thoughts and feelings. You'll write detailed, expressive stories while edging. Let your imagination flow as you describe your experiences and fantasies.'",
actionText: "Edge while writing creative and expressive stories",
duration: 240,
effects: { arousal: 25, control: 10 },
nextStep: "writing_evaluation"
},
performance_art_path: {
type: 'action',
mood: 'theatrical',
story: "Your instructor sets up a performance space. 'Performance art combines physical expression with emotional exposure. You'll act out creative scenarios while maintaining arousal. Become the character of your own artistic expression.'",
actionText: "Perform creative scenes while edging",
duration: 180,
effects: { arousal: 30, control: -5 },
nextStep: "performance_continuation"
},
visual_art_path: {
type: 'action',
mood: 'artistic',
story: "Your instructor provides art supplies. 'Visual art captures the energy of the moment. Edge while sketching or painting - let your arousal flow through your artistic expression. Create something beautiful and personal.'",
actionText: "Create visual art while edging",
duration: 300,
effects: { arousal: 20, control: 15 },
nextStep: "visual_progression"
},
mixed_media_path: {
type: 'action',
mood: 'experimental',
story: "Your instructor prepares multiple art stations. 'Mixed media combines all forms - writing, performance, visual, and movement. You'll rotate between stations, creating a complete artistic expression while maintaining constant arousal.'",
actionText: "Multi-station creative expression while edging",
duration: 300,
effects: { arousal: 35, control: -10, intensity: 1 },
nextStep: "artistic_mastery"
},
writing_evaluation: {
type: 'choice',
mood: 'literarily_accomplished',
story: "Your instructor reviews your writing. 'Excellent creative expression! Your writing shows real depth and creativity enhanced by arousal. Choose your next creative challenge.'",
choices: [
{
text: "Poetry and verse creation",
type: "poetry",
preview: "Express feelings through poetic form",
effects: { arousal: 15, control: 10 },
nextStep: "poetry_completion"
},
{
text: "Storytelling and narrative",
type: "narrative",
preview: "Create engaging stories and scenarios",
effects: { arousal: 10, control: 15 },
nextStep: "narrative_completion"
}
]
},
performance_continuation: {
type: 'action',
mood: 'dramatically_enhanced',
story: "Your instructor encourages your performance. 'Beautiful artistic expression! Now let's add more complexity. Continue performing while edging - let your arousal enhance your dramatic presence and emotional authenticity.'",
actionText: "Enhanced performance art while maintaining arousal",
duration: 240,
effects: { arousal: 40, control: -10 },
nextStep: "performance_mastery"
},
visual_progression: {
type: 'action',
mood: 'visually_inspired',
story: "Your instructor observes your artwork. 'Wonderful visual creativity! The arousal is clearly enhancing your artistic vision. Continue creating while edging - produce a complete artistic portfolio.'",
actionText: "Complete artistic portfolio creation while edging",
duration: 360,
effects: { arousal: 30, control: 20 },
nextStep: "visual_mastery"
},
artistic_mastery: {
type: 'ending',
mood: 'artistically_fulfilled',
story: "Your instructor reviews your complete artistic expression. 'Extraordinary creative work across all mediums. You've transformed arousal into art and created something truly unique while maintaining perfect control.'",
endingText: "Creative arts mastery achieved. Final state: Arousal {arousal}, Control {control}. You are now a certified multimedia artist.",
outcome: "artistic_master"
},
poetry_completion: {
type: 'ending',
mood: 'poetically_inspired',
story: "Your instructor reads your poetry. 'Beautiful poetic expression enhanced by arousal. You've learned to channel physical sensations into meaningful verse. Your poetry captures both passion and artistry.'",
endingText: "Poetry creation mastered. Final state: Arousal {arousal}, Control {control}. You have achieved poetic expression mastery.",
outcome: "poet_master"
},
narrative_completion: {
type: 'ending',
mood: 'narratively_accomplished',
story: "Your instructor reviews your stories. 'Compelling narrative creation! Arousal has enhanced your storytelling ability and creative imagination. Your stories are both engaging and artistically valuable.'",
endingText: "Narrative storytelling mastered. Final state: Arousal {arousal}, Control {control}. You are now a master storyteller.",
outcome: "narrative_master"
},
performance_mastery: {
type: 'ending',
mood: 'dramatically_masterful',
story: "Your instructor applauds your performance. 'Outstanding dramatic artistry! You've learned to use arousal to enhance emotional authenticity and stage presence. Your performance art is truly compelling.'",
endingText: "Performance art mastery achieved. Final state: Arousal {arousal}, Control {control}. You have mastered dramatic expression.",
outcome: "performance_master"
},
visual_mastery: {
type: 'ending',
mood: 'visually_masterful',
story: "Your instructor examines your complete portfolio. 'Exceptional visual artistry! Arousal has clearly enhanced your creative vision and artistic technique. Your artwork shows both skill and passionate expression.'",
endingText: "Visual arts mastery achieved. Final state: Arousal {arousal}, Control {control}. You are now a master visual artist.",
outcome: "visual_master"
}
}
}
};
// Register the scenario in the browser environment
if (typeof window !== 'undefined' && window.scenarioLoader) {
window.scenarioLoader.registerScenario('scenario-creative-tasks', scenarioData);
}
// Export for potential Node.js usage
if (typeof module !== 'undefined' && module.exports) {
module.exports = scenarioData;
}

View File

@ -0,0 +1,151 @@
/**
* Dress-Up Photo Session Scenario
* Photography studio themed scenario with dress-up elements
*/
const scenarioData = {
text: "Professional Photo Session",
difficulty: "Medium",
interactiveData: {
title: "Photography Studio Session",
steps: {
start: {
type: 'choice',
mood: 'professional',
story: "Welcome to the professional photography studio. Your photographer reviews various outfit options and poses. 'Today we're creating artistic photos that capture both beauty and sensuality. What type of session would you like to begin with?'",
choices: [
{
text: "Elegant fashion photography",
type: "fashion",
preview: "Sophisticated clothing and poses",
effects: { arousal: 8, control: 10 },
nextStep: "fashion_path"
},
{
text: "Artistic nude photography",
type: "artistic",
preview: "Tasteful artistic expression",
effects: { arousal: 15, control: 5 },
nextStep: "artistic_path"
},
{
text: "Themed costume photography",
type: "costume",
preview: "Fun themed outfits and scenarios",
effects: { arousal: 10, control: 8 },
nextStep: "costume_path"
},
{
text: "Intimate boudoir session",
type: "boudoir",
preview: "Sensual and intimate photography",
effects: { arousal: 20, control: -5 },
nextStep: "boudoir_path"
}
]
},
fashion_path: {
type: 'action',
mood: 'sophisticated',
story: "Your photographer sets up elegant lighting. 'Fashion photography is about confidence and grace. Put on this elegant outfit and we'll capture your natural beauty. Edge gently while posing - the arousal will give you a natural glow.'",
actionText: "Model elegant outfits while edging gently",
duration: 240,
effects: { arousal: 20, control: 15 },
nextStep: "fashion_progression"
},
artistic_path: {
type: 'action',
mood: 'artistic',
story: "Your photographer adjusts the artistic lighting. 'Artistic photography celebrates the human form. We'll create beautiful, tasteful images. Edge while posing artistically - let your arousal enhance your natural beauty.'",
actionText: "Pose artistically while edging to enhance natural beauty",
duration: 300,
effects: { arousal: 30, control: 10 },
nextStep: "artistic_progression"
},
costume_path: {
type: 'action',
mood: 'playful',
story: "Your photographer brings out various costumes. 'Themed photography lets you explore different personas. Choose a costume and become that character. Edge while embodying your chosen role.'",
actionText: "Dress up in costume and edge while staying in character",
duration: 180,
effects: { arousal: 25, control: 5 },
nextStep: "costume_progression"
},
boudoir_path: {
type: 'action',
mood: 'sensual',
story: "Your photographer dims the lights for intimate atmosphere. 'Boudoir photography captures sensuality and confidence. Edge while posing in intimate wear - let your arousal enhance the sensual energy.'",
actionText: "Pose sensually in intimate wear while edging",
duration: 360,
effects: { arousal: 35, control: -10 },
nextStep: "boudoir_progression"
},
fashion_progression: {
type: 'choice',
mood: 'elevated_fashion',
story: "Your photographer reviews the elegant shots. 'Beautiful work! The camera loves you. Ready for the next level of fashion photography?'",
choices: [
{
text: "High fashion avant-garde shoot",
type: "avant_garde",
preview: "Experimental and artistic fashion",
effects: { arousal: 10, control: 10 },
nextStep: "avant_garde_completion"
},
{
text: "Classic glamour photography",
type: "glamour",
preview: "Timeless Hollywood-style glamour",
effects: { arousal: 15, control: 5 },
nextStep: "glamour_completion"
}
]
},
artistic_progression: {
type: 'ending',
mood: 'artistically_fulfilled',
story: "Your photographer reviews the artistic shots. 'Extraordinary artistic expression captured. You've created beautiful art while maintaining perfect arousal control. These images celebrate both beauty and sensuality.'",
endingText: "Artistic photography session completed. Final state: Arousal {arousal}, Control {control}. You are now a certified artistic model.",
outcome: "artistic_model"
},
costume_progression: {
type: 'ending',
mood: 'playfully_satisfied',
story: "Your photographer reviews the themed shots. 'Fantastic character work! You really embodied each role perfectly. The costume photography captured both playfulness and sensuality beautifully.'",
endingText: "Themed costume photography completed. Final state: Arousal {arousal}, Control {control}. You have mastered character modeling.",
outcome: "character_model"
},
boudoir_progression: {
type: 'ending',
mood: 'sensually_confident',
story: "Your photographer reviews the intimate shots. 'Incredible sensual energy captured. You've learned to be beautifully vulnerable while maintaining arousal control. These boudoir images are stunning.'",
endingText: "Boudoir photography session completed. Final state: Arousal {arousal}, Control {control}. You have achieved sensual modeling mastery.",
outcome: "boudoir_master"
},
avant_garde_completion: {
type: 'ending',
mood: 'avant_garde_artist',
story: "Your photographer completes the experimental shoot. 'Cutting-edge fashion artistry achieved. You've pushed boundaries and created truly unique images that blend fashion with sensual energy.'",
endingText: "Avant-garde fashion photography completed. Final state: Arousal {arousal}, Control {control}. You are now a avant-garde fashion model.",
outcome: "avant_garde_model"
},
glamour_completion: {
type: 'ending',
mood: 'classic_glamour',
story: "Your photographer captures the final glamour shots. 'Timeless Hollywood glamour achieved perfectly. You've mastered the classic art of glamour photography while maintaining beautiful arousal energy.'",
endingText: "Classic glamour photography completed. Final state: Arousal {arousal}, Control {control}. You have achieved classic glamour status.",
outcome: "glamour_icon"
}
}
}
};
// Register the scenario in the browser environment
if (typeof window !== 'undefined' && window.scenarioLoader) {
window.scenarioLoader.registerScenario('scenario-dress-up-photo', scenarioData);
}
// Export for potential Node.js usage
if (typeof module !== 'undefined' && module.exports) {
module.exports = scenarioData;
}

View File

@ -0,0 +1,85 @@
/**
* Scenario Loader
* Loads and manages all game scenarios from individual files
* Browser-compatible version
*/
/**
* Scenario registry - maps scenario IDs to their data
* Individual scenario files will add themselves to this registry
*/
window.scenarioRegistry = window.scenarioRegistry || {};
/**
* Register a scenario
* @param {string} scenarioId - The ID of the scenario
* @param {Object} scenarioData - The scenario data
*/
function registerScenario(scenarioId, scenarioData) {
window.scenarioRegistry[scenarioId] = scenarioData;
console.log(`📝 Registered scenario: ${scenarioId}`);
}
/**
* Get scenario data by ID
* @param {string} scenarioId - The ID of the scenario to retrieve
* @returns {Object|null} The scenario data or null if not found
*/
function getScenario(scenarioId) {
return window.scenarioRegistry[scenarioId] || null;
}
/**
* Get all available scenario IDs
* @returns {string[]} Array of scenario IDs
*/
function getAvailableScenarios() {
return Object.keys(window.scenarioRegistry);
}
/**
* Check if a scenario exists
* @param {string} scenarioId - The ID of the scenario to check
* @returns {boolean} True if scenario exists
*/
function hasScenario(scenarioId) {
return scenarioId in window.scenarioRegistry;
}
/**
* Get scenario metadata (title, difficulty, etc.)
* @param {string} scenarioId - The ID of the scenario
* @returns {Object|null} Scenario metadata or null if not found
*/
function getScenarioMetadata(scenarioId) {
const scenario = getScenario(scenarioId);
if (!scenario) return null;
return {
id: scenarioId,
text: scenario.text,
difficulty: scenario.difficulty,
title: scenario.interactiveData?.title || scenario.text,
stepCount: scenario.interactiveData?.steps ? Object.keys(scenario.interactiveData.steps).length : 0
};
}
/**
* Get all scenario metadata
* @returns {Object[]} Array of scenario metadata objects
*/
function getAllScenarioMetadata() {
return getAvailableScenarios().map(id => getScenarioMetadata(id)).filter(Boolean);
}
// Make functions globally available
window.scenarioLoader = {
registerScenario,
getScenario,
getAvailableScenarios,
hasScenario,
getScenarioMetadata,
getAllScenarioMetadata
};
console.log('🎭 Scenario loader initialized');

View File

@ -0,0 +1,187 @@
/**
* Punishment Session Scenario
* Disciplinary training with consequences and correction
*/
const scenarioData = {
text: "Disciplinary Punishment Session",
difficulty: "Hard",
interactiveData: {
title: "Academy Punishment Division",
steps: {
start: {
type: 'choice',
mood: 'stern',
story: "You enter the Punishment Division of the Academy. The atmosphere is serious and intimidating. Your disciplinary instructor reviews your file. 'You're here because you need correction. Your attitude toward this punishment will determine its severity. How do you respond?'",
choices: [
{
text: "Accept responsibility and show genuine remorse",
type: "repentant",
preview: "Take ownership of your behavior",
effects: { arousal: 10, control: 10 },
nextStep: "remorseful_path"
},
{
text: "Submit completely to whatever punishment is deemed fit",
type: "submissive",
preview: "Total surrender to authority",
effects: { arousal: 15, control: -10 },
nextStep: "submission_path"
},
{
text: "Challenge the authority to punish you",
type: "defiant",
preview: "Question the legitimacy of punishment",
effects: { arousal: 5, control: 20 },
nextStep: "defiant_path"
},
{
text: "Remain silent and await judgment",
type: "stoic",
preview: "Neither resist nor surrender",
effects: { arousal: 8, control: 5 },
nextStep: "stoic_path"
}
]
},
remorseful_path: {
type: 'choice',
mood: 'stern_but_fair',
story: "Your instructor nods approvingly. 'Genuine remorse is noted. Since you accept responsibility, your punishment will be corrective rather than purely punitive. Choose the form of your corrective discipline.'",
choices: [
{
text: "Extended edging with reflection periods",
type: "reflective",
preview: "Combine physical discipline with contemplation",
effects: { arousal: 20, control: 15 },
nextStep: "reflective_discipline"
},
{
text: "Service-oriented punishment tasks",
type: "service",
preview: "Earn redemption through helpful actions",
effects: { arousal: 15, control: 10 },
nextStep: "service_discipline"
}
]
},
submission_path: {
type: 'action',
mood: 'disciplinary',
story: "Your instructor's expression hardens. 'Complete submission noted. You will undergo regulation punishment. Edge for exactly 2 minutes while maintaining perfect stillness. Any movement or loss of control will extend your punishment.'",
actionText: "Edge motionlessly for exactly 2 minutes",
duration: 120,
effects: { arousal: 25, control: -15 },
nextStep: "regulation_continuation"
},
defiant_path: {
type: 'action',
mood: 'harsh',
story: "Your instructor's eyes flash with controlled anger. 'Defiance will be corrected. You will edge while acknowledging why you deserve punishment, and you will continue until your defiance is completely replaced with proper submission.'",
actionText: "Edge while verbally acknowledging your need for discipline",
duration: 300,
effects: { arousal: 30, control: -25 },
nextStep: "defiance_correction"
},
stoic_path: {
type: 'action',
mood: 'measured',
story: "Your instructor observes your composure. 'Stoic acceptance noted. You will undergo measured discipline. Edge while maintaining absolute silence and stillness. Your ability to endure without reaction will be tested.'",
actionText: "Edge in complete silence and stillness",
duration: 240,
effects: { arousal: 20, control: 5 },
nextStep: "stoic_evaluation"
},
reflective_discipline: {
type: 'action',
mood: 'contemplative',
story: "Your instructor provides materials for reflection. 'Edge for 30 seconds, then stop and reflect on your behavior for 30 seconds. This cycle will continue until you achieve genuine understanding of your need for discipline.'",
actionText: "Alternate between edging and behavioral reflection",
duration: 360,
effects: { arousal: 35, control: 20 },
nextStep: "redemption_earned"
},
service_discipline: {
type: 'action',
mood: 'constructive',
story: "Your instructor assigns service tasks. 'You will edge while performing helpful tasks. This transforms your punishment into service, allowing you to earn redemption through contribution while maintaining disciplinary arousal.'",
actionText: "Edge while completing service tasks",
duration: 420,
effects: { arousal: 40, control: 25 },
nextStep: "service_completion"
},
regulation_continuation: {
type: 'action',
mood: 'regulatory',
story: "Your instructor checks a timer. 'Acceptable performance. Continue with regulation progression. Edge for 3 minutes while maintaining position. Your submission is being evaluated for sincerity.'",
actionText: "Continue edging in regulation punishment position",
duration: 180,
effects: { arousal: 35, control: -10 },
nextStep: "regulation_completion"
},
defiance_correction: {
type: 'action',
mood: 'transformative',
story: "Your instructor notes your changing attitude. 'Defiance is weakening. Continue edging while expressing your growing understanding of why you need discipline. Your resistance is being properly redirected.'",
actionText: "Edge while verbalizing your submission to discipline",
duration: 240,
effects: { arousal: 45, control: -35 },
nextStep: "complete_surrender"
},
stoic_evaluation: {
type: 'action',
mood: 'testing',
story: "Your instructor intensifies the evaluation. 'Admirable composure. Now we test deeper. Edge while maintaining perfect stillness even as intensity increases. True stoicism must be proven under pressure.'",
actionText: "Edge with increased intensity while maintaining stoic composure",
duration: 300,
effects: { arousal: 40, control: 10, intensity: 1 },
nextStep: "stoic_mastery"
},
redemption_earned: {
type: 'ending',
mood: 'redeemed',
story: "Your instructor reviews your reflection work. 'Genuine understanding achieved through proper discipline. You have earned redemption through sincere remorse and corrective action. Your punishment is complete.'",
endingText: "Punishment completed through redemption. Final state: Arousal {arousal}, Control {control}. You have learned and grown from discipline.",
outcome: "redeemed"
},
service_completion: {
type: 'ending',
mood: 'constructively_disciplined',
story: "Your instructor evaluates your service work. 'Exemplary service during punishment. You have transformed discipline into positive contribution. This demonstrates true understanding of corrective behavior.'",
endingText: "Service-oriented punishment completed. Final state: Arousal {arousal}, Control {control}. You have turned discipline into service.",
outcome: "service_oriented"
},
regulation_completion: {
type: 'ending',
mood: 'properly_disciplined',
story: "Your instructor completes the regulation procedure. 'Punishment administered according to standards. You have demonstrated proper submission to disciplinary authority. Lesson learned and recorded.'",
endingText: "Regulation punishment completed. Final state: Arousal {arousal}, Control {control}. You have been properly disciplined.",
outcome: "regulation_disciplined"
},
complete_surrender: {
type: 'ending',
mood: 'surrendered',
story: "Your instructor observes your complete transformation. 'Defiance completely eliminated. You now understand the necessity of discipline and proper authority. Your resistance has been properly channeled into submission.'",
endingText: "Defiance corrected through discipline. Final state: Arousal {arousal}, Control {control}. You have surrendered completely to proper authority.",
outcome: "defiance_corrected"
},
stoic_mastery: {
type: 'ending',
mood: 'stoically_disciplined',
story: "Your instructor acknowledges your composure. 'Impressive stoic discipline maintained under pressure. You have demonstrated that true strength comes from controlled acceptance of necessary discipline.'",
endingText: "Stoic discipline mastery achieved. Final state: Arousal {arousal}, Control {control}. You have proven strength through disciplined acceptance.",
outcome: "stoic_master"
}
}
}
};
// Register the scenario in the browser environment
if (typeof window !== 'undefined' && window.scenarioLoader) {
window.scenarioLoader.registerScenario('scenario-punishment-session', scenarioData);
}
// Export for potential Node.js usage
if (typeof module !== 'undefined' && module.exports) {
module.exports = scenarioData;
}

View File

View File

@ -0,0 +1,320 @@
/**
* Training Regimen Scenario
* Extended Personal Training Academy scenario
*/
const trainingRegimenScenario = {
text: "Extended Personal Training Academy",
difficulty: "Medium",
interactiveData: {
title: "Personal Training Academy",
steps: {
start: {
type: 'choice',
mood: 'professional',
story: "Welcome to the Personal Training Academy. Your trainer studies your profile carefully. 'I see you're here for comprehensive training. We have several specialized programs available. Which area would you like to focus on first?'",
choices: [
{
text: "Physical endurance training",
type: "athletic",
preview: "Focus on stamina and physical control",
effects: { arousal: 5, intensity: 1 },
nextStep: "physical_path"
},
{
text: "Mental discipline training",
type: "mental",
preview: "Develop psychological control",
effects: { arousal: 5, control: 15 },
nextStep: "mental_path"
},
{
text: "Submission and obedience training",
type: "submissive",
preview: "Learn proper obedience",
effects: { arousal: 10, control: -5 },
nextStep: "obedience_path"
},
{
text: "Advanced technique development",
type: "technical",
preview: "Master sophisticated methods",
effects: { arousal: 8, control: 10 },
nextStep: "technique_path"
}
]
},
physical_path: {
type: 'choice',
mood: 'athletic',
story: "Your trainer leads you to the endurance training area. 'Physical training requires building stamina while maintaining perfect control. We'll start with basic conditioning, then move to advanced exercises. How would you like to begin?'",
choices: [
{
text: "Start with basic warm-up",
preview: "Gentle introduction",
effects: { arousal: 10 },
nextStep: "basic_warmup"
},
{
text: "Jump straight to challenging exercises",
preview: "Intense immediate training",
effects: { arousal: 15, intensity: 2 },
nextStep: "intense_physical"
},
{
text: "I want to design my own routine",
preview: "Custom training program",
effects: { control: 10 },
nextStep: "custom_physical"
}
]
},
basic_warmup: {
type: 'action',
mood: 'encouraging',
story: "Your trainer guides you through proper warm-up technique. 'Start with gentle touches, build arousal slowly over 60 seconds. Focus on breathing and body awareness. This establishes your baseline.'",
actionText: "Gentle 60-second warm-up routine",
duration: 60,
effects: { arousal: 15, control: 10 },
nextStep: "warmup_assessment"
},
intense_physical: {
type: 'action',
mood: 'challenging',
story: "Your trainer nods approvingly. 'Ambitious. Let's see what you can handle. Edge vigorously for 45 seconds, then complete stop for 15 seconds. We'll repeat this cycle three times to test your limits.'",
actionText: "Intense edge-and-stop cycles",
duration: 180,
effects: { arousal: 30, control: -5, intensity: 1 },
nextStep: "endurance_training"
},
custom_physical: {
type: 'choice',
mood: 'collaborative',
story: "Your trainer is impressed. 'I like initiative. What type of physical challenge interests you most?'",
choices: [
{
text: "Endurance challenges",
preview: "Long-duration exercises",
nextStep: "endurance_training"
},
{
text: "Precision timing exercises",
preview: "Exact control training",
nextStep: "advanced_edging"
},
{
text: "Variable intensity training",
preview: "Dynamic difficulty changes",
nextStep: "training_advanced"
}
]
},
mental_path: {
type: 'choice',
mood: 'intellectual',
story: "Your trainer leads you to a quiet room. 'Mental discipline is the foundation of all advanced training. We'll explore psychological arousal, fantasy control, and mental submission. Which aspect calls to you?'",
choices: [
{
text: "Fantasy and imagination training",
preview: "Develop mental arousal skills",
effects: { arousal: 12 },
nextStep: "fantasy_training"
},
{
text: "Meditation and control techniques",
preview: "Learn mental discipline",
effects: { control: 20 },
nextStep: "endurance_training"
},
{
text: "Psychological submission exercises",
preview: "Mental obedience training",
effects: { arousal: 8, control: -8 },
nextStep: "full_submission"
}
]
},
obedience_path: {
type: 'choice',
mood: 'authoritative',
story: "Your trainer's demeanor becomes more commanding. 'Obedience training requires surrendering your will to instruction. You will learn to follow commands without question. Are you prepared to submit completely?'",
choices: [
{
text: "Yes, I'm ready to obey",
type: "submissive",
preview: "Complete submission",
effects: { arousal: 15, control: -15 },
nextStep: "full_submission"
},
{
text: "I want to maintain some control",
preview: "Partial submission",
effects: { arousal: 8, control: 5 },
nextStep: "endurance_training"
},
{
text: "I need to understand the rules first",
preview: "Learn submission protocols",
effects: { control: 10 },
nextStep: "training_advanced"
}
]
},
technique_path: {
type: 'choice',
mood: 'expert',
story: "Your trainer opens an advanced manual. 'Technique development focuses on sophisticated methods, precise control, and artistic expression. Which advanced skill would you like to master?'",
choices: [
{
text: "Advanced edging techniques",
preview: "Master complex edging patterns",
nextStep: "advanced_edging"
},
{
text: "Breathing and rhythm coordination",
preview: "Synchronize body and breath",
nextStep: "endurance_training"
},
{
text: "Multi-phase arousal building",
preview: "Complex arousal management",
nextStep: "training_advanced"
}
]
},
warmup_assessment: {
type: 'choice',
mood: 'evaluative',
story: "Your trainer observes your warm-up performance. 'Good baseline established. Arousal level {arousal}, control at {control}. Now let's advance your training. What's next?'",
choices: [
{
text: "Move to endurance training",
preview: "Build stamina",
nextStep: "endurance_training"
},
{
text: "Practice control techniques",
preview: "Develop precision",
nextStep: "advanced_edging"
},
{
text: "Try position and posture training",
preview: "Physical positioning",
nextStep: "posture_training"
}
]
},
fantasy_training: {
type: 'action',
mood: 'imaginative',
story: "Your trainer dims the lights. 'Close your eyes. Build arousal using only your imagination. Create a vivid fantasy scenario and let it excite you. No physical touch allowed - this is pure mental stimulation for 90 seconds.'",
actionText: "Pure fantasy arousal - no touching",
duration: 90,
effects: { arousal: 25, control: 15 },
nextStep: "training_advanced"
},
full_submission: {
type: 'action',
mood: 'commanding',
story: "Your trainer's voice becomes authoritative. 'Good. Now you will follow my instructions exactly. Edge for 30 seconds, stop for 10, repeat this cycle while I give you commands. Complete obedience is required.'",
actionText: "Follow precise obedience commands",
duration: 120,
effects: { arousal: 35, control: -20 },
nextStep: "training_advanced"
},
advanced_edging: {
type: 'action',
mood: 'technical',
story: "Your trainer demonstrates complex patterns. 'Advanced edging involves variable pressure, rhythm changes, and precise timing. Follow this pattern: 20 seconds fast, 10 seconds slow, 5 seconds stop, repeat four times.'",
actionText: "Execute advanced edging pattern",
duration: 140,
effects: { arousal: 30, control: 25 },
nextStep: "training_advanced"
},
endurance_training: {
type: 'action',
mood: 'determined',
story: "Your trainer sets a timer. 'Endurance training. Maintain steady arousal for 3 minutes without going over the edge. Consistency is key - no rushing, no stopping.'",
actionText: "3-minute endurance challenge",
duration: 180,
effects: { arousal: 35, control: 20 },
nextStep: "training_advanced"
},
posture_training: {
type: 'choice',
mood: 'instructional',
story: "Your trainer explains positioning. 'Proper posture affects arousal and control. Different positions create different sensations and levels of difficulty. Choose your training position.'",
choices: [
{
text: "Standing position training",
preview: "Vertical control exercises",
effects: { intensity: 1 },
nextStep: "training_advanced"
},
{
text: "Kneeling position training",
preview: "Submissive positioning",
effects: { arousal: 10, control: -5 },
nextStep: "master_challenges"
},
{
text: "Lying down position training",
preview: "Relaxed positioning",
effects: { control: 10 },
nextStep: "training_advanced"
}
]
},
training_advanced: {
type: 'choice',
mood: 'expert',
story: "Your trainer reviews your progress. 'Excellent development. You're ready for advanced training modules. These will truly test your abilities.'",
choices: [
{
text: "Master-level challenges",
preview: "Ultimate difficulty tests",
nextStep: "master_challenges"
},
{
text: "Complete the academy program",
preview: "Graduate with current skills",
nextStep: "academy_graduation"
},
{
text: "Request additional training",
preview: "Extend the program",
nextStep: "endurance_training"
}
]
},
master_challenges: {
type: 'action',
mood: 'extreme',
story: "Your trainer presents the ultimate challenge. 'This is master-level training. You will edge for 4 minutes with variable intensity, changing technique every 30 seconds, while maintaining perfect control. This separates novices from experts.'",
actionText: "Master-level variable technique challenge",
duration: 240,
effects: { arousal: 50, control: 30, intensity: 2 },
nextStep: "academy_graduation"
},
academy_graduation: {
type: 'ending',
mood: 'proud',
story: "Your trainer stands and applauds. 'Congratulations. You have completed the Personal Training Academy with distinction. Your final performance demonstrates mastery of multiple skills.'",
endingText: "Academy graduation achieved! Final state: Arousal {arousal}, Control {control}, Intensity {intensity}. You are now a certified practitioner.",
outcome: "graduated"
}
}
}
};
// Register this scenario when the script loads
if (typeof window !== 'undefined' && window.scenarioLoader) {
window.scenarioLoader.registerScenario('scenario-training-regimen', trainingRegimenScenario);
} else {
// If loader isn't ready yet, wait for it
document.addEventListener('DOMContentLoaded', () => {
if (window.scenarioLoader) {
window.scenarioLoader.registerScenario('scenario-training-regimen', trainingRegimenScenario);
}
});
}

40
test-scenarios.js Normal file
View File

@ -0,0 +1,40 @@
/**
* Test Scenario Loading System
* Quick test to verify scenarios are registering properly
*/
// Wait for window to load
window.addEventListener('load', () => {
console.log('🧪 Testing Scenario Loading System...');
if (window.scenarioLoader) {
console.log('✅ Scenario loader is available');
// Test individual scenarios
const testScenarios = [
'scenario-training-regimen',
'scenario-dress-up-photo',
'scenario-creative-tasks',
'scenario-punishment-session'
];
console.log('\n📋 Testing Individual Scenarios:');
testScenarios.forEach(scenarioId => {
if (window.scenarioLoader.hasScenario(scenarioId)) {
console.log(`${scenarioId} - Loaded successfully`);
const data = window.scenarioLoader.getScenario(scenarioId);
console.log(` Title: ${data.interactiveData?.title || 'No title'}`);
console.log(` Difficulty: ${data.difficulty || 'No difficulty'}`);
} else {
console.log(`${scenarioId} - NOT FOUND`);
}
});
console.log('\n📊 Summary:');
console.log(`Total scenarios registered: ${Object.keys(window.scenarioRegistry || {}).length}`);
console.log('Registered scenarios:', Object.keys(window.scenarioRegistry || {}));
} else {
console.log('❌ Scenario loader not found!');
}
});

43
test/scenario-test.html Normal file
View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<title>Scenario System Test</title>
</head>
<body>
<h1>Scenario System Test</h1>
<div id="status">Loading...</div>
<div id="scenarios"></div>
<script src="../src/data/scenarios/index.js"></script>
<script src="../src/data/scenarios/training-regimen.js"></script>
<script>
// Test the scenario loading system
document.addEventListener('DOMContentLoaded', function() {
const statusDiv = document.getElementById('status');
const scenariosDiv = document.getElementById('scenarios');
// Check if window.scenarioLoader exists
if (window.scenarioLoader) {
statusDiv.innerHTML = '<span style="color: green;">✓ Scenario loader initialized</span>';
// Check available scenarios
const availableScenarios = window.scenarioLoader.getAvailableScenarios();
scenariosDiv.innerHTML = '<h2>Available Scenarios:</h2><ul>' +
availableScenarios.map(id => `<li>${id}</li>`).join('') + '</ul>';
// Test loading a specific scenario
if (window.scenarioLoader.hasScenario('scenario-training-regimen')) {
const scenario = window.scenarioLoader.getScenario('scenario-training-regimen');
scenariosDiv.innerHTML += '<h2>Training Regimen Scenario:</h2>' +
'<p><strong>Title:</strong> ' + scenario.interactiveData.title + '</p>' +
'<p><strong>Difficulty:</strong> ' + scenario.difficulty + '</p>';
} else {
scenariosDiv.innerHTML += '<p style="color: red;">❌ Training regimen scenario not found</p>';
}
} else {
statusDiv.innerHTML = '<span style="color: red;">❌ Scenario loader not found</span>';
}
});
</script>
</body>
</html>