mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-21 11:18:08 +00:00
feat: Implement scenario-based keyPins for locks and keys, enhancing lockpicking mechanics
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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(', ')}]`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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'"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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": [
|
||||
|
||||
Reference in New Issue
Block a user