/**
* Game Mode Manager
* Handles different game modes including scenario-based modes
*/
class GameModeManager {
constructor() {
this.currentMode = 'standard'; // Default to standard mode
this.availableModes = {
'photography-studio': {
name: 'Photography Studio',
description: 'Dedicated webcam photography and dressing sessions',
icon: '📸'
},
'training-academy': {
name: 'Training Academy',
description: 'Structured training programs and challenges',
icon: '🎓'
},
'punishment-gauntlet': {
name: 'Punishment Gauntlet',
description: 'Face intense punishment and humiliation challenges',
icon: '⛓️'
},
'endurance-trials': {
name: 'Endurance Trials',
description: 'Test your limits with marathon sessions',
icon: '💪'
}
};
// Scenario collections for different modes - UPDATED WITH CORRECT AVAILABLE SCENARIOS
this.scenarioCollections = {
'photography-studio': [
'scenario-dress-up-photo'
],
'training-academy': [
'scenario-training-regimen',
'scenario-creative-tasks',
'scenario-training-session',
'scenario-obedience-training'
],
'punishment-gauntlet': [
'scenario-punishment-session',
'scenario-humiliation-task'
],
'endurance-trials': [
'scenario-training-regimen',
'scenario-edging-marathon'
],
'worship-session': [
'scenario-worship-session'
]
};
this.currentScenarios = [];
this.customTasksEnabled = true;
this.customTaskFrequency = 0.3; // 30% chance to include custom tasks
}
/**
* Initialize the game mode system
*/
init() {
console.log('🎮 Initializing GameModeManager...');
this.setupModeSelectionUI();
this.bindEvents();
console.log('🎮 GameModeManager initialization complete');
}
/**
* Setup the mode selection UI
*/
setupModeSelectionUI() {
// Remove hint button from existing scenarios first
this.removeHintButtons();
// Replace the existing timed/score game modes with our new modes
const gameModeSelection = document.querySelector('.game-mode-selection');
console.log('🔍 Looking for .game-mode-selection element:', gameModeSelection);
if (gameModeSelection) {
console.log('✅ Found game mode selection, replacing with updated modes');
gameModeSelection.innerHTML = `
Choose Your Game Mode
${Object.entries(this.availableModes).map(([key, mode]) => `
`).join('')}
`;
// Add event listeners for the new controls
this.bindEvents();
// Verify the radio buttons were created
const radioButtons = gameModeSelection.querySelectorAll('input[name="gameMode"]');
console.log(`🔘 Created ${radioButtons.length} radio buttons:`, Array.from(radioButtons).map(r => r.value));
} else {
console.log('⚠️ Game mode selection element not found - skipping UI setup (likely in dedicated screen)');
}
}
/**
* Remove hint buttons from scenarios in game.js
*/
removeHintButtons() {
// This will be handled by modifying the interactive task display
console.log('Hint buttons will be removed from scenario display');
}
/**
* Bind events for mode selection
*/
bindEvents() {
console.log('🔗 Binding GameModeManager events...');
// Mode selection
document.addEventListener('change', (e) => {
console.log('🎯 Change event detected:', e.target.name, e.target.value);
if (e.target.name === 'gameMode') {
console.log('🎮 Game mode radio button changed to:', e.target.value);
this.handleModeChange(e.target.value);
}
});
// Also try click events on the cards themselves
document.addEventListener('click', (e) => {
const card = e.target.closest('.game-mode-card');
if (card) {
const mode = card.dataset.mode;
const radio = card.querySelector('input[type="radio"]');
if (radio && mode) {
radio.checked = true;
this.handleModeChange(mode);
}
}
});
console.log('🔗 Events bound successfully');
// Custom task frequency slider
const frequencySlider = document.getElementById('frequency-slider');
const frequencyDisplay = document.getElementById('frequency-display');
if (frequencySlider && frequencyDisplay) {
frequencySlider.addEventListener('input', (e) => {
const value = e.target.value;
frequencyDisplay.textContent = `${value}%`;
this.customTaskFrequency = value / 100;
});
}
// Custom tasks toggle
const customTasksToggle = document.getElementById('include-custom-tasks');
if (customTasksToggle) {
customTasksToggle.addEventListener('change', (e) => {
this.customTasksEnabled = e.target.checked;
const frequencyControl = document.getElementById('custom-task-frequency');
if (frequencyControl) {
frequencyControl.style.display = e.target.checked ? 'block' : 'none';
}
});
}
}
/**
* Handle mode selection change
*/
handleModeChange(mode) {
this.currentMode = mode;
// Show/hide mode-specific options
const allConfigs = document.querySelectorAll('.mode-config');
allConfigs.forEach(config => config.style.display = 'none');
// Show scenario config for scenario modes
const scenarioConfig = document.getElementById('scenario-config');
if (scenarioConfig) {
scenarioConfig.style.display = 'block';
console.log('🎮 Showing scenario configuration');
}
// Update UI to highlight selected mode
document.querySelectorAll('.game-mode-card').forEach(card => {
card.classList.remove('selected');
});
document.querySelector(`[data-mode="${mode}"]`)?.classList.add('selected');
}
/**
* Get tasks for the current game mode
*/
getTasksForMode() {
if (this.currentMode === 'standard' || this.currentMode === 'timed' || this.currentMode === 'scored') {
return this.getStandardTasks();
} else {
return this.getScenarioModeTasks();
}
}
/**
* Map new mode names to original game functionality
*/
getGameModeForEngine() {
// Quick Play mode uses timed mode as the base
if (this.currentMode === 'quick-play') {
return 'timed';
} else {
// Scenario modes use complete-all as base
return 'complete-all';
}
}
/**
* Get standard game tasks (using new data system)
*/
getStandardTasks() {
// Use the new data manager for standard tasks
if (window.gameDataManager) {
console.log(`📋 Using GameDataManager for standard tasks`);
return window.gameDataManager.getTasksForMode('standard');
}
// Fallback to legacy system
console.log(`⚠️ GameDataManager not available, using legacy gameData`);
return window.gameData?.mainTasks || [];
}
/**
* Get tasks for scenario-based modes
*/
getScenarioModeTasks() {
// Use the new data manager to get mode-specific data
if (window.gameDataManager) {
const tasks = window.gameDataManager.getTasksForMode(this.currentMode);
const scenarios = window.gameDataManager.getScenariosForMode(this.currentMode);
// Combine tasks and scenarios into the format expected by the game
const allTasks = [];
// Add scenarios FIRST (so they get priority in selection)
scenarios.forEach(scenario => {
const gameTask = {
id: scenario.id,
text: scenario.text,
difficulty: scenario.difficulty,
type: 'main',
interactiveType: scenario.interactiveType,
interactiveData: scenario.interactiveData,
isScenario: true,
image: this.getRandomScenarioImage()
};
allTasks.push(gameTask);
});
// Add regular tasks AFTER scenarios
tasks.forEach(task => {
const gameTask = {
id: task.id,
text: task.text,
difficulty: task.difficulty,
type: 'main',
interactiveType: task.interactiveType,
story: task.story,
mirrorInstructions: task.mirrorInstructions,
mirrorTaskText: task.mirrorTaskText,
isScenario: false,
image: this.getRandomScenarioImage()
};
allTasks.push(gameTask);
});
return allTasks;
}
// Fallback to old system if data manager not available
console.warn('GameDataManager not available, using fallback system');
return this.getScenarioModeTasksLegacy();
}
/**
* Legacy method for getting scenario tasks (fallback)
*/
getScenarioModeTasksLegacy() {
const tasks = [];
const scenarios = this.scenarioCollections[this.currentMode] || [];
console.log(`📋 Available scenarios for ${this.currentMode}:`, scenarios);
// Add scenario tasks
scenarios.forEach(scenarioId => {
const scenarioTask = this.createScenarioTask(scenarioId);
console.log(`🎬 Created scenario task for ${scenarioId}:`, scenarioTask ? 'Success' : 'Failed');
if (scenarioTask) {
tasks.push(scenarioTask);
}
});
console.log(`🎯 Created ${tasks.length} scenario tasks`);
// Intersperse custom tasks if enabled
if (this.customTasksEnabled) {
const customTasks = this.getCustomTasks();
console.log(`📦 Found ${customTasks.length} custom tasks`);
if (tasks.length === 0 && customTasks.length > 0) {
// If no scenarios but custom tasks available, use custom tasks
console.log(`⚠️ No scenarios available, falling back to custom tasks only`);
return customTasks;
} else if (tasks.length > 0) {
// Normal interspersing when scenarios exist
const interspersedTasks = this.intersperseCustomTasks(tasks, customTasks);
console.log(`🎲 Interspersed with custom tasks: ${interspersedTasks.length} total tasks`);
return interspersedTasks;
}
}
if (tasks.length === 0) {
console.error(`❌ No tasks available for mode ${this.currentMode}`);
}
return tasks;
}
/**
* Create a scenario or interactive task object
*/
createScenarioTask(taskId) {
console.log(`🎬 Creating task for: ${taskId}`);
// First check if this is a regular interactive task from gameData
const regularTask = this.getRegularTaskData(taskId);
if (regularTask) {
console.log(`📋 Found regular interactive task: ${taskId} with type: ${regularTask.interactiveType}`);
return {
id: taskId,
text: regularTask.text,
difficulty: regularTask.difficulty || 'Medium',
type: 'main',
interactiveType: regularTask.interactiveType,
story: regularTask.story,
mirrorInstructions: regularTask.mirrorInstructions,
mirrorTaskText: regularTask.mirrorTaskText,
isScenario: false,
image: this.getRandomScenarioImage()
};
}
// If not a regular task, treat as scenario
const game = window.game;
if (game && game.interactiveTaskManager && game.interactiveTaskManager.taskTypes.has('scenario-adventure')) {
console.log(`✅ Interactive task manager and scenario-adventure type found`);
const scenarioData = this.getScenarioData(taskId);
console.log(`📋 Scenario data for ${taskId}:`, scenarioData ? 'Found' : 'Not found');
if (scenarioData) {
const task = {
id: taskId,
text: scenarioData.text,
difficulty: scenarioData.difficulty,
type: 'main',
interactiveType: 'scenario-adventure',
interactiveData: scenarioData.interactiveData,
isScenario: true,
image: this.getRandomScenarioImage() // Add random image from both folders
};
console.log(`🎯 Created scenario task:`, task);
return task;
}
} else {
console.log(`❌ Interactive task manager not available or scenario-adventure type missing`);
}
return null;
}
/**
* Get random image from both task and consequence folders for scenario modes
*/
getRandomScenarioImage() {
// Get images from both folders
const taskImages = window.gameData?.discoveredTaskImages || [];
const consequenceImages = window.gameData?.discoveredConsequenceImages || [];
const allImages = [...taskImages, ...consequenceImages];
if (allImages.length === 0) {
console.warn('No images found, creating placeholder');
return this.createPlaceholderImage('Scenario Image');
}
// Filter out disabled images
const game = window.game;
const disabledImages = game?.dataManager?.get('disabledImages') || [];
const availableImages = allImages.filter(img => {
const imagePath = typeof img === 'string' ? img : (img.cachedPath || img.originalName);
return !disabledImages.includes(imagePath);
});
if (availableImages.length === 0) {
console.log(`⚠️ All images disabled, creating placeholder`);
return this.createPlaceholderImage('Scenario Image');
}
// Select random image
const randomIndex = Math.floor(Math.random() * availableImages.length);
const selectedImage = availableImages[randomIndex];
// Convert to displayable format
const displayImage = this.getImageSrc(selectedImage);
return displayImage;
}
/**
* Get regular interactive task data from gameData.mainTasks
*/
getRegularTaskData(taskId) {
if (window.gameData && window.gameData.mainTasks) {
console.log(`🔍 All tasks in gameData:`, window.gameData.mainTasks.map(t => t.id));
const task = window.gameData.mainTasks.find(t => t.id === taskId);
console.log(`🔍 Looking for task ${taskId}, found:`, task ? `${task.text} (${task.interactiveType})` : 'not found');
if (task && task.interactiveType) {
return task;
}
}
return null;
}
/**
* Convert image data to displayable format
*/
getImageSrc(imageData) {
// Handle both old base64/path format and new cached metadata format
if (typeof imageData === 'string') {
return imageData; // Old format: base64 or file path
} else {
return imageData.dataUrl || imageData.cachedPath; // New format: use data URL or cached path
}
}
/**
* Create placeholder image for scenarios
*/
createPlaceholderImage(text) {
const canvas = document.createElement('canvas');
canvas.width = 400;
canvas.height = 300;
const ctx = canvas.getContext('2d');
// Create gradient background
const gradient = ctx.createLinearGradient(0, 0, 400, 300);
gradient.addColorStop(0, '#667eea');
gradient.addColorStop(1, '#764ba2');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 400, 300);
// Add text
ctx.fillStyle = 'white';
ctx.font = '24px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(text, 200, 150);
return canvas.toDataURL();
}
/**
* Get scenario data by ID - Now uses modular scenario loader
*/
getScenarioData(scenarioId) {
// Try to get scenario from the new modular system first
if (window.gameDataManager) {
const task = window.gameDataManager.findTaskById(scenarioId);
if (task) {
return {
text: task.text,
difficulty: task.difficulty,
interactiveData: task.interactiveData
};
}
}
// Fallback to legacy system or game.js for backwards compatibility
return this.getScenarioFromGame(scenarioId);
}
/**
* Get scenario data from the current game.js implementation
*/
getScenarioFromGame(scenarioId) {
// This accesses the scenarios currently defined in game.js
if (window.gameData && window.gameData.mainTasks) {
const scenario = window.gameData.mainTasks.find(task => task.id === scenarioId);
if (scenario) {
return {
text: scenario.text,
difficulty: scenario.difficulty,
interactiveData: scenario.interactiveData
};
}
}
return null;
}
/**
* Get custom tasks from localStorage
*/
getCustomTasks() {
// Get custom tasks from the same source as the main game
return window.gameData?.mainTasks || [];
}
/**
* Intersperse custom tasks among scenarios
*/
intersperseCustomTasks(scenarios, customTasks) {
if (!customTasks.length) return scenarios;
const result = [];
const customTasksCopy = [...customTasks];
scenarios.forEach((scenario, index) => {
result.push(scenario);
// Add custom task based on frequency
if (Math.random() < this.customTaskFrequency && customTasksCopy.length > 0) {
const randomIndex = Math.floor(Math.random() * customTasksCopy.length);
const customTask = customTasksCopy.splice(randomIndex, 1)[0];
customTask.isCustomTask = true;
result.push(customTask);
}
});
return result;
}
/**
* Get the current mode info
*/
getCurrentMode() {
return this.availableModes[this.currentMode] || this.availableModes['standard'];
}
/**
* Check if current mode is scenario-based
*/
isScenarioMode() {
return this.currentMode && this.currentMode !== 'standard';
}
/**
* Get mode-specific completion message
*/
getCompletionMessage() {
const modeInfo = this.getCurrentMode();
switch (this.currentMode) {
case 'training-academy':
return `Graduation Day! You've completed your training in the ${modeInfo.name}!`;
case 'punishment-gauntlet':
return `Gauntlet Survived! You've endured all challenges in the ${modeInfo.name}!`;
case 'endurance-trials':
return `Endurance Champion! You've proven your stamina in the ${modeInfo.name}!`;
default:
return "Game Complete! You've finished all available tasks!";
}
}
}
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
window.gameModeManager = new GameModeManager();
window.gameModeManager.init();
});