diff --git a/assets/objects/key-ring.png b/assets/objects/key-ring.png new file mode 100644 index 0000000..9ff347a Binary files /dev/null and b/assets/objects/key-ring.png differ diff --git a/css/inventory.css b/css/inventory.css index 3e31e47..3e463ab 100644 --- a/css/inventory.css +++ b/css/inventory.css @@ -69,4 +69,33 @@ .inventory-item:hover + .inventory-tooltip { opacity: 1; +} + +/* Key ring specific styling */ +.inventory-item[data-type="key_ring"] { + position: relative; +} + +.inventory-item[data-type="key_ring"]::after { + content: attr(data-key-count); + position: absolute; + top: -5px; + right: -5px; + background: #ff6b6b; + color: white; + border-radius: 50%; + width: 18px; + height: 18px; + font-size: 10px; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + border: 2px solid #fff; + box-shadow: 0 2px 4px rgba(0,0,0,0.3); +} + +/* Hide count badge for single keys */ +.inventory-item[data-type="key_ring"][data-key-count="1"]::after { + display: none; } \ No newline at end of file diff --git a/js/systems/inventory.js b/js/systems/inventory.js index 4d56f90..389df98 100644 --- a/js/systems/inventory.js +++ b/js/systems/inventory.js @@ -123,6 +123,11 @@ export function addToInventory(sprite) { sprite.setVisible(false); + // Special handling for keys - group them together + if (sprite.scenarioData.type === 'key') { + return addKeyToInventory(sprite); + } + // Create a new slot for this item const inventoryContainer = document.getElementById('inventory-container'); if (!inventoryContainer) { @@ -212,6 +217,134 @@ export function addToInventory(sprite) { } } +// Key management functions +function addKeyToInventory(sprite) { + // Initialize key ring if it doesn't exist + if (!window.inventory.keyRing) { + window.inventory.keyRing = { + keys: [], + slot: null, + itemImg: null + }; + } + + // Add the key to the key ring + window.inventory.keyRing.keys.push(sprite); + + // Update or create the key ring display + updateKeyRingDisplay(); + + // Show notification + if (window.gameAlert) { + window.gameAlert(`Added ${sprite.scenarioData.name} to key ring`, 'success', 'Key Collected', 3000); + } + + return true; +} + +function updateKeyRingDisplay() { + const keyRing = window.inventory.keyRing; + if (!keyRing || keyRing.keys.length === 0) { + // Remove key ring display if no keys + if (keyRing && keyRing.slot) { + keyRing.slot.remove(); + keyRing.slot = null; + keyRing.itemImg = null; + } + return; + } + + const inventoryContainer = document.getElementById('inventory-container'); + if (!inventoryContainer) { + console.error('Inventory container not found'); + return; + } + + // Remove existing key ring slot if it exists + if (keyRing.slot) { + keyRing.slot.remove(); + } + + // Create new slot for key ring + const slot = document.createElement('div'); + slot.className = 'inventory-slot'; + inventoryContainer.appendChild(slot); + + // Create key ring item + const itemImg = document.createElement('img'); + itemImg.className = 'inventory-item'; + itemImg.src = keyRing.keys.length === 1 ? `assets/objects/key.png` : `assets/objects/key-ring.png`; + itemImg.alt = keyRing.keys.length === 1 ? keyRing.keys[0].scenarioData.name : 'Key Ring'; + + // Add data attributes for styling + itemImg.setAttribute('data-type', 'key_ring'); + itemImg.setAttribute('data-key-count', keyRing.keys.length); + + // Create tooltip + const tooltip = document.createElement('div'); + tooltip.className = 'inventory-tooltip'; + tooltip.textContent = keyRing.keys.length === 1 ? keyRing.keys[0].scenarioData.name : 'Key Ring'; + + // Add item data - use the first key's data as the primary data + itemImg.scenarioData = { + ...keyRing.keys[0].scenarioData, + name: keyRing.keys.length === 1 ? keyRing.keys[0].scenarioData.name : 'Key Ring', + type: 'key_ring', + keyCount: keyRing.keys.length, + allKeys: keyRing.keys.map(k => k.scenarioData) + }; + itemImg.name = 'key'; + itemImg.objectId = 'inventory_key_ring'; + + // Add click handler for key ring + itemImg.addEventListener('click', function() { + if (window.handleKeyRingInteraction) { + window.handleKeyRingInteraction(this); + } + }); + + // Add to slot + slot.appendChild(itemImg); + slot.appendChild(tooltip); + + // Store references + keyRing.slot = slot; + keyRing.itemImg = itemImg; + + // Add to inventory array (replace any existing key ring item) + const existingKeyRingIndex = window.inventory.items.findIndex(item => + item && item.scenarioData && item.scenarioData.type === 'key_ring' + ); + + if (existingKeyRingIndex !== -1) { + window.inventory.items[existingKeyRingIndex] = itemImg; + } else { + window.inventory.items.push(itemImg); + } +} + +function handleKeyRingInteraction(keyRingItem) { + const keyRing = window.inventory.keyRing; + if (!keyRing || keyRing.keys.length === 0) { + return; + } + + if (keyRing.keys.length === 1) { + // Single key - handle normally + if (window.handleObjectInteraction) { + window.handleObjectInteraction(keyRingItem); + } + } else { + // Multiple keys - show list + const keyNames = keyRing.keys.map(key => key.scenarioData.name).join('\n• '); + const message = `Key Ring contains ${keyRing.keys.length} keys:\n• ${keyNames}`; + + if (window.gameAlert) { + window.gameAlert(message, 'info', 'Key Ring', 0); + } + } +} + // Add notepad to inventory function addNotepadToInventory() { // Check if notepad is already in inventory @@ -310,4 +443,5 @@ window.processInitialInventoryItems = processInitialInventoryItems; window.addToInventory = addToInventory; window.removeFromInventory = removeFromInventory; window.addNotepadToInventory = addNotepadToInventory; -window.createItemIdentifier = createItemIdentifier; \ No newline at end of file +window.createItemIdentifier = createItemIdentifier; +window.handleKeyRingInteraction = handleKeyRingInteraction; \ No newline at end of file diff --git a/js/systems/key-lock-system.js b/js/systems/key-lock-system.js index cfb7e3f..8bd8edb 100644 --- a/js/systems/key-lock-system.js +++ b/js/systems/key-lock-system.js @@ -44,11 +44,33 @@ const PREDEFINED_LOCK_CONFIGS = { function assignKeysToLocks() { console.log('Assigning keys to locks based on scenario definitions...'); - // Get all keys from inventory - const playerKeys = window.inventory?.items?.filter(item => + // Get all keys from inventory (including key ring) + let playerKeys = []; + + // Check for individual keys + const individualKeys = window.inventory?.items?.filter(item => item && item.scenarioData && item.scenarioData.type === 'key' ) || []; + playerKeys = playerKeys.concat(individualKeys); + + // Check for key ring + const keyRingItem = window.inventory?.items?.find(item => + item && item.scenarioData && + item.scenarioData.type === 'key_ring' + ); + + if (keyRingItem && keyRingItem.scenarioData.allKeys) { + // Convert key ring keys to the format expected by the system + const keyRingKeys = keyRingItem.scenarioData.allKeys.map(keyData => { + return { + scenarioData: keyData, + name: 'key', + objectId: `key_ring_${keyData.key_id || keyData.name}` + }; + }); + playerKeys = playerKeys.concat(keyRingKeys); + } console.log(`Found ${playerKeys.length} keys in inventory`); diff --git a/js/systems/unlock-system.js b/js/systems/unlock-system.js index 2a8e375..45fb293 100644 --- a/js/systems/unlock-system.js +++ b/js/systems/unlock-system.js @@ -53,11 +53,34 @@ export function handleUnlock(lockable, type) { const requiredKey = lockRequirements.requires; console.log('KEY REQUIRED', requiredKey); - // Get all keys from player's inventory - const playerKeys = window.inventory.items.filter(item => + // Get all keys from player's inventory (including key ring) + let playerKeys = []; + + // Check for individual keys + const individualKeys = window.inventory.items.filter(item => item && item.scenarioData && item.scenarioData.type === 'key' ); + playerKeys = playerKeys.concat(individualKeys); + + // Check for key ring + const keyRingItem = window.inventory.items.find(item => + item && item.scenarioData && + item.scenarioData.type === 'key_ring' + ); + + if (keyRingItem && keyRingItem.scenarioData.allKeys) { + // Convert key ring keys to the format expected by the minigame + const keyRingKeys = keyRingItem.scenarioData.allKeys.map(keyData => { + // Create a mock inventory item for each key in the ring + return { + scenarioData: keyData, + name: 'key', + objectId: `key_ring_${keyData.key_id || keyData.name}` + }; + }); + playerKeys = playerKeys.concat(keyRingKeys); + } if (playerKeys.length > 0) { // Show key selection interface