Fix training academy task completion and prevent unwanted default task cycling
- Fixed completion behavior to return to mode selection instead of cycling through tasks - Added explicit training-academy mode handling to load proper scenario data - Prevented default focus-hold tasks (edge-focus-training, etc.) from being loaded - Added task filtering to block unwanted default tasks - Enhanced gameData protection with getter/setter to prevent task replacement - Improved error handling to return to mode selection on invalid scenarios - Training academy now properly loads scenario adventures with full interactive data - Fixed scenario-training-regimen loading to include proper step data
This commit is contained in:
parent
dbadd4a828
commit
9a8d4b5432
|
|
@ -90,9 +90,12 @@ const humiliationGameData = {
|
||||||
nextStep: "verbal_escalation"
|
nextStep: "verbal_escalation"
|
||||||
},
|
},
|
||||||
position_punishment: {
|
position_punishment: {
|
||||||
type: 'text',
|
type: 'verification-required',
|
||||||
mood: 'authoritative',
|
mood: 'authoritative',
|
||||||
story: "The supervisor points to the floor aggressively. 'Get on your knees immediately. Hands behind your back, head down in shame. This is your punishment position. You will hold this degrading pose while thinking about what a complete failure you are.'",
|
story: "The supervisor points to the floor aggressively. 'Get on your knees immediately. Hands behind your back, head down in shame. This is your punishment position. You will hold this degrading pose while thinking about what a complete failure you are.'",
|
||||||
|
verificationInstructions: "Get on your knees with hands behind your back and head down",
|
||||||
|
verificationDuration: 45,
|
||||||
|
verificationText: "Maintain this humiliating position while the camera captures your shame",
|
||||||
nextStep: "position_escalation"
|
nextStep: "position_escalation"
|
||||||
},
|
},
|
||||||
mirror_punishment: {
|
mirror_punishment: {
|
||||||
|
|
@ -223,19 +226,21 @@ const humiliationGameData = {
|
||||||
nextStep: "punishment_completion"
|
nextStep: "punishment_completion"
|
||||||
},
|
},
|
||||||
extreme_position_punishment: {
|
extreme_position_punishment: {
|
||||||
type: 'action',
|
type: 'verification-required',
|
||||||
mood: 'physical_degradation',
|
mood: 'physical_degradation',
|
||||||
story: "The supervisor forces you into the most degrading positions possible. 'Lower! More shameful! Show how worthless you are through your posture!'",
|
story: "The supervisor forces you into the most degrading positions possible. 'Lower! More shameful! Show how worthless you are through your posture!'",
|
||||||
actionText: "Assume the most degrading and shameful physical positions possible",
|
verificationInstructions: "Assume the most degrading physical position you can imagine",
|
||||||
duration: 240,
|
verificationDuration: 60,
|
||||||
|
verificationText: "Hold your most shameful position while the camera documents your disgrace",
|
||||||
nextStep: "punishment_completion"
|
nextStep: "punishment_completion"
|
||||||
},
|
},
|
||||||
endurance_position_punishment: {
|
endurance_position_punishment: {
|
||||||
type: 'action',
|
type: 'verification-required',
|
||||||
mood: 'endurance_humiliation',
|
mood: 'endurance_humiliation',
|
||||||
story: "The supervisor makes you hold degrading positions for extended time. 'Hold that shameful pose longer! Feel how degrading it is!'",
|
story: "The supervisor makes you hold degrading positions for extended time. 'Hold that shameful pose longer! Feel how degrading it is!'",
|
||||||
actionText: "Hold degrading positions for extended periods as punishment",
|
verificationInstructions: "Get on your knees, hands behind back, head down in complete submission",
|
||||||
duration: 360,
|
verificationDuration: 90,
|
||||||
|
verificationText: "Maintain this humiliating position for the full duration as your punishment",
|
||||||
nextStep: "punishment_completion"
|
nextStep: "punishment_completion"
|
||||||
},
|
},
|
||||||
mirror_position_punishment: {
|
mirror_position_punishment: {
|
||||||
|
|
|
||||||
|
|
@ -1133,6 +1133,346 @@ class WebcamManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start webcam verification mode for position verification
|
||||||
|
*/
|
||||||
|
async startVerificationMode(verificationData) {
|
||||||
|
console.log('🔍 Starting webcam verification mode');
|
||||||
|
|
||||||
|
// Request camera if not already active
|
||||||
|
if (!this.isActive) {
|
||||||
|
const accessGranted = await this.requestCameraAccess();
|
||||||
|
if (!accessGranted) {
|
||||||
|
console.warn('📷 Camera access required for verification mode');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track verification start
|
||||||
|
if (this.game && this.game.trackWebcamVerification) {
|
||||||
|
this.game.trackWebcamVerification(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show verification interface
|
||||||
|
this.showVerificationInterface(verificationData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display verification interface - webcam feed with position verification
|
||||||
|
*/
|
||||||
|
showVerificationInterface(verificationData) {
|
||||||
|
// Create verification overlay
|
||||||
|
const overlay = document.createElement('div');
|
||||||
|
overlay.id = 'verification-overlay';
|
||||||
|
overlay.innerHTML = `
|
||||||
|
<div class="verification-container">
|
||||||
|
<div class="verification-header">
|
||||||
|
<h3>🔍 Position Verification Required</h3>
|
||||||
|
<p>${verificationData?.instructions || 'Follow the position instructions and maintain pose'}</p>
|
||||||
|
</div>
|
||||||
|
<div class="verification-video-container">
|
||||||
|
<video id="verification-video" autoplay muted playsinline></video>
|
||||||
|
<div class="verification-overlay-text">
|
||||||
|
<div class="position-instructions">
|
||||||
|
${verificationData?.verificationInstructions || 'Assume required position'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="verification-timer" id="verification-timer" style="display: none;">
|
||||||
|
<div class="verification-progress" id="verification-progress">
|
||||||
|
<div class="progress-bar" id="verification-progress-bar"></div>
|
||||||
|
</div>
|
||||||
|
<div class="timer-text">Verification time: <span id="verification-time">${verificationData?.verificationDuration || 30}</span>s</div>
|
||||||
|
<div class="verification-status" id="verification-status">Get in position...</div>
|
||||||
|
</div>
|
||||||
|
<div class="verification-controls">
|
||||||
|
<button id="verification-start-btn" class="btn btn-primary">
|
||||||
|
🔍 Start Verification
|
||||||
|
</button>
|
||||||
|
<button id="verification-close-btn" class="btn btn-secondary">
|
||||||
|
❌ Abandon Task
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
${verificationData?.verificationText ? `<div class="verification-task-text">${verificationData.verificationText}</div>` : ''}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Style the verification overlay
|
||||||
|
overlay.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.95);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 99999;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const containerStyle = `
|
||||||
|
background: linear-gradient(135deg, #2c3e50, #34495e);
|
||||||
|
border: 2px solid #e74c3c;
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 30px;
|
||||||
|
max-width: 700px;
|
||||||
|
width: 95%;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.7);
|
||||||
|
color: #ecf0f1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const videoStyle = `
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 15px 0;
|
||||||
|
transform: scaleX(-1);
|
||||||
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
|
||||||
|
border: 2px solid #e74c3c;
|
||||||
|
position: relative;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const buttonStyle = `
|
||||||
|
margin: 10px;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
background: linear-gradient(135deg, #e74c3c, #c0392b);
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
min-width: 140px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Apply styles
|
||||||
|
overlay.querySelector('.verification-container').style.cssText = containerStyle;
|
||||||
|
overlay.querySelector('#verification-video').style.cssText = videoStyle;
|
||||||
|
overlay.querySelectorAll('button').forEach(btn => {
|
||||||
|
btn.style.cssText = buttonStyle;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Style specific elements
|
||||||
|
const startBtn = overlay.querySelector('#verification-start-btn');
|
||||||
|
const closeBtn = overlay.querySelector('#verification-close-btn');
|
||||||
|
|
||||||
|
if (closeBtn) {
|
||||||
|
closeBtn.style.background = 'linear-gradient(135deg, #95a5a6, #7f8c8d)';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
|
||||||
|
// Connect video stream to verification video element
|
||||||
|
const verificationVideo = overlay.querySelector('#verification-video');
|
||||||
|
if (this.stream && verificationVideo) {
|
||||||
|
verificationVideo.srcObject = this.stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listeners
|
||||||
|
startBtn.addEventListener('click', () => {
|
||||||
|
console.log('🔍 Starting verification process');
|
||||||
|
this.startVerificationTimer(verificationData, overlay);
|
||||||
|
});
|
||||||
|
|
||||||
|
closeBtn.addEventListener('click', () => {
|
||||||
|
console.log('❌ Verification abandoned - triggering game over');
|
||||||
|
this.closeVerificationMode();
|
||||||
|
this.showCondescendingGameOver();
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('🔍 Verification interface displayed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start verification timer with countdown and auto-capture
|
||||||
|
*/
|
||||||
|
startVerificationTimer(verificationData, overlay) {
|
||||||
|
const duration = verificationData?.verificationDuration || 30;
|
||||||
|
const timerDisplay = overlay.querySelector('#verification-time');
|
||||||
|
const progressBar = overlay.querySelector('#verification-progress-bar');
|
||||||
|
const timerElement = overlay.querySelector('#verification-timer');
|
||||||
|
const statusElement = overlay.querySelector('#verification-status');
|
||||||
|
const startBtn = overlay.querySelector('#verification-start-btn');
|
||||||
|
|
||||||
|
// Hide start button and show timer
|
||||||
|
if (startBtn) startBtn.style.display = 'none';
|
||||||
|
if (timerElement) timerElement.style.display = 'block';
|
||||||
|
|
||||||
|
// Preparation phase (10 seconds)
|
||||||
|
let prepTime = 10;
|
||||||
|
if (statusElement) statusElement.textContent = `Get in position now! ${prepTime}s`;
|
||||||
|
|
||||||
|
const prepTimer = setInterval(() => {
|
||||||
|
prepTime--;
|
||||||
|
if (statusElement) statusElement.textContent = `Get in position now! ${prepTime}s`;
|
||||||
|
|
||||||
|
if (prepTime <= 0) {
|
||||||
|
clearInterval(prepTimer);
|
||||||
|
this.startMainVerification(duration, overlay);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start main verification phase with position holding
|
||||||
|
*/
|
||||||
|
startMainVerification(duration, overlay) {
|
||||||
|
const timerDisplay = overlay.querySelector('#verification-time');
|
||||||
|
const progressBar = overlay.querySelector('#verification-progress-bar');
|
||||||
|
const statusElement = overlay.querySelector('#verification-status');
|
||||||
|
|
||||||
|
let timeLeft = duration;
|
||||||
|
if (statusElement) {
|
||||||
|
statusElement.textContent = 'HOLD POSITION - Being verified...';
|
||||||
|
statusElement.style.color = '#e74c3c';
|
||||||
|
statusElement.style.fontWeight = 'bold';
|
||||||
|
}
|
||||||
|
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
timeLeft--;
|
||||||
|
|
||||||
|
// Update timer display
|
||||||
|
if (timerDisplay) {
|
||||||
|
timerDisplay.textContent = timeLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update progress bar
|
||||||
|
if (progressBar) {
|
||||||
|
const progress = ((duration - timeLeft) / duration) * 100;
|
||||||
|
progressBar.style.width = progress + '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update status
|
||||||
|
if (statusElement && timeLeft > 0) {
|
||||||
|
statusElement.textContent = `HOLD POSITION - ${timeLeft}s remaining`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verification complete
|
||||||
|
if (timeLeft <= 0) {
|
||||||
|
clearInterval(timer);
|
||||||
|
this.completeVerification(overlay);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
// Store timer reference for cleanup
|
||||||
|
this.verificationTimer = timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete verification process with photo capture
|
||||||
|
*/
|
||||||
|
completeVerification(overlay) {
|
||||||
|
const statusElement = overlay.querySelector('#verification-status');
|
||||||
|
|
||||||
|
if (statusElement) {
|
||||||
|
statusElement.textContent = 'Capturing verification photo...';
|
||||||
|
statusElement.style.color = '#27ae60';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-capture verification photo
|
||||||
|
setTimeout(() => {
|
||||||
|
this.captureVerificationPhoto(overlay);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capture verification photo and complete process
|
||||||
|
*/
|
||||||
|
captureVerificationPhoto(overlay) {
|
||||||
|
const video = overlay.querySelector('#verification-video');
|
||||||
|
const statusElement = overlay.querySelector('#verification-status');
|
||||||
|
|
||||||
|
if (video && video.videoWidth > 0) {
|
||||||
|
// Create canvas and capture frame
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = video.videoWidth;
|
||||||
|
canvas.height = video.videoHeight;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(video, 0, 0);
|
||||||
|
|
||||||
|
// Convert to base64
|
||||||
|
const photoData = canvas.toDataURL('image/jpeg', 0.8);
|
||||||
|
|
||||||
|
// Store verification photo
|
||||||
|
const verificationPhoto = {
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
data: photoData,
|
||||||
|
type: 'position_verification'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Save to localStorage
|
||||||
|
const existingPhotos = JSON.parse(localStorage.getItem('verificationPhotos') || '[]');
|
||||||
|
existingPhotos.push(verificationPhoto);
|
||||||
|
localStorage.setItem('verificationPhotos', JSON.stringify(existingPhotos));
|
||||||
|
|
||||||
|
console.log('📸 Verification photo captured and stored');
|
||||||
|
|
||||||
|
if (statusElement) {
|
||||||
|
statusElement.textContent = 'Verification COMPLETE - Position documented';
|
||||||
|
statusElement.style.color = '#27ae60';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete verification after 2 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
this.finalizeVerification(overlay);
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
console.error('❌ Failed to capture verification photo');
|
||||||
|
if (statusElement) {
|
||||||
|
statusElement.textContent = 'Verification failed - try again';
|
||||||
|
statusElement.style.color = '#e74c3c';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize verification and proceed
|
||||||
|
*/
|
||||||
|
finalizeVerification(overlay) {
|
||||||
|
console.log('✅ Position verification completed successfully');
|
||||||
|
|
||||||
|
this.closeVerificationMode();
|
||||||
|
|
||||||
|
// Notify completion
|
||||||
|
const event = new CustomEvent('verificationComplete', {
|
||||||
|
detail: { success: true }
|
||||||
|
});
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close verification mode
|
||||||
|
*/
|
||||||
|
closeVerificationMode() {
|
||||||
|
console.log('🔚 Closing verification mode');
|
||||||
|
|
||||||
|
// Clear timer if running
|
||||||
|
if (this.verificationTimer) {
|
||||||
|
clearInterval(this.verificationTimer);
|
||||||
|
this.verificationTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track verification end
|
||||||
|
if (this.game && this.game.trackWebcamVerification) {
|
||||||
|
this.game.trackWebcamVerification(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove verification overlay
|
||||||
|
const overlay = document.getElementById('verification-overlay');
|
||||||
|
if (overlay) {
|
||||||
|
overlay.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop camera stream
|
||||||
|
this.stopCamera();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display mirror interface - webcam feed without photo capture
|
* Display mirror interface - webcam feed without photo capture
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1244,6 +1244,19 @@
|
||||||
isScenario: true
|
isScenario: true
|
||||||
}));
|
}));
|
||||||
console.log(`📋 Loaded ${trainingTasks.length} punishment scenarios directly from humiliation data`);
|
console.log(`📋 Loaded ${trainingTasks.length} punishment scenarios directly from humiliation data`);
|
||||||
|
} else if (selectedTrainingMode === 'training-academy' && window.trainingGameData && window.trainingGameData.scenarios) {
|
||||||
|
console.log('🎓 Training Academy mode detected - loading training scenarios directly');
|
||||||
|
trainingTasks = window.trainingGameData.scenarios.map(scenario => ({
|
||||||
|
id: scenario.id,
|
||||||
|
text: scenario.text,
|
||||||
|
difficulty: scenario.difficulty,
|
||||||
|
type: 'main',
|
||||||
|
interactiveType: scenario.interactiveType,
|
||||||
|
interactiveData: scenario.interactiveData,
|
||||||
|
isScenario: true
|
||||||
|
}));
|
||||||
|
console.log(`📋 Loaded ${trainingTasks.length} training scenarios directly from training data`);
|
||||||
|
console.log('🔍 First scenario interactive data:', trainingTasks[0]?.interactiveData ? 'Present' : 'Missing');
|
||||||
} else if (selectedTrainingMode === 'photography-studio' && window.dressUpGameData && window.dressUpGameData.scenarios) {
|
} else if (selectedTrainingMode === 'photography-studio' && window.dressUpGameData && window.dressUpGameData.scenarios) {
|
||||||
console.log('📸 Photography Studio mode detected - loading dress-up scenarios directly');
|
console.log('📸 Photography Studio mode detected - loading dress-up scenarios directly');
|
||||||
trainingTasks = window.dressUpGameData.scenarios.map(scenario => ({
|
trainingTasks = window.dressUpGameData.scenarios.map(scenario => ({
|
||||||
|
|
@ -1283,10 +1296,12 @@
|
||||||
} else if (selectedTrainingMode === 'endurance-trials' && window.enduranceGameData && window.enduranceGameData.scenarios) {
|
} else if (selectedTrainingMode === 'endurance-trials' && window.enduranceGameData && window.enduranceGameData.scenarios) {
|
||||||
fallbackData = window.enduranceGameData.scenarios;
|
fallbackData = window.enduranceGameData.scenarios;
|
||||||
console.log(`📋 Using endurance data fallback for endurance-trials mode`);
|
console.log(`📋 Using endurance data fallback for endurance-trials mode`);
|
||||||
} else if (window.trainingGameData && window.trainingGameData.scenarios) {
|
} else if (selectedTrainingMode === 'training-academy' && window.trainingGameData && window.trainingGameData.scenarios) {
|
||||||
|
// Only use training data scenarios if they exist and the mode is specifically training-academy
|
||||||
fallbackData = window.trainingGameData.scenarios;
|
fallbackData = window.trainingGameData.scenarios;
|
||||||
console.log(`📋 Using training data fallback for ${selectedTrainingMode} mode`);
|
console.log(`📋 Using training data fallback for training-academy mode`);
|
||||||
}
|
}
|
||||||
|
// Removed the generic fallback to prevent using wrong task types
|
||||||
|
|
||||||
if (fallbackData) {
|
if (fallbackData) {
|
||||||
trainingTasks = fallbackData.map(scenario => ({
|
trainingTasks = fallbackData.map(scenario => ({
|
||||||
|
|
@ -1304,18 +1319,34 @@
|
||||||
|
|
||||||
// Check if we have any tasks to work with
|
// Check if we have any tasks to work with
|
||||||
if (trainingTasks.length === 0) {
|
if (trainingTasks.length === 0) {
|
||||||
console.error('❌ No training tasks available');
|
console.error('❌ No training tasks available for mode:', selectedTrainingMode);
|
||||||
alert('Error: No training scenarios found. Please check your game data.');
|
alert(`Error: No training scenarios found for ${selectedTrainingMode} mode. This training mode may not have content available yet.`);
|
||||||
|
|
||||||
|
// Return to mode selection instead of failing
|
||||||
|
returnToModeSelection();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out any invalid tasks and ensure proper structure
|
// Filter out any invalid tasks and ensure proper structure
|
||||||
const validTrainingTasks = trainingTasks.filter(task => {
|
const validTrainingTasks = trainingTasks.filter(task => {
|
||||||
const isValid = task && task.id && task.text && task.interactiveType;
|
const isValid = task && task.id && task.text && task.interactiveType;
|
||||||
|
|
||||||
|
// Also exclude the default focus-hold training tasks that shouldn't be in scenarios
|
||||||
|
const isUnwantedDefaultTask = task.id === 'edge-focus-training' ||
|
||||||
|
task.id === 'stroking-endurance-training' ||
|
||||||
|
task.id === 'extended-edging-session';
|
||||||
|
|
||||||
|
if (isUnwantedDefaultTask) {
|
||||||
|
console.warn('⚠️ Filtering out unwanted default task:', task.id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
console.warn('⚠️ Filtering out invalid task:', task);
|
console.warn('⚠️ Filtering out invalid task:', task);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return isValid;
|
|
||||||
|
return true;
|
||||||
}).map(task => {
|
}).map(task => {
|
||||||
// Ensure each task has all required properties for the game engine
|
// Ensure each task has all required properties for the game engine
|
||||||
return {
|
return {
|
||||||
|
|
@ -1408,6 +1439,31 @@
|
||||||
// Set training tasks as the active tasks
|
// Set training tasks as the active tasks
|
||||||
window.gameData.mainTasks = trainingTasks;
|
window.gameData.mainTasks = trainingTasks;
|
||||||
console.log('📋 Set training tasks as active game data');
|
console.log('📋 Set training tasks as active game data');
|
||||||
|
|
||||||
|
// Create a robust getter/setter to prevent unwanted task replacement
|
||||||
|
const tasksList = [...trainingTasks];
|
||||||
|
Object.defineProperty(window.gameData, 'mainTasks', {
|
||||||
|
get: function() {
|
||||||
|
return this._trainingTasks || tasksList;
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
// Filter out unwanted default tasks if they somehow get added
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
const filteredTasks = value.filter(task =>
|
||||||
|
task.id !== 'edge-focus-training' &&
|
||||||
|
task.id !== 'stroking-endurance-training' &&
|
||||||
|
task.id !== 'extended-edging-session'
|
||||||
|
);
|
||||||
|
this._trainingTasks = filteredTasks.length > 0 ? filteredTasks : tasksList;
|
||||||
|
console.log('🛡️ Training Academy: Filtered tasks, keeping', this._trainingTasks.length, 'valid tasks');
|
||||||
|
} else {
|
||||||
|
this._trainingTasks = tasksList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize with training tasks
|
||||||
|
window.gameData.mainTasks = trainingTasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.5. Override interactive task display to prevent UI errors
|
// 3.5. Override interactive task display to prevent UI errors
|
||||||
|
|
@ -1800,22 +1856,63 @@
|
||||||
const existing = document.getElementById('training-task-display');
|
const existing = document.getElementById('training-task-display');
|
||||||
if (existing) existing.remove();
|
if (existing) existing.remove();
|
||||||
|
|
||||||
// Show completion message
|
// Clear the game container
|
||||||
const completionContainer = document.querySelector('.game-content') || document.body;
|
const gameContainer = document.getElementById('game-container');
|
||||||
const completionDiv = document.createElement('div');
|
if (gameContainer) gameContainer.innerHTML = '';
|
||||||
completionDiv.id = 'training-completion';
|
|
||||||
completionDiv.style.cssText = 'position: fixed; top: 30%; left: 50%; transform: translateX(-50%); z-index: 9999; width: 80%; max-width: 600px;';
|
// Return to mode selection by resetting the interface
|
||||||
completionDiv.innerHTML = `
|
returnToModeSelection();
|
||||||
<div class="training-task">
|
}
|
||||||
<h3>🎉 Training Complete!</h3>
|
|
||||||
<p>Congratulations! You have completed your training session.</p>
|
function returnToModeSelection() {
|
||||||
<div class="training-controls">
|
console.log('🔄 Returning to training mode selection...');
|
||||||
<button onclick="location.reload()" class="complete-btn">Start New Session</button>
|
|
||||||
<button onclick="selectMode('training-academy')" class="next-btn">Select Different Mode</button>
|
// Clear any active training state
|
||||||
</div>
|
selectedTrainingMode = null;
|
||||||
</div>
|
currentScenarioTask = null;
|
||||||
`;
|
currentScenarioStep = 'start';
|
||||||
completionContainer.appendChild(completionDiv);
|
|
||||||
|
// Clear any game overrides and restore original state
|
||||||
|
if (window.game) {
|
||||||
|
// Stop the game session
|
||||||
|
window.game.gameState.isRunning = false;
|
||||||
|
window.game.gameState.isPaused = false;
|
||||||
|
|
||||||
|
// Clear current task
|
||||||
|
window.game.gameState.currentTask = null;
|
||||||
|
window.game.currentTask = null;
|
||||||
|
|
||||||
|
// Reset any overridden methods if needed
|
||||||
|
if (window.gameData && window.gameData.originalMainTasks) {
|
||||||
|
window.gameData.mainTasks = window.gameData.originalMainTasks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show setup interface again
|
||||||
|
document.querySelector('.academy-header').style.display = 'block';
|
||||||
|
document.querySelector('.library-status').style.display = 'block';
|
||||||
|
document.querySelector('.training-controls').style.display = 'block';
|
||||||
|
document.querySelector('.academy-start-controls').style.display = 'block';
|
||||||
|
|
||||||
|
// Hide game interface
|
||||||
|
const gameInterface = document.getElementById('gameInterface');
|
||||||
|
gameInterface.style.display = 'none';
|
||||||
|
|
||||||
|
// Reset training mode cards
|
||||||
|
document.querySelectorAll('.training-mode-card').forEach(card => {
|
||||||
|
card.classList.remove('selected');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Disable start button until new mode is selected
|
||||||
|
document.getElementById('startTrainingBtn').disabled = true;
|
||||||
|
|
||||||
|
// Restore video controls visibility
|
||||||
|
const videoControls = document.getElementById('videoControlsOverlay');
|
||||||
|
if (videoControls) {
|
||||||
|
videoControls.style.opacity = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ Returned to training mode selection screen');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scenario Adventure Display System
|
// Scenario Adventure Display System
|
||||||
|
|
@ -1984,6 +2081,28 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
} else if (step.type === 'verification-required') {
|
||||||
|
stepHtml = `
|
||||||
|
<div class="training-task scenario-verification">
|
||||||
|
<h3>🔍 ${scenario.title} - Verification Required</h3>
|
||||||
|
<div class="scenario-story">
|
||||||
|
${step.story}
|
||||||
|
</div>
|
||||||
|
<div class="verification-requirements">
|
||||||
|
<h4>📋 Position Requirements:</h4>
|
||||||
|
<p class="verification-instructions">${step.verificationInstructions}</p>
|
||||||
|
<p class="verification-text">${step.verificationText}</p>
|
||||||
|
<p class="verification-duration"><strong>Duration:</strong> ${step.verificationDuration} seconds</p>
|
||||||
|
</div>
|
||||||
|
<div class="verification-warning">
|
||||||
|
<p>⚠️ <strong>Warning:</strong> You must maintain the required position for the full duration. The webcam will verify your compliance.</p>
|
||||||
|
</div>
|
||||||
|
<div class="training-controls">
|
||||||
|
<button onclick="startPositionVerification('${step.nextStep}', ${step.verificationDuration}, '${step.verificationInstructions}', '${step.verificationText}')" class="action-btn">🔍 Start Position Verification</button>
|
||||||
|
<button onclick="selectScenarioChoice('${step.nextStep}')" class="skip-btn">Skip (Failure)</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
} else if (step.type === 'ending') {
|
} else if (step.type === 'ending') {
|
||||||
stepHtml = `
|
stepHtml = `
|
||||||
<div class="training-task scenario-ending">
|
<div class="training-task scenario-ending">
|
||||||
|
|
@ -2085,6 +2204,54 @@
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startPositionVerification(nextStep, duration, instructions, verificationText) {
|
||||||
|
console.log('🔍 Starting position verification for', duration, 'seconds');
|
||||||
|
|
||||||
|
// Store next step for completion callback
|
||||||
|
window.trainingAcademyNextStep = nextStep;
|
||||||
|
|
||||||
|
// Create verification data for the webcam system
|
||||||
|
const verificationData = {
|
||||||
|
instructions: "Position verification required for training compliance",
|
||||||
|
verificationInstructions: instructions,
|
||||||
|
verificationText: verificationText,
|
||||||
|
verificationDuration: duration,
|
||||||
|
onComplete: function() {
|
||||||
|
console.log('🔍 Position verification completed, proceeding to:', window.trainingAcademyNextStep);
|
||||||
|
proceedToNextStep(window.trainingAcademyNextStep);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use the webcam manager to start verification mode
|
||||||
|
if (window.game && window.game.webcamManager) {
|
||||||
|
console.log('🎥 Starting webcam verification mode...');
|
||||||
|
window.game.webcamManager.startVerificationMode(verificationData).then((success) => {
|
||||||
|
if (success) {
|
||||||
|
console.log('🔍 Verification mode started successfully');
|
||||||
|
|
||||||
|
// Listen for verification completion
|
||||||
|
document.addEventListener('verificationComplete', function(event) {
|
||||||
|
if (event.detail.success) {
|
||||||
|
console.log('✅ Verification completed successfully');
|
||||||
|
proceedToNextStep(nextStep);
|
||||||
|
}
|
||||||
|
}, { once: true });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ Verification mode failed to start');
|
||||||
|
// Show failure and allow skip or retry
|
||||||
|
alert('Camera access required for position verification. Please enable camera access.');
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('❌ Verification mode failed:', error);
|
||||||
|
alert('Failed to start position verification. Check camera access.');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ Webcam manager not available');
|
||||||
|
alert('Webcam verification system not available. Cannot proceed with position verification.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function startScenarioAction(nextStep, duration) {
|
function startScenarioAction(nextStep, duration) {
|
||||||
console.log('🎬 Starting scenario action for', duration, 'seconds');
|
console.log('🎬 Starting scenario action for', duration, 'seconds');
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue