From 6afbe0331b7becf02e92ae9803836a1fa2a57292 Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Thu, 27 Mar 2025 16:22:27 +0000 Subject: [PATCH] Refactor object handling in index.html to improve room object management and interaction. Introduced a mapping system for room objects by type, streamlined sprite creation, and enhanced inventory handling with unique identifiers. Updated scenario and room JSON files to reflect new object types and connections. --- assets/rooms/room_office.json | 12 +- assets/scenarios/scenario2.json | 24 ++-- index.html | 205 ++++++++++++++++++++------------ 3 files changed, 150 insertions(+), 91 deletions(-) diff --git a/assets/rooms/room_office.json b/assets/rooms/room_office.json index 8d01e3b..c575886 100644 --- a/assets/rooms/room_office.json +++ b/assets/rooms/room_office.json @@ -183,6 +183,17 @@ "x":113.75128085701, "y":36.7545412203075 }, + { + "height":48, + "id":18, + "name":"safe", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":265.75128085701, + "y":36.7545412203075 + }, { "height":48, @@ -229,7 +240,6 @@ "y":251.312529110387 }, { - "gid":428, "height":48, "id":14, "name":"pc2", diff --git a/assets/scenarios/scenario2.json b/assets/scenarios/scenario2.json index 71c0eb1..3fb9832 100644 --- a/assets/scenarios/scenario2.json +++ b/assets/scenarios/scenario2.json @@ -1,9 +1,9 @@ { "scenario_brief": "You are a curious traveler who stumbles upon Beckett, a ghost town shrouded in mystery. After entering the only standing building, the door slams shut, trapping you inside. A note from Mayor McFluffins warns: 'Fail to escape, and you’ll be turned into a llama.' Solve cryptographic puzzles and break the curse before time runs out, or grow fur and join the town’s eerie fate!", - "startRoom": "room_reception", + "startRoom": "room_start", "rooms": { - "room_reception": { - "type": "room_reception", + "room_start": { + "type": "room_office", "connections": { "north": "room_office" }, @@ -30,7 +30,7 @@ "takeable": true, "readable": true, "observations": "Numbers are important, remember these to proceed:\n- Prime modulus (p): 23\n- Base (g): 5\n- Tim's private key (a): 3\n- Jullie's private key (b): 5\nCalculate Tim's public key, Jullie's public key, and the final shared secret key." - }, + }, { "type": "pc", "name": "Computer", @@ -40,7 +40,7 @@ }, { "type": "safe", - "name": "Safe1", + "name": "Safe 1", "takeable": false, "locked": true, "lockType": "password", @@ -58,7 +58,7 @@ ] }, { - "type": "safe2", + "type": "safe", "name": "Safe 2", "takeable": false, "locked": true, @@ -77,13 +77,13 @@ ] }, { - "type": "safe3", - "name": "Safe 3", + "type": "suitcase", + "name": "Briefcase", "takeable": false, "locked": true, "lockType": "password", "requires": "19", - "observations": "A locked safe containing the key to the next room.", + "observations": "A locked briefcase containing the key to the next room.", "contents": [ { "type": "key", @@ -99,7 +99,7 @@ "room_office": { "type": "room_office", "connections": { - "south": "room_reception", + "south": "room_start", "north": "room_servers" }, "locked": true, @@ -150,13 +150,13 @@ "text": "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQCczVF4Oq+Njf1Olf/JNnZcSP0jbZVpdVJ+hySa7OPMSpjMsppb\nV1E8qytLIx+HfiU065I/Lhr0LhoKj+hWA3ceCUQa2GeSU+p8X5bseet6/hhrsBYV\nuT+4ajIQ8tDOi/0vrnSh+EMc912TpjAh1nEfeL65LXOwWHDf0rR8Uxv3AQIDAQAB\nAoGACiIVo/6s5im5Jzk32r2/h+a6ny2/hF1t25npsm5hKUxf1Aitw33g1Nod9eDa" }, { - "type": "notes2", + "type": "notes", "name": "Private Key Part 2", "takeable": true, "readable": true, "observations": "8oNjLaiUnqsg2EtbaPfUVKysJ6WaFQ4BnFe6rKQH+kXDEjSOyMcQsoObO0Bcjk/3\nWpxdTH0qp71yHzg1D6h40cwSra5u/t/ZRFJI/08hBdbt8DECQQDPQwVS5hYfDfXa\ni5Rxwwp4EBZmvy8z/KXPJ+8sXfqi5pBkZTrQfWsiqCW2aRtnTUsC0b3HjRQxf2SV\n+1y9aqQpAkEAwaypvhpE7I2P1LgIPrgW2HM1wiP0oZiM9LizsDHYO/bKqSWL7hnS\n/s6NcQ5CLOyB3uxYBkDIovUSem6/Y6hXGQJBAKi/qaMAQLySEj0Y7gjdwzVT69lG", "text": "Cfmq15ldq0cVUU62qJOFNCiyJLt36hSlaTFnZg5qlLjXbbyLO2s92BlErVkCQDaY\nH3kxGoC8HvFNtzVG21nEkEDbtdffksxhTHW8d0Hf/ZzUsq85pFqjiwd1h332ZV2b\nreyFUoltH/pXQagsCfECQFyG0RpJtc9ojIRUMOqDGQvoi8il4xM4yCiSKQAcLzuu\nqLrEVyNbKHcBf2Hn3xuEHs/DB6zCLVj/FJ7ZWONCJuU=\n-----END RSA PRIVATE KEY-----" - } + } ] }, "room_closet": { diff --git a/index.html b/index.html index bf924e1..0afd344 100644 --- a/index.html +++ b/index.html @@ -2338,54 +2338,93 @@ if (objectsLayer && objectsLayer.objects) { rooms[roomId].objects = {}; + // Create a map of room objects by type for easy lookup + const roomObjectsByType = {}; objectsLayer.objects.forEach(obj => { - // Find matching object in scenario data - const scenarioObject = gameScenario.rooms[roomId].objects.find( - item => item.type === obj.name - ); - - // Check if this object should be active in the current scenario - const isActiveObject = scenarioObject !== undefined; - - const sprite = this.add.sprite( - position.x + obj.x, - position.y + (obj.gid !== undefined ? obj.y - obj.height : obj.y), - obj.name - ); - - sprite.setOrigin(0, 0); - sprite.name = obj.name; - sprite.setInteractive({ useHandCursor: true }); - sprite.setDepth(1001); - sprite.originalAlpha = 1; - sprite.active = isActiveObject; - - // Store scenario data with sprite for later use - if (isActiveObject) { - sprite.scenarioData = scenarioObject; + if (!roomObjectsByType[obj.name]) { + roomObjectsByType[obj.name] = []; } - - // Initially hide all objects - they'll be shown when room is revealed - sprite.setVisible(false); - - if (obj.rotation) { - sprite.setRotation(Phaser.Math.DegToRad(obj.rotation)); - } - - rooms[roomId].objects[obj.name] = sprite; - - // Add click handler for all objects - sprite.on('pointerdown', () => { - if (isActiveObject) { - debugLog('OBJECT CLICKED', { name: obj.name }, 2); - handleObjectInteraction(sprite); - } else { - gameAlert("Nothing of note here", 'info', '', 2000); - } - }); + roomObjectsByType[obj.name].push(obj); }); + + // Process scenario objects first + if (gameScenario.rooms[roomId].objects) { + gameScenario.rooms[roomId].objects.forEach((scenarioObj, index) => { + const objType = scenarioObj.type; + // skip "inInventory": true, + if (scenarioObj.inInventory) { + return; + } + + // Try to find a matching room object + let roomObj = null; + if (roomObjectsByType[objType] && roomObjectsByType[objType].length > 0) { + // Take the first available room object of this type + roomObj = roomObjectsByType[objType].shift(); + } + + let sprite; + + if (roomObj) { + // Create sprite at the room object's position + sprite = this.add.sprite( + position.x + roomObj.x, + position.y + (roomObj.gid !== undefined ? roomObj.y - roomObj.height : roomObj.y), + objType + ); + + if (roomObj.rotation) { + sprite.setRotation(Phaser.Math.DegToRad(roomObj.rotation)); + } + + // Create a unique key using the room object's ID + sprite.objectId = `${objType}_${roomObj.id || index}`; + } else { + // No matching room object, create at random position + // Assuming room size is 10x9 tiles of 48px each + const roomWidth = 10 * 48; + const roomHeight = 9 * 48; + + // Add some padding from the edges (2 tile width) + const padding = 48*2; + + const randomX = position.x + padding + Math.random() * (roomWidth - padding * 2); + const randomY = position.y + padding + Math.random() * (roomHeight - padding * 2); + + sprite = this.add.sprite(randomX, randomY, objType); + console.log(`Created object ${objType} at random position (${randomX}, ${randomY})`); + } + + // SIMPLIFIED NAMING APPROACH + // Use a consistent format: roomId_type_index + const objectId = `${roomId}_${objType}_${index}`; + + // Set common properties + sprite.setOrigin(0, 0); + sprite.name = objType; // Keep name as the object type for texture loading + sprite.objectId = objectId; // Use our simplified ID format + sprite.setInteractive({ useHandCursor: true }); + sprite.setDepth(1001); + sprite.originalAlpha = 1; + sprite.active = true; + + // Store scenario data with sprite + sprite.scenarioData = scenarioObj; + + // Initially hide the object + sprite.setVisible(false); + + // Store the object + rooms[roomId].objects[objectId] = sprite; + + // Add click handler + sprite.on('pointerdown', () => { + debugLog('OBJECT CLICKED', { name: objType, id: objectId }, 2); + handleObjectInteraction(sprite); + }); + }); + } } - } catch (error) { console.error(`Error creating room ${roomId}:`, error); console.error('Error details:', error.stack); @@ -2985,7 +3024,8 @@ // Only log detailed object interactions at debug level 2+ debugLog('OBJECT INTERACTION', { name: sprite.name, - type: sprite.scenarioData?.type + id: sprite.objectId, + scenarioData: sprite.scenarioData }, 2); if (!sprite || !sprite.scenarioData) { @@ -2993,6 +3033,9 @@ return; } + // Log the full object data to help debug + console.log("Interacting with object:", sprite.scenarioData); + // Handle the Crypto Workstation if (sprite.scenarioData.type === "workstation") { openCryptoWorkstation(); @@ -3010,7 +3053,8 @@ if (distanceSq > INTERACTION_RANGE_SQ) { // Player is too far away to interact debugLog('INTERACTION_OUT_OF_RANGE', { - objectName: sprite.name, + objectName: sprite.name, + objectId: sprite.objectId, distance: Math.sqrt(distanceSq), maxRange: Math.sqrt(INTERACTION_RANGE_SQ) }, 2); @@ -3114,6 +3158,8 @@ } } } + + console.log("Interacting with object:", data); if (data.takeable) { // If it's a note type item that's already been read and added to notes, @@ -3122,10 +3168,10 @@ data.type === 'notes' && data.readable && data.text && - !data.hasSpecialPurpose; // Add this flag to notes that need to be in inventory + !data.hasNoSpecialPurpose; // Add this flag to notes that need to be in inventory if (!isJustInformationalNote) { - message += `This item can be taken\n\n`; + // message += `This item can be taken\n\n`; if (!inventory || !Array.isArray(inventory.items)) { console.error('Inventory not properly initialized'); @@ -3133,9 +3179,9 @@ } const isInRoom = currentRoom && - rooms[currentRoom] && - rooms[currentRoom].objects && - rooms[currentRoom].objects[sprite.name]; + rooms[currentRoom] && + rooms[currentRoom].objects && + rooms[currentRoom].objects[sprite.objectId]; const itemIdentifier = createItemIdentifier(sprite.scenarioData); @@ -3152,9 +3198,9 @@ if (currentRoom && rooms[currentRoom] && rooms[currentRoom].objects && - rooms[currentRoom].objects[sprite.name]) { + rooms[currentRoom].objects[sprite.objectId]) { - const roomObj = rooms[currentRoom].objects[sprite.name]; + const roomObj = rooms[currentRoom].objects[sprite.objectId]; roomObj.setVisible(false); roomObj.active = false; @@ -3181,47 +3227,58 @@ } try { - // Check if the item is already in the inventory using the unique identifier - const itemIdentifier = createItemIdentifier(sprite.scenarioData); - console.log(`Checking if item ${itemIdentifier} is already in inventory`); + // Debug logging + console.log("Trying to add to inventory:", { + objectId: sprite.objectId, + name: sprite.name, + type: sprite.scenarioData?.type, + currentRoom: currentRoom + }); + // Check if the item is already in the inventory + const itemIdentifier = createItemIdentifier(sprite.scenarioData); const isAlreadyInInventory = inventory.items.some(item => createItemIdentifier(item.scenarioData) === itemIdentifier ); if (isAlreadyInInventory) { - console.log(`Item ${itemIdentifier} is already in inventory, not adding again`); + console.log(`Item ${itemIdentifier} is already in inventory`); return false; } // Remove from room if it exists - if (currentRoom && - rooms[currentRoom] && - rooms[currentRoom].objects && - rooms[currentRoom].objects[sprite.name]) { - - const roomObj = rooms[currentRoom].objects[sprite.name]; - roomObj.setVisible(false); - roomObj.active = false; + if (currentRoom && rooms[currentRoom] && rooms[currentRoom].objects) { + // Try to find by objectId first + if (rooms[currentRoom].objects[sprite.objectId]) { + const roomObj = rooms[currentRoom].objects[sprite.objectId]; + roomObj.setVisible(false); + roomObj.active = false; + console.log(`Removed object ${sprite.objectId} from room`); + } } + sprite.setVisible(false); const scene = sprite.scene; + // SIMPLIFIED INVENTORY NAMING + // Use a consistent format: inventory_type_index + const inventoryId = `inventory_${sprite.name}_${inventory.items.length}`; + // Create new sprite for inventory const inventorySprite = scene.add.sprite( - inventory.items.length * 60, // Remove the +100 offset + inventory.items.length * 60, 0, sprite.name ); - // inventorySprite.setScale(0.8); inventorySprite.setInteractive({ useHandCursor: true, pixelPerfect: true }); inventorySprite.scenarioData = { ...sprite.scenarioData, foundIn: currentRoom ? gameScenario.rooms[currentRoom].name || currentRoom : 'unknown location' }; inventorySprite.name = sprite.name; + inventorySprite.objectId = inventoryId; // Set depth higher than container inventorySprite.setDepth(2003); @@ -3229,6 +3286,7 @@ // Add pointer events inventorySprite.on('pointerdown', function(pointer) { // Handle inventory item interaction + handleObjectInteraction(inventorySprite); }); inventorySprite.on('pointerover', function() { @@ -3461,17 +3519,8 @@ // Add this new helper function: function createItemIdentifier(scenarioData) { - // Combine multiple properties to create a unique identifier - const identifierParts = [ - scenarioData.type, - scenarioData.name, - // Add more unique properties if available - scenarioData.key_id, // For keys - scenarioData.requires, // For locks - scenarioData.text // For readable items - ].filter(Boolean); // Remove any undefined/null values - - return identifierParts.join('|'); + // Just use type and name as the identifier + return `${scenarioData.type}|${scenarioData.name}`; } // Add this new function after the other function definitions