diff --git a/js/core/game.js b/js/core/game.js index 3635623..d26ac12 100644 --- a/js/core/game.js +++ b/js/core/game.js @@ -394,7 +394,10 @@ export function preload() { // Get scenario from URL parameter or use default const urlParams = new URLSearchParams(window.location.search); - const scenarioFile = urlParams.get('scenario') || 'scenarios/ceo_exfil.json'; + let scenarioFile = urlParams.get('scenario') || 'scenarios/ceo_exfil.json'; + + // Add cache buster query parameter to prevent browser caching + scenarioFile = `${scenarioFile}${scenarioFile.includes('?') ? '&' : '?'}v=${Date.now()}`; // Load the specified scenario this.load.json('gameScenarioJSON', scenarioFile); @@ -414,6 +417,12 @@ export function create() { window.gameScenario = this.cache.json.get('gameScenarioJSON'); } gameScenario = window.gameScenario; + + // Debug: log what we loaded + console.log('🎮 Loaded gameScenario with rooms:', Object.keys(gameScenario?.rooms || {})); + if (gameScenario?.rooms?.office1) { + console.log('office1 room data:', gameScenario.rooms.office1); + } // Calculate world bounds after scenario is loaded const worldBounds = calculateWorldBounds(this); diff --git a/js/core/rooms.js b/js/core/rooms.js index f591859..9a31006 100644 --- a/js/core/rooms.js +++ b/js/core/rooms.js @@ -319,8 +319,16 @@ function applyScenarioProperties(sprite, scenarioObj, roomId, index) { takeable: scenarioObj.takeable, readable: scenarioObj.readable, text: scenarioObj.text, - observations: scenarioObj.observations + observations: scenarioObj.observations, + keyPins: scenarioObj.keyPins, // Include keyPins in log + locked: scenarioObj.locked, + lockType: scenarioObj.lockType }); + + // Verify keyPins are stored on the sprite + if (scenarioObj.keyPins) { + console.log(`✓ keyPins stored on ${roomId}_${scenarioObj.type}: [${sprite.keyPins.join(', ')}]`); + } } /** diff --git a/js/minigames/lockpick/lockpick-set-minigame.js b/js/minigames/lockpick/lockpick-set-minigame.js index 33ec8a5..a6f2cdb 100644 --- a/js/minigames/lockpick/lockpick-set-minigame.js +++ b/js/minigames/lockpick/lockpick-set-minigame.js @@ -259,6 +259,9 @@ export class LockpickSetMinigame extends MinigameScene { // Get difficulty from object data const difficulty = obj.scenarioData?.difficulty || obj.scenarioData?.lockDifficulty || 'medium'; + // Get keyPins from scenario data + const keyPins = obj.scenarioData?.keyPins || null; + // Use the existing lockpicking system window.startLockpickingMinigame(obj, window.game, difficulty, (success) => { if (success) { @@ -267,7 +270,7 @@ export class LockpickSetMinigame extends MinigameScene { } else { console.log('Lockpicking failed'); } - }); + }, keyPins); // Pass keyPins to minigame starter } else { console.error('Lockpicking minigame not available'); if (window.gameAlert) { diff --git a/js/minigames/lockpicking/lock-configuration.js b/js/minigames/lockpicking/lock-configuration.js index 0b5a7aa..b4e2a78 100644 --- a/js/minigames/lockpicking/lock-configuration.js +++ b/js/minigames/lockpicking/lock-configuration.js @@ -19,39 +19,14 @@ export class LockConfiguration { } saveLockConfiguration() { - // Save the current lock configuration to global storage and localStorage - if (this.parent.pins && this.parent.pins.length > 0) { - const pinHeights = this.parent.pins.map(pin => pin.originalHeight); - const config = { - pinHeights: pinHeights, - pinCount: this.parent.pinCount, - timestamp: Date.now() - }; - - // Save to memory - window.lockConfigurations[this.parent.lockId] = config; - - // Save to localStorage for persistence - try { - const savedConfigs = localStorage.getItem('lockConfigurations') || '{}'; - const parsed = JSON.parse(savedConfigs); - parsed[this.parent.lockId] = config; - localStorage.setItem('lockConfigurations', JSON.stringify(parsed)); - } catch (error) { - console.warn('Failed to save lock configuration to localStorage:', error); - } - - console.log(`Saved lock configuration for ${this.parent.lockId}:`, pinHeights); - } + // DISABLED: Persistence removed - all locks use keyPins from scenario + // Pin configurations are now determined solely by the scenario's keyPins property + console.log(`Lock configuration for ${this.parent.lockId} uses scenario keyPins - no persistence`); } loadLockConfiguration() { - // Load lock configuration from global storage - const config = window.lockConfigurations[this.parent.lockId]; - if (config && config.pinHeights && config.pinHeights.length === this.parent.pinCount) { - console.log(`Loaded lock configuration for ${this.parent.lockId}:`, config.pinHeights); - return config.pinHeights; - } + // DISABLED: Persistence removed - return null to force use of predefined pins + // Pin configurations should come from scenario's keyPins passed in params return null; } diff --git a/js/minigames/lockpicking/lockpicking-game-phaser.js b/js/minigames/lockpicking/lockpicking-game-phaser.js index e9d82fb..1c720dc 100644 --- a/js/minigames/lockpicking/lockpicking-game-phaser.js +++ b/js/minigames/lockpicking/lockpicking-game-phaser.js @@ -23,14 +23,62 @@ export class LockpickingMinigamePhaser extends MinigameScene { // Ensure params is an object params = params || {}; - console.log('DEBUG: Lockpicking minigame constructor received params:', params); - console.log('DEBUG: predefinedPinHeights from params:', params.predefinedPinHeights); + console.log('🎮 Lockpicking minigame constructor received params:', { + predefinedPinHeights: params.predefinedPinHeights, + difficulty: params.difficulty, + pinCount: params.pinCount, + lockableType: params.lockable?.doorProperties ? 'door' : params.lockable?.scenarioData ? 'item' : 'unknown' + }); this.lockable = params.lockable || 'default-lock'; this.lockId = params.lockId || 'default_lock'; this.difficulty = params.difficulty || 'medium'; - // Use passed pinCount if provided, otherwise calculate based on difficulty - this.pinCount = params.pinCount || (this.difficulty === 'easy' ? 3 : this.difficulty === 'medium' ? 4 : 5); + + // Determine pin count: prioritize based on keyPins array length from scenario + let pinCount = params.pinCount; + let predefinedPinHeights = params.predefinedPinHeights; + + console.log('🔍 pinCount determination started:', { + explicitPinCount: pinCount, + predefinedPinHeights: predefinedPinHeights, + difficulty: this.difficulty + }); + + // If predefinedPinHeights not in params, try to extract from lockable object + if (!predefinedPinHeights && this.lockable) { + console.log('🔍 Attempting to extract predefinedPinHeights from lockable object'); + if (this.lockable.doorProperties?.keyPins) { + predefinedPinHeights = this.lockable.doorProperties.keyPins; + console.log(`✓ Extracted predefinedPinHeights from lockable.doorProperties:`, predefinedPinHeights); + } else if (this.lockable.scenarioData?.keyPins) { + predefinedPinHeights = this.lockable.scenarioData.keyPins; + console.log(`✓ Extracted predefinedPinHeights from lockable.scenarioData:`, predefinedPinHeights); + } else if (this.lockable.keyPins) { + predefinedPinHeights = this.lockable.keyPins; + console.log(`✓ Extracted predefinedPinHeights from lockable.keyPins:`, predefinedPinHeights); + } else { + console.warn('⚠ Could not extract predefinedPinHeights from lockable object'); + } + } + + // Store for use in pin management + this.params = params; + this.params.predefinedPinHeights = predefinedPinHeights; + + // If pinCount not explicitly provided, derive from predefinedPinHeights (keyPins from scenario) + if (!pinCount && predefinedPinHeights && Array.isArray(predefinedPinHeights)) { + pinCount = predefinedPinHeights.length; + console.log(`✓ Determined pinCount ${pinCount} from predefinedPinHeights array length: [${predefinedPinHeights.join(', ')}]`); + } + + // Fall back to difficulty-based pin count if still not set + if (!pinCount) { + pinCount = this.difficulty === 'easy' ? 3 : this.difficulty === 'medium' ? 4 : 5; + console.log(`⚠ Using difficulty-based pinCount: ${pinCount} (difficulty: ${this.difficulty})`); + } + + + this.pinCount = pinCount; // Initialize global lock storage if it doesn't exist if (!window.lockConfigurations) { diff --git a/js/minigames/lockpicking/pin-management.js b/js/minigames/lockpicking/pin-management.js index 4ac0592..6294bf4 100644 --- a/js/minigames/lockpicking/pin-management.js +++ b/js/minigames/lockpicking/pin-management.js @@ -29,34 +29,27 @@ export class PinManagement { const pinSpacing = 400 / (this.parent.pinCount + 1); const margin = pinSpacing * 0.75; // 25% smaller margins - // Try to load saved pin heights for this lock - const savedPinHeights = this.parent.lockConfig.loadLockConfiguration(); - - // Check if predefined pin heights were passed + // REMOVED: Persistence check - load only from predefined pins in params + // keyPins should be passed from scenario as predefinedPinHeights parameter const predefinedPinHeights = this.parent.params?.predefinedPinHeights; - console.log(`DEBUG: Lockpicking minigame received parameters:`); + console.log(`🔧 PIN MANAGEMENT createPins():`); console.log(` - pinCount: ${this.parent.pinCount}`); - console.log(` - this.parent.params:`, this.parent.params); - console.log(` - predefinedPinHeights: [${predefinedPinHeights ? predefinedPinHeights.join(', ') : 'none'}]`); - console.log(` - savedPinHeights: [${savedPinHeights ? savedPinHeights.join(', ') : 'none'}]`); + console.log(` - lockId: ${this.parent.lockId}`); + console.log(` - params.predefinedPinHeights: ${predefinedPinHeights ? '[' + predefinedPinHeights.join(', ') + ']' : 'none'}`); + console.log(` - using predefined: ${predefinedPinHeights ? 'YES' : 'NO - will generate random'}`); for (let i = 0; i < this.parent.pinCount; i++) { const pinX = 100 + margin + i * pinSpacing; const pinY = 200; - // Use predefined pin heights if available, otherwise use saved or generate random ones + // Use predefined pin heights if available, otherwise generate random ones let keyPinLength, driverPinLength; if (predefinedPinHeights && predefinedPinHeights[i] !== undefined) { - // Use predefined configuration + // Use predefined configuration from scenario keyPins keyPinLength = predefinedPinHeights[i]; driverPinLength = 75 - keyPinLength; // Total height is 75 - console.log(`✓ Pin ${i}: Using predefined pin height: ${keyPinLength} (driver: ${driverPinLength})`); - } else if (savedPinHeights && savedPinHeights[i] !== undefined) { - // Use saved configuration - keyPinLength = savedPinHeights[i]; - driverPinLength = 75 - keyPinLength; // Total height is 75 - console.log(`✓ Pin ${i}: Using saved pin height: ${keyPinLength} (driver: ${driverPinLength})`); + console.log(`✓ Pin ${i}: Using scenario keyPin height: ${keyPinLength} (driver: ${driverPinLength})`); } else { // Generate random pin lengths that add up to 75 (total height - 25% increase from 60) keyPinLength = 25 + Math.random() * 37.5; // 25-62.5 (25% increase) diff --git a/js/systems/doors.js b/js/systems/doors.js index c8292c5..d673564 100644 --- a/js/systems/doors.js +++ b/js/systems/doors.js @@ -224,6 +224,9 @@ export function createDoorSpritesForRoom(roomId, position) { // Get lock properties from the destination room (the room you're trying to enter) const connectedRoomData = gameScenario.rooms[connectedRoom]; + // Check for both keyPins (camelCase) and key_pins (snake_case) in the room data + const keyPinsArray = connectedRoomData?.keyPins || connectedRoomData?.key_pins; + // Set up door properties doorSprite.doorProperties = { roomId: roomId, @@ -234,15 +237,18 @@ export function createDoorSpritesForRoom(roomId, position) { open: false, locked: connectedRoomData?.locked || false, lockType: connectedRoomData?.lockType || null, - requires: connectedRoomData?.requires || null + requires: connectedRoomData?.requires || null, + keyPins: keyPinsArray, // Include keyPins from scenario (supports both cases) + difficulty: connectedRoomData?.difficulty // Include difficulty from scenario }; // Debug door properties - console.log(`Door properties set for ${roomId} -> ${connectedRoom}:`, { + console.log(`🚪 Door properties set for ${roomId} -> ${connectedRoom}:`, { locked: doorSprite.doorProperties.locked, lockType: doorSprite.doorProperties.lockType, requires: doorSprite.doorProperties.requires, - connectedRoomData: connectedRoomData + keyPins: doorSprite.doorProperties.keyPins, + difficulty: doorSprite.doorProperties.difficulty }); // Set up door info for transition detection diff --git a/js/systems/inventory.js b/js/systems/inventory.js index aa4aa51..fe501b0 100644 --- a/js/systems/inventory.js +++ b/js/systems/inventory.js @@ -74,13 +74,32 @@ function createInventorySprite(itemData) { texture: { key: itemData.type // Use the type as the texture key for image lookup }, + // Copy critical properties for easy access + keyPins: itemData.keyPins, // Preserve keyPins for keys + key_id: itemData.key_id, // Preserve key_id for keys + locked: itemData.locked, + lockType: itemData.lockType, + requires: itemData.requires, + difficulty: itemData.difficulty, setVisible: function(visible) { // For inventory items, visibility is handled by DOM return this; } }; - console.log('Created inventory sprite:', sprite); + console.log('Created inventory sprite:', { + name: sprite.name, + key_id: sprite.key_id, + keyPins: sprite.keyPins, + locked: sprite.locked, + lockType: sprite.lockType + }); + + // Log if this is a key with keyPins + if (sprite.keyPins) { + console.log(`✓ Inventory key "${sprite.name}" has keyPins: [${sprite.keyPins.join(', ')}]`); + } + return sprite; } catch (error) { console.error('Error creating inventory sprite:', error); @@ -163,6 +182,14 @@ export function addToInventory(sprite) { itemImg.name = sprite.name; itemImg.objectId = 'inventory_' + sprite.objectId; + // Explicitly preserve critical lock-related properties + itemImg.keyPins = sprite.keyPins || sprite.scenarioData?.keyPins; + itemImg.key_id = sprite.key_id || sprite.scenarioData?.key_id; + itemImg.lockType = sprite.scenarioData?.lockType; + itemImg.locked = sprite.scenarioData?.locked; + itemImg.requires = sprite.scenarioData?.requires; + itemImg.difficulty = sprite.scenarioData?.difficulty; + // Mark as non-takeable once in inventory (so it won't try to be picked up again) itemImg.scenarioData.takeable = false; @@ -226,6 +253,16 @@ function addKeyToInventory(sprite) { // Add the key to the key ring window.inventory.keyRing.keys.push(sprite); + // Log key storage with keyPins + const keyId = sprite.scenarioData?.key_id || sprite.key_id; + const keyPins = sprite.scenarioData?.keyPins || sprite.keyPins; + console.log(`✓ Key "${sprite.scenarioData?.name}" added to key ring:`, { + key_id: keyId, + keyPins: keyPins, + locked: sprite.scenarioData?.locked, + lockType: sprite.scenarioData?.lockType + }); + // Update or create the key ring display updateKeyRingDisplay(); diff --git a/js/systems/key-lock-system.js b/js/systems/key-lock-system.js index 8bd8edb..6bc99d4 100644 --- a/js/systems/key-lock-system.js +++ b/js/systems/key-lock-system.js @@ -214,9 +214,55 @@ if (window.inventory && window.inventory.items) { } // Function to generate key cuts that match a specific lock's pin configuration -export function generateKeyCutsForLock(key, lockable) { +export function generateKeyCutsForLock(key, lockable, overrideKeyPins = null) { const keyId = key.scenarioData.key_id; + // First, try to use provided keyPins override, then lockable's keyPins + let keyPinsToUse = overrideKeyPins; + if (!keyPinsToUse) { + // Try to extract keyPins from the lockable (door or item) + if (lockable?.doorProperties?.keyPins || lockable?.doorProperties?.key_pins) { + keyPinsToUse = lockable.doorProperties.keyPins || lockable.doorProperties.key_pins; + console.log(`✓ Using keyPins from lockable.doorProperties:`, keyPinsToUse); + } else if (lockable?.scenarioData?.keyPins || lockable?.scenarioData?.key_pins) { + keyPinsToUse = lockable.scenarioData.keyPins || lockable.scenarioData.key_pins; + console.log(`✓ Using keyPins from lockable.scenarioData:`, keyPinsToUse); + } else if (lockable?.keyPins || lockable?.key_pins) { + keyPinsToUse = lockable.keyPins || lockable.key_pins; + console.log(`✓ Using keyPins from lockable object:`, keyPinsToUse); + } + } + + // If we have keyPins from the scenario, use them directly + if (keyPinsToUse && Array.isArray(keyPinsToUse)) { + console.log(`Generating cuts for key "${key.scenarioData.name}" using scenario keyPins:`, keyPinsToUse); + + const cuts = []; + for (let i = 0; i < keyPinsToUse.length; i++) { + const keyPinLength = keyPinsToUse[i]; + + // Calculate cut depth with relationship to key pin length + // Based on the lockpicking minigame formula: + // Cut depth = key pin length - gap from key blade top to shear line + const keyBladeTop_world = 175; // Key blade top position + const shearLine_world = 155; // Shear line position + const gapFromKeyBladeTopToShearLine = keyBladeTop_world - shearLine_world; // 20 + + // Calculate the required cut depth + const cutDepth_needed = keyPinLength - gapFromKeyBladeTopToShearLine; + + // Clamp to valid range (0 to 110, which is key blade height) + const clampedCutDepth = Math.max(0, Math.min(110, cutDepth_needed)); + + cuts.push(Math.round(clampedCutDepth)); + + console.log(`Pin ${i}: keyPinLength=${keyPinLength}, cutDepth=${clampedCutDepth} (gap=${gapFromKeyBladeTopToShearLine})`); + } + + console.log(`Generated cuts for key ${keyId} using scenario keyPins:`, cuts); + return cuts; + } + // Check if this key has a predefined lock assignment if (window.keyLockMappings && window.keyLockMappings[keyId]) { const mapping = window.keyLockMappings[keyId]; @@ -231,10 +277,7 @@ export function generateKeyCutsForLock(key, lockable) { for (let i = 0; i < lockConfig.pinCount; i++) { const keyPinLength = pinHeights[i] || 30; // Use predefined pin height - // Calculate cut depth with INVERSE relationship to key pin length - // Longer key pins need shallower cuts (less lift required) - // Shorter key pins need deeper cuts (more lift required) - + // Calculate cut depth with relationship to key pin length // Based on the lockpicking minigame formula: // Cut depth = key pin length - gap from key blade top to shear line const keyBladeTop_world = 175; // Key blade top position diff --git a/js/systems/minigame-starters.js b/js/systems/minigame-starters.js index 5f66dfd..10954cb 100644 --- a/js/systems/minigame-starters.js +++ b/js/systems/minigame-starters.js @@ -8,8 +8,35 @@ import { generateKeyCutsForLock, doesKeyMatchLock, PREDEFINED_LOCK_CONFIGS } from './key-lock-system.js'; -export function startLockpickingMinigame(lockable, scene, difficulty = 'medium', callback) { - console.log('Starting lockpicking minigame with difficulty:', difficulty); +export function startLockpickingMinigame(lockable, scene, difficulty = 'medium', callback, keyPins = null) { + console.log('🎮 startLockpickingMinigame called with:', { + keyPinsParam: keyPins, + difficulty: difficulty, + lockable: lockable?.name || lockable?.scenarioData?.name || 'unknown', + hasDoorProperties: !!lockable?.doorProperties, + hasScenarioData: !!lockable?.scenarioData + }); + + // If keyPins not provided as parameter, try to extract from lockable object + if (!keyPins) { + if (lockable?.doorProperties?.keyPins || lockable?.doorProperties?.key_pins) { + keyPins = lockable.doorProperties.keyPins || lockable.doorProperties.key_pins; + console.log('✓ Extracted keyPins from door properties:', keyPins); + } else if (lockable?.scenarioData?.keyPins || lockable?.scenarioData?.key_pins) { + keyPins = lockable.scenarioData.keyPins || lockable.scenarioData.key_pins; + console.log('✓ Extracted keyPins from scenarioData:', keyPins); + } else if (lockable?.keyPins || lockable?.key_pins) { + keyPins = lockable.keyPins || lockable.key_pins; + console.log('✓ Extracted keyPins from lockable property:', keyPins); + } else { + console.warn('⚠ No keyPins found in lockable object - will use random pins'); + } + } else { + console.log('✓ Using keyPins passed as parameter:', keyPins); + } + + console.log('🎮 Starting lockpicking minigame with difficulty:', difficulty, 'keyPins:', keyPins); + // Initialize the minigame framework if not already done if (!window.MinigameFramework) { @@ -75,6 +102,7 @@ export function startLockpickingMinigame(lockable, scene, difficulty = 'medium', window.MinigameFramework.startMinigame('lockpicking', null, { lockable: lockable, difficulty: difficulty, + predefinedPinHeights: keyPins, // Pass scenario keyPins as predefinedPinHeights itemName: itemName, itemImage: itemImage, itemObservations: itemObservations, @@ -207,32 +235,53 @@ export function startKeySelectionMinigame(lockable, type, playerKeys, requiredKe }); // Determine which lock configuration to use for this lockable + // CHANGED: Now get keyPins from scenario instead of predefined configurations let lockConfig = null; + let scenarioKeyPins = null; + let scenarioDifficulty = null; - // First, try to find the lock configuration from scenario-based mappings - if (lockable.scenarioData?.requires) { - const requiredKeyId = lockable.scenarioData.requires; - if (window.keyLockMappings && window.keyLockMappings[requiredKeyId]) { - lockConfig = window.keyLockMappings[requiredKeyId].lockConfig; - console.log(`Using scenario-based lock configuration for key "${requiredKeyId}":`, lockConfig); - } + // First, try to get keyPins from the lockable's scenario data + if (lockable?.doorProperties?.keyPins) { + // This is a door - get keyPins from door properties + scenarioKeyPins = lockable.doorProperties.keyPins; + scenarioDifficulty = lockable.doorProperties.difficulty; + console.log(`✓ Using keyPins from door properties:`, scenarioKeyPins); + } else if (lockable?.scenarioData?.keyPins) { + // This is an item - get keyPins from scenario data + scenarioKeyPins = lockable.scenarioData.keyPins; + scenarioDifficulty = lockable.scenarioData.difficulty; + console.log(`✓ Using keyPins from item scenarioData:`, scenarioKeyPins); + } else if (lockable?.keyPins) { + // Fallback: keyPins might be stored directly on the object + scenarioKeyPins = lockable.keyPins; + scenarioDifficulty = lockable.difficulty; + console.log(`✓ Using keyPins from lockable object:`, scenarioKeyPins); } - // Fallback to predefined configurations - if (!lockConfig && PREDEFINED_LOCK_CONFIGS[lockId]) { - lockConfig = PREDEFINED_LOCK_CONFIGS[lockId]; - console.log(`Using predefined lock configuration for ${lockId}:`, lockConfig); - } - - // Final fallback to default configuration - if (!lockConfig) { + // If we have scenario keyPins, use them to build the lock config + if (scenarioKeyPins && Array.isArray(scenarioKeyPins)) { lockConfig = { id: lockId, - pinCount: 4, - pinHeights: [30, 28, 32, 29], - difficulty: 'medium' + pinCount: scenarioKeyPins.length, + pinHeights: scenarioKeyPins, + difficulty: scenarioDifficulty || 'medium' }; - console.log(`Using default lock configuration for ${lockId}:`, lockConfig); + console.log(`Created lock configuration from scenario keyPins:`, lockConfig); + } else { + // Fallback to predefined configurations if no scenario keyPins found + if (PREDEFINED_LOCK_CONFIGS[lockId]) { + lockConfig = PREDEFINED_LOCK_CONFIGS[lockId]; + console.log(`Falling back to predefined lock configuration for ${lockId}:`, lockConfig); + } else { + // Final fallback to default configuration + lockConfig = { + id: lockId, + pinCount: 4, + pinHeights: [30, 28, 32, 29], + difficulty: 'medium' + }; + console.log(`Using default lock configuration for ${lockId}:`, lockConfig); + } } // Extract item information from lockable object (handles both items and doors) diff --git a/js/systems/unlock-system.js b/js/systems/unlock-system.js index e9599f7..86d4e2d 100644 --- a/js/systems/unlock-system.js +++ b/js/systems/unlock-system.js @@ -95,7 +95,24 @@ export function handleUnlock(lockable, type) { } else if (hasLockpick) { // Only lockpick available - launch lockpicking minigame directly console.log('LOCKPICK AVAILABLE - STARTING LOCKPICKING MINIGAME'); - let difficulty = lockable.scenarioData?.difficulty || lockable.properties?.difficulty || 'medium'; + let difficulty = lockable.doorProperties?.difficulty || lockable.scenarioData?.difficulty || lockable.properties?.difficulty || lockRequirements.difficulty || 'medium'; + // Check for both keyPins (camelCase) and key_pins (snake_case) + let keyPins = lockable.doorProperties?.keyPins || lockable.doorProperties?.key_pins || + lockable.scenarioData?.keyPins || lockable.scenarioData?.key_pins || + lockable.properties?.keyPins || lockable.properties?.key_pins || + lockRequirements.keyPins || lockRequirements.key_pins; + + console.log('🔓 Door/Item lock details:', { + hasDoorProperties: !!lockable.doorProperties, + doorKeyPins: lockable.doorProperties?.keyPins, + hasScenarioData: !!lockable.scenarioData, + scenarioKeyPins: lockable.scenarioData?.keyPins, + hasProperties: !!lockable.properties, + propertiesKeyPins: lockable.properties?.keyPins, + lockRequirementsKeyPins: lockRequirements.keyPins, + finalKeyPins: keyPins, + finalDifficulty: difficulty + }); startLockpickingMinigame(lockable, window.game, difficulty, (success) => { if (success) { @@ -107,7 +124,7 @@ export function handleUnlock(lockable, type) { console.log('LOCKPICK FAILED'); window.gameAlert('Failed to pick the lock. Try again.', 'error', 'Pick Failed', 3000); } - }); + }, keyPins); // Pass keyPins to minigame starter } else { console.log('NO KEYS OR LOCKPICK AVAILABLE'); window.gameAlert(`Requires key`, 'error', 'Locked', 4000); @@ -259,7 +276,9 @@ export function getLockRequirementsForDoor(doorSprite) { if (props.locked) { return { lockType: props.lockType, - requires: props.requires + requires: props.requires, + keyPins: props.keyPins, // Include keyPins for scenario-based locks + difficulty: props.difficulty }; } } @@ -302,6 +321,8 @@ export function getLockRequirementsForDoor(doorSprite) { distance: distanceToPlayer, lockType: roomData?.lockType, requires: roomData?.requires, + keyPins: roomData?.keyPins || roomData?.key_pins, // Include keyPins from scenario (supports both cases) + difficulty: roomData?.difficulty, locked: roomData?.locked }); } @@ -315,7 +336,9 @@ export function getLockRequirementsForDoor(doorSprite) { const targetRoom = lockedRooms[0]; return { lockType: targetRoom.lockType, - requires: targetRoom.requires + requires: targetRoom.requires, + keyPins: targetRoom.keyPins, // Include keyPins from scenario + difficulty: targetRoom.difficulty }; } @@ -327,7 +350,9 @@ export function getLockRequirementsForItem(item) { return { lockType: item.scenarioData.lockType || 'key', - requires: item.scenarioData.requires || '' + requires: item.scenarioData.requires || '', + keyPins: item.scenarioData.keyPins, // Include keyPins for scenario-based locks + difficulty: item.scenarioData.difficulty }; } diff --git a/scenarios/ceo_exfil.json b/scenarios/ceo_exfil.json index ddd4898..969ebfe 100644 --- a/scenarios/ceo_exfil.json +++ b/scenarios/ceo_exfil.json @@ -86,7 +86,7 @@ "name": "Office Key", "takeable": true, "key_id": "office1_key", - "key_pins": [40, 35, 38, 32], + "keyPins": [65.5, 25.5, 65.5, 25.5], "observations": "A key to access the office areas" }, { @@ -102,7 +102,7 @@ "locked": true, "lockType": "key", "requires": "office1_key", - "key_pins": [40, 35, 38, 32], + "keyPins": [65.5, 25.5, 65.5, 25.5], "difficulty": "easy", "door_sign": "4A Hot Desks", @@ -170,7 +170,7 @@ "name": "CEO Office Key", "takeable": true, "key_id": "ceo_office_key", - "key_pins": [10, 20, 30, 40], + "keyPins": [10, 20, 30, 40], "observations": "A spare key to the CEO's office, carelessly left behind" } ] @@ -210,7 +210,7 @@ "locked": true, "lockType": "key", "requires": "ceo_office_key", - "key_pins": [10, 20, 30, 40], + "keyPins": [10, 20, 30, 40], "difficulty": "easy", "objects": [ { @@ -233,7 +233,7 @@ "locked": true, "lockType": "key", "requires": "briefcase_key", - "key_pins": [45, 35, 25, 15], + "keyPins": [45, 35, 25, 15], "difficulty": "medium", "observations": "An expensive leather briefcase with a sturdy lock", "contents": [ @@ -250,7 +250,7 @@ "name": "Safe Key", "takeable": true, "key_id": "safe_key", - "key_pins": [52, 29, 44, 37], + "keyPins": [52, 29, 44, 37], "observations": "A heavy-duty safe key hidden behind server equipment" } ] @@ -283,7 +283,7 @@ "locked": true, "lockType": "key", "requires": "safe_key", - "key_pins": [52, 29, 44, 37], + "keyPins": [52, 29, 44, 37], "difficulty": "hard", "observations": "A well-hidden wall safe behind a painting", "contents": [ @@ -319,7 +319,7 @@ "name": "Briefcase Key", "takeable": true, "key_id": "briefcase_key", - "key_pins": [45, 35, 25, 15], + "keyPins": [45, 35, 25, 15], "observations": "A small key labeled 'Personal - Do Not Copy'" } ] diff --git a/scenarios/cybok_heist.json b/scenarios/cybok_heist.json index 4a3b017..ca28c66 100644 --- a/scenarios/cybok_heist.json +++ b/scenarios/cybok_heist.json @@ -52,7 +52,8 @@ "type": "room_office", "locked": true, "lockType": "key", - "requires": "admin_office_key:25,30,35,40", + "requires": "admin_office_key", + "keyPins": [60,50,40,30], "difficulty": "medium", "door_sign": "Admin Office - Authorized Personnel Only", "connections": { @@ -78,7 +79,8 @@ "type": "key", "name": "Professor's Office Key", "takeable": true, - "key_id": "prof_office_key:25,30,35,40", + "key_id": "prof_office_key", + "keyPins": [40, 35, 38, 32], "observations": "A dusty key marked 'Professor'." } ] @@ -92,7 +94,8 @@ }, "locked": true, "lockType": "key", - "requires": "prof_office_key:25,30,35,40", + "requires": "prof_office_key", + "keyPins": [40, 35, 38, 32], "difficulty": "medium", "door_sign": "Professor's Office - Do Not Disturb!", "objects": [