feat: Implement scenario-based keyPins for locks and keys, enhancing lockpicking mechanics

This commit is contained in:
Z. Cliffe Schreuders
2025-10-28 11:33:54 +00:00
parent 004a537936
commit 90fa4d0047
13 changed files with 298 additions and 99 deletions

View File

@@ -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);

View File

@@ -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(', ')}]`);
}
}
/**

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -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)

View File

@@ -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
};
}

View File

@@ -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'"
}
]

View File

@@ -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": [