/** * Game Mode Manager * Handles different game modes including scenario-based modes */ class GameModeManager { constructor() { this.currentMode = 'standard'; // Default to standard mode this.availableModes = { 'standard': { name: 'Standard Game', description: 'Classic endless task mode with regular tasks only', icon: '🎮' }, 'timed': { name: 'Timed Challenge', description: 'Race against the clock to complete as many tasks as possible', icon: '⏰' }, 'scored': { name: 'Score Target', description: 'Reach a target score by completing tasks based on difficulty', icon: '🎯' }, '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' ] }; 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 new modes'); gameModeSelection.innerHTML = `

Choose Your Game Mode

${Object.entries(this.availableModes).map(([key, mode]) => `
${mode.icon}

${mode.name}

${mode.description}

`).join('')}
`; // 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.error('❌ Could not find .game-mode-selection element'); } } /** * 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 if (mode !== 'standard' && mode !== 'timed' && mode !== 'scored') { const scenarioConfig = document.getElementById('scenario-config'); if (scenarioConfig) { scenarioConfig.style.display = 'block'; } } // For timed and scored modes, show the original configuration UI if (mode === 'timed') { const timedConfig = document.getElementById('timed-config'); if (timedConfig) { timedConfig.style.display = 'block'; console.log('⏱️ Showing timed challenge configuration'); } } else if (mode === 'scored') { const scoreTargetConfig = document.getElementById('score-target-config'); if (scoreTargetConfig) { scoreTargetConfig.style.display = 'block'; console.log('🏆 Showing score target 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() { switch(this.currentMode) { case 'standard': return 'complete-all'; case 'timed': return 'timed'; case 'scored': return 'score-target'; default: return 'complete-all'; // Scenario modes use complete-all as base } } /** * 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(); });