From 2c359fc46fbdccfc7b346a2569036db0b6153190 Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 00:07:56 +0000 Subject: [PATCH 01/10] Refactor toggle buttons layout and add container for better UI organization --- index.html | 82 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/index.html b/index.html index e203bc3..9f47632 100644 --- a/index.html +++ b/index.html @@ -266,9 +266,7 @@ } #notes-toggle { - position: fixed; - bottom: 20px; - right: 20px; + position: relative; width: 60px; height: 60px; background-color: #3498db; @@ -282,6 +280,7 @@ z-index: 1998; font-size: 28px; transition: all 0.3s ease; + margin-left: 10px; } #notes-toggle:hover { @@ -585,9 +584,7 @@ } #bluetooth-toggle { - position: fixed; - bottom: 20px; - right: 90px; + position: relative; width: 60px; height: 60px; background-color: #9b59b6; @@ -601,6 +598,7 @@ z-index: 1998; font-size: 28px; transition: all 0.3s ease; + margin-left: 10px; } #bluetooth-toggle:hover { @@ -855,9 +853,7 @@ } #biometrics-toggle { - position: fixed; - bottom: 20px; - right: 160px; + position: relative; width: 60px; height: 60px; background-color: #e74c3c; @@ -871,6 +867,7 @@ z-index: 1998; font-size: 28px; transition: all 0.3s ease; + margin-left: 10px; } #biometrics-toggle:hover { @@ -895,6 +892,27 @@ } /* Rest of existing styles follow */ + .biometric-sample-timestamp { + font-size: 11px; + color: #888; + margin-top: 5px; + text-align: right; + } + + /* Toggle Buttons Container */ + #toggle-buttons-container { + position: fixed; + bottom: 20px; + right: 20px; + display: flex; + flex-direction: row-reverse; + z-index: 1998; + } + + /* Game container */ + #game-container { + position: relative; + } @@ -923,9 +941,21 @@
-
- 📝 -
0
+ + +
+
+ 📝 +
0
+
+ +
@@ -944,10 +974,6 @@
-
@@ -965,10 +991,6 @@
- \ No newline at end of file From 538bfd2b6815871be710216bac51b8232ec7812b Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 00:19:56 +0000 Subject: [PATCH 02/10] Add null checks to toggle button initialization to prevent errors --- index.html | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 9f47632..3754c5f 100644 --- a/index.html +++ b/index.html @@ -6406,15 +6406,21 @@ function initializeToggleButtons() { // Set up notes toggle button const notesToggle = document.getElementById('notes-toggle'); - notesToggle.addEventListener('click', toggleNotesPanel); + if (notesToggle) { + notesToggle.addEventListener('click', toggleNotesPanel); + } // Set up bluetooth toggle button const bluetoothToggle = document.getElementById('bluetooth-toggle'); - bluetoothToggle.addEventListener('click', toggleBluetoothPanel); + if (bluetoothToggle) { + bluetoothToggle.addEventListener('click', toggleBluetoothPanel); + } // Set up biometrics toggle button const biometricsToggle = document.getElementById('biometrics-toggle'); - biometricsToggle.addEventListener('click', toggleBiometricsPanel); + if (biometricsToggle) { + biometricsToggle.addEventListener('click', toggleBiometricsPanel); + } } // Call the initialization function when the game starts From 44e51dfd699dcd29a9f3d73485a41ad8e64c9456 Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 15:29:05 +0000 Subject: [PATCH 03/10] Created a basic biometric scenario --- assets/scenarios/biometric_breach.json | 197 +++++++++++++++++++++++++ index.html | 2 +- 2 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 assets/scenarios/biometric_breach.json diff --git a/assets/scenarios/biometric_breach.json b/assets/scenarios/biometric_breach.json new file mode 100644 index 0000000..d149d4f --- /dev/null +++ b/assets/scenarios/biometric_breach.json @@ -0,0 +1,197 @@ +{ + "scenario_brief": "You are a security specialist tasked with investigating a high-security research facility after reports of unauthorized access. Your mission is to use biometric tools to identify the intruder and secure sensitive research data before it's stolen.", + "startRoom": "reception", + "rooms": { + "reception": { + "type": "room_reception", + "connections": { + "north": "lab1" + }, + "objects": [ + { + "type": "phone", + "name": "Reception Phone", + "takeable": false, + "readable": true, + "text": "Voicemail: 'Security alert: Unauthorized access detected in the biometrics lab. All personnel must verify identity at security checkpoints. Server room PIN changed to 5923. - Security Team'", + "observations": "The reception phone's message light is blinking with an urgent message" + }, + { + "type": "notes", + "name": "Security Log", + "takeable": true, + "readable": true, + "text": "Unusual access patterns detected:\n- Lab 1: 23:45 PM\n- Biometrics Lab: 01:30 AM\n- Server Room: 02:15 AM", + "observations": "A concerning security log from last night" + }, + { + "type": "fingerprint_kit", + "name": "Fingerprint Kit", + "takeable": true, + "inInventory": true, + "observations": "A professional kit for collecting fingerprint samples" + }, + { + "type": "pc", + "name": "Reception Computer", + "takeable": false, + "hasFingerprint": true, + "fingerprintOwner": "receptionist", + "fingerprintQuality": 0.8, + "observations": "The reception computer shows a security alert screen. There might be fingerprints on the keyboard." + } + ] + }, + "lab1": { + "type": "room_office", + "connections": { + "north": ["biolab", "server"], + "south": "reception" + }, + "objects": [ + { + "type": "pc", + "name": "Lab Computer", + "takeable": false, + "hasFingerprint": true, + "fingerprintOwner": "researcher", + "fingerprintQuality": 0.9, + "observations": "A research computer with data analysis software running. There might be fingerprints on the keyboard." + }, + { + "type": "notes", + "name": "Research Notes", + "takeable": true, + "readable": true, + "text": "Project Sentinel: Biometric security breakthrough. Final test results stored in secure server. Access requires Level 3 clearance or backup key.", + "observations": "Important research notes about a biometric security project" + }, + { + "type": "tablet", + "name": "Security Tablet", + "takeable": true, + "readable": true, + "text": "Security Alert: Unauthorized access to biometrics lab detected at 01:30 AM. Biometric scanner in server room requires admin fingerprint or emergency override key.", + "observations": "A security tablet showing access logs and alerts" + }, + { + "type": "key", + "name": "Biolab Key", + "takeable": true, + "key_id": "biolab_key", + "observations": "A backup key for the biometrics lab, kept for emergencies" + } + ] + }, + "biolab": { + "type": "room_office", + "connections": { + "south": "lab1" + }, + "locked": true, + "lockType": "key", + "requires": "biolab_key", + "difficulty": "medium", + "objects": [ + { + "type": "pc", + "name": "Biometrics Research Station", + "takeable": false, + "hasFingerprint": true, + "fingerprintOwner": "intruder", + "fingerprintQuality": 0.85, + "observations": "A specialized workstation for biometric research. The screen shows someone was recently using it." + }, + { + "type": "notes", + "name": "Access Log", + "takeable": true, + "readable": true, + "text": "Unusual access pattern detected: Admin credentials used during off-hours. Timestamp matches security alert. Safe PIN code: 8741", + "observations": "A log showing suspicious access to the biometrics lab" + }, + { + "type": "workstation", + "name": "Fingerprint Analysis Station", + "takeable": false, + "observations": "A specialized workstation for analyzing fingerprint samples" + }, + { + "type": "key", + "name": "Server Room Key", + "takeable": true, + "key_id": "server_key", + "observations": "A key to the server room, carelessly left behind by someone" + } + ] + }, + "server": { + "type": "room_servers", + "connections": { + "south": "lab1" + }, + "locked": true, + "lockType": "key", + "requires": "server_key", + "difficulty": "easy", + "objects": [ + { + "type": "pc", + "name": "Server Terminal", + "takeable": false, + "hasFingerprint": true, + "fingerprintOwner": "admin", + "fingerprintQuality": 0.95, + "observations": "The main server terminal controlling access to research data. There are clear fingerprints on the screen." + }, + { + "type": "safe", + "name": "Secure Data Safe", + "takeable": false, + "locked": true, + "lockType": "pin", + "requires": "8741", + "difficulty": "medium", + "observations": "A secure safe containing the sensitive research data", + "contents": [ + { + "type": "notes", + "name": "Project Sentinel Data", + "takeable": true, + "readable": true, + "text": "Complete research data for Project Sentinel biometric security system. Evidence shows unauthorized copy was made at 02:17 AM by someone using spoofed admin credentials.", + "observations": "The complete research data for the biometric security project" + }, + { + "type": "key", + "name": "Case Key", + "takeable": true, + "key_id": "case_key", + "observations": "A small key with a strange logo etched on it" + } + ] + }, + { + "type": "suitcase", + "name": "Suspicious Case", + "takeable": false, + "locked": true, + "lockType": "key", + "requires": "case_key", + "difficulty": "hard", + "observations": "A suspicious case hidden behind server racks", + "contents": [ + { + "type": "notes", + "name": "Stolen Data", + "takeable": true, + "readable": true, + "text": "Copy of Project Sentinel data and instructions for delivery to competitor. Payment confirmation included.", + "observations": "Evidence of corporate espionage and data theft" + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/index.html b/index.html index 3754c5f..a2a6615 100644 --- a/index.html +++ b/index.html @@ -1536,7 +1536,7 @@ this.load.image('lockpick', 'assets/objects/lockpick.png'); - this.load.json('gameScenarioJSON', 'assets/scenarios/ceo_exfil.json'); + this.load.json('gameScenarioJSON', 'assets/scenarios/biometric_breach.json'); gameScenario = this.cache.json.get('gameScenarioJSON'); } From 7adda138e37376a9f0d8d1b87cb523372f6dcee2 Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 15:33:51 +0000 Subject: [PATCH 04/10] Enhance inventory item uniqueness check with item identifier --- index.html | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index a2a6615..e708306 100644 --- a/index.html +++ b/index.html @@ -2886,10 +2886,16 @@ } try { - // Check if the item is already in the inventory - const isAlreadyInInventory = inventory.items.some(item => item.name === sprite.name); + // 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`); + + const isAlreadyInInventory = inventory.items.some(item => + createItemIdentifier(item.scenarioData) === itemIdentifier + ); + if (isAlreadyInInventory) { - console.log(`Item ${sprite.name} is already in inventory, not adding again`); + console.log(`Item ${itemIdentifier} is already in inventory, not adding again`); return false; } From 2fa510e7d8ff3c88968c3270266065273d8dc069 Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 15:54:30 +0000 Subject: [PATCH 05/10] Add support for pre-populating inventory items in scenario data --- assets/scenarios/biometric_breach.json | 7 +++++++ index.html | 28 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/assets/scenarios/biometric_breach.json b/assets/scenarios/biometric_breach.json index d149d4f..6250131 100644 --- a/assets/scenarios/biometric_breach.json +++ b/assets/scenarios/biometric_breach.json @@ -39,6 +39,13 @@ "fingerprintOwner": "receptionist", "fingerprintQuality": 0.8, "observations": "The reception computer shows a security alert screen. There might be fingerprints on the keyboard." + }, + { + "type": "lockpick", + "name": "Lockpick", + "takeable": true, + "inInventory": true, + "observations": "A tool for picking locks" } ] }, diff --git a/index.html b/index.html index e708306..f34a7e8 100644 --- a/index.html +++ b/index.html @@ -1733,6 +1733,9 @@ // Initialize game systems initializeInventory.call(this); + + // Process items marked with inInventory: true in the scenario data + processInitialInventoryItems.call(this); // Add the workstation to inventory addCryptoWorkstation.call(this); @@ -3037,6 +3040,31 @@ debugLog('INVENTORY INITIALIZED', inventory, 2); // Debug log at level 2 } + + // Process all items marked with inInventory: true in the scenario data + function processInitialInventoryItems() { + debugLog('PROCESSING INITIAL INVENTORY ITEMS', null, 2); + + // Loop through all rooms in the scenario + Object.entries(gameScenario.rooms).forEach(([roomId, roomData]) => { + if (!roomData.objects) return; + + // Check each object in the room + roomData.objects.forEach(objectData => { + // If the object has inInventory: true, add it to the player's inventory + if (objectData.takeable && objectData.inInventory === true) { + debugLog('ADDING INITIAL INVENTORY ITEM', objectData, 2); + + // Create a sprite for the item + const sprite = createInventorySprite(objectData); + if (sprite) { + // Add to inventory + addToInventory(sprite); + } + } + }); + }); + } // runs after rooms are fully set up // checks if doors are overlapping rooms and removes them if they are not From 3764f6428fdc91bfac56c74128a114ab4af5f418 Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 16:54:17 +0000 Subject: [PATCH 06/10] Refactor workstation creation and inventory handling in scenario loading --- assets/scenarios/biometric_breach.json | 7 ++++++ assets/scenarios/ceo_exfil.json | 7 ++++++ index.html | 35 ++++++++++++-------------- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/assets/scenarios/biometric_breach.json b/assets/scenarios/biometric_breach.json index 6250131..2fe3d07 100644 --- a/assets/scenarios/biometric_breach.json +++ b/assets/scenarios/biometric_breach.json @@ -46,6 +46,13 @@ "takeable": true, "inInventory": true, "observations": "A tool for picking locks" + }, + { + "type": "workstation", + "name": "Crypto Analysis Station", + "takeable": true, + "inInventory": true, + "observations": "A powerful workstation for cryptographic analysis" } ] }, diff --git a/assets/scenarios/ceo_exfil.json b/assets/scenarios/ceo_exfil.json index 2a77d16..aec2aa3 100644 --- a/assets/scenarios/ceo_exfil.json +++ b/assets/scenarios/ceo_exfil.json @@ -47,6 +47,13 @@ "observations": "A device for detecting nearby Bluetooth signals", "canScanBluetooth": true }, + { + "type": "workstation", + "name": "Crypto Analysis Station", + "takeable": true, + "inInventory": true, + "observations": "A powerful workstation for cryptographic analysis" + }, { "type": "bluetooth_spoofer", "name": "Bluetooth Spoofer", diff --git a/index.html b/index.html index f34a7e8..2b6f6c6 100644 --- a/index.html +++ b/index.html @@ -1535,34 +1535,25 @@ this.load.image('fingerprint_kit', 'assets/objects/fingerprint_kit.png'); this.load.image('lockpick', 'assets/objects/lockpick.png'); - - this.load.json('gameScenarioJSON', 'assets/scenarios/biometric_breach.json'); + //this.load.json('gameScenarioJSON', 'assets/scenarios/biometric_breach.json'); + this.load.json('gameScenarioJSON', 'assets/scenarios/ceo_exfil.json'); gameScenario = this.cache.json.get('gameScenarioJSON'); } // creates the workstation - function addCryptoWorkstation() { - // console.log('CyberChef: Adding crypto workstation...'); - const workstationData = { - type: "workstation", - name: "Crypto Analysis Station", - observations: "A powerful workstation for cryptographic analysis" - }; - + function createCryptoWorkstation(objectData) { // Create the workstation sprite const workstationSprite = this.add.sprite(0, 0, 'workstation'); workstationSprite.setVisible(false); workstationSprite.name = "workstation"; - workstationSprite.scenarioData = workstationData; + workstationSprite.scenarioData = objectData; workstationSprite.setInteractive({ useHandCursor: true }); // Override the default handleObjectInteraction for this specific item workstationSprite.openCryptoWorkstation = function() { - // console.log('CyberChef: Workstation custom interaction triggered'); // Create popup let popup = document.getElementById('laptop-popup'); if (!popup) { - // console.log('CyberChef: Creating new popup...'); popup = document.createElement('div'); popup.id = 'laptop-popup'; popup.innerHTML = ` @@ -1608,9 +1599,7 @@ return true; }; - // Add to inventory directly - addToInventory(workstationSprite); - // console.log('CyberChef: Workstation added to inventory'); + return workstationSprite; } // creates the game @@ -1737,8 +1726,8 @@ // Process items marked with inInventory: true in the scenario data processInitialInventoryItems.call(this); - // Add the workstation to inventory - addCryptoWorkstation.call(this); + // NOTE: Crypto workstation is now handled by processInitialInventoryItems + // based on inInventory flag in scenario data - addCryptoWorkstation.call(this); // Add this line after processAllDoorCollisions() setupDoorOverlapChecks.call(this); @@ -3056,7 +3045,15 @@ debugLog('ADDING INITIAL INVENTORY ITEM', objectData, 2); // Create a sprite for the item - const sprite = createInventorySprite(objectData); + let sprite; + + // Special handling for workstation type + if (objectData.type === "workstation") { + sprite = createCryptoWorkstation.call(this, objectData); + } else { + sprite = createInventorySprite(objectData); + } + if (sprite) { // Add to inventory addToInventory(sprite); From 03cc85685d01db2d4bd647fd695d7683c988fd6c Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 17:02:00 +0000 Subject: [PATCH 07/10] Refactor CryptoWorkstation interaction and remove redundant inventory item --- assets/scenarios/biometric_breach.json | 7 -- index.html | 119 ++++++++++++------------- 2 files changed, 58 insertions(+), 68 deletions(-) diff --git a/assets/scenarios/biometric_breach.json b/assets/scenarios/biometric_breach.json index 2fe3d07..6250131 100644 --- a/assets/scenarios/biometric_breach.json +++ b/assets/scenarios/biometric_breach.json @@ -46,13 +46,6 @@ "takeable": true, "inInventory": true, "observations": "A tool for picking locks" - }, - { - "type": "workstation", - "name": "Crypto Analysis Station", - "takeable": true, - "inInventory": true, - "observations": "A powerful workstation for cryptographic analysis" } ] }, diff --git a/index.html b/index.html index 2b6f6c6..29a1487 100644 --- a/index.html +++ b/index.html @@ -1549,56 +1549,6 @@ workstationSprite.scenarioData = objectData; workstationSprite.setInteractive({ useHandCursor: true }); - // Override the default handleObjectInteraction for this specific item - workstationSprite.openCryptoWorkstation = function() { - // Create popup - let popup = document.getElementById('laptop-popup'); - if (!popup) { - popup = document.createElement('div'); - popup.id = 'laptop-popup'; - popup.innerHTML = ` - -
-
-
- CryptoWorkstation - -
-
-
-
- `; - document.body.appendChild(popup); - - // Find the CyberChef file - fetch('assets/cyberchef/') - .then(response => response.text()) - .then(html => { - // Use regex to find the CyberChef filename - const match = html.match(/CyberChef_v[0-9.]+\.html/); - if (match) { - const cyberchefPath = `assets/cyberchef/${match[0]}`; - // Create and append the iframe with the found path - const iframe = document.createElement('iframe'); - iframe.src = cyberchefPath; - iframe.frameBorder = "0"; - document.getElementById('cyberchef-container').appendChild(iframe); - } else { - console.error('Could not find CyberChef file'); - } - }) - .catch(error => { - console.error('Error loading CyberChef:', error); - }); - - popup.querySelector('.close-btn').addEventListener('click', () => { - popup.style.display = 'none'; - }); - } - popup.style.display = 'flex'; - return true; - }; - return workstationSprite; } @@ -2702,19 +2652,20 @@ // Only log detailed object interactions at debug level 2+ debugLog('OBJECT INTERACTION', { name: sprite.name, - hasWorkstation: !!sprite.openCryptoWorkstation + type: sprite.scenarioData?.type }, 2); - if (sprite.openCryptoWorkstation && sprite.openCryptoWorkstation()) { - debugLog('WORKSTATION OPENED', null, 1); - return; - } - if (!sprite || !sprite.scenarioData) { console.warn('Invalid sprite or missing scenario data'); return; } + // Handle the Crypto Workstation + if (sprite.scenarioData.type === "workstation") { + openCryptoWorkstation(); + return; + } + // Skip range check for inventory items const isInventoryItem = inventory.items.includes(sprite); if (!isInventoryItem) { @@ -2919,11 +2870,6 @@ }; inventorySprite.name = sprite.name; - // Copy over the custom interaction if it exists - if (sprite.openCryptoWorkstation) { - inventorySprite.openCryptoWorkstation = sprite.openCryptoWorkstation; - } - // Set depth higher than container inventorySprite.setDepth(2003); @@ -6459,6 +6405,57 @@ initializeToggleButtons(); }); + // Function to open the crypto workstation + function openCryptoWorkstation() { + debugLog('OPENING CRYPTO WORKSTATION', null, 1); + + // Create popup + let popup = document.getElementById('laptop-popup'); + if (!popup) { + popup = document.createElement('div'); + popup.id = 'laptop-popup'; + popup.innerHTML = ` + +
+
+
+ CryptoWorkstation + +
+
+
+
+ `; + document.body.appendChild(popup); + + // Find the CyberChef file + fetch('assets/cyberchef/') + .then(response => response.text()) + .then(html => { + // Use regex to find the CyberChef filename + const match = html.match(/CyberChef_v[0-9.]+\.html/); + if (match) { + const cyberchefPath = `assets/cyberchef/${match[0]}`; + // Create and append the iframe with the found path + const iframe = document.createElement('iframe'); + iframe.src = cyberchefPath; + iframe.frameBorder = "0"; + document.getElementById('cyberchef-container').appendChild(iframe); + } else { + console.error('Could not find CyberChef file'); + } + }) + .catch(error => { + console.error('Error loading CyberChef:', error); + }); + + popup.querySelector('.close-btn').addEventListener('click', () => { + popup.style.display = 'none'; + }); + } + popup.style.display = 'flex'; + } + \ No newline at end of file From 80f6f82d19ba2c9afb8b78de75a1504c4495c0a4 Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 17:09:43 +0000 Subject: [PATCH 08/10] Improve interaction range logging and update interaction handling method --- index.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 29a1487..803f159 100644 --- a/index.html +++ b/index.html @@ -2675,8 +2675,12 @@ const distanceSq = dx * dx + dy * dy; if (distanceSq > INTERACTION_RANGE_SQ) { - // Show notification instead of alert - //gameAlert("Too far away to interact with this object.", 'warning', '', 2000); + // Player is too far away to interact + debugLog('INTERACTION_OUT_OF_RANGE', { + objectName: sprite.name, + distance: Math.sqrt(distanceSq), + maxRange: Math.sqrt(INTERACTION_RANGE_SQ) + }, 2); return; } } @@ -2883,7 +2887,7 @@ } // Handle other inventory items as before - handleItemInteraction(this, true); + handleObjectInteraction(this); }); inventorySprite.on('pointerover', function() { From cac79c69f9e2001c33024d53f585ef5f3b890f47 Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 17:48:27 +0000 Subject: [PATCH 09/10] Enhance biometric breach scenario with detailed narrative and improved game mechanics --- assets/scenarios/biometric_breach.json | 261 +++++++++++++++++++++---- index.html | 42 +++- 2 files changed, 261 insertions(+), 42 deletions(-) diff --git a/assets/scenarios/biometric_breach.json b/assets/scenarios/biometric_breach.json index 6250131..c99058b 100644 --- a/assets/scenarios/biometric_breach.json +++ b/assets/scenarios/biometric_breach.json @@ -1,11 +1,12 @@ { - "scenario_brief": "You are a security specialist tasked with investigating a high-security research facility after reports of unauthorized access. Your mission is to use biometric tools to identify the intruder and secure sensitive research data before it's stolen.", + "scenario_brief": "You are a security specialist tasked with investigating a high-security research facility after reports of unauthorized access. Your mission is to use biometric tools to identify the intruder, secure sensitive research data, and recover the stolen prototype before it leaves the facility.", + "endGoal": "Recover the stolen Project Sentinel prototype from the intruder's hidden exit route and secure all compromised data.", "startRoom": "reception", "rooms": { "reception": { "type": "room_reception", "connections": { - "north": "lab1" + "north": "office1" }, "objects": [ { @@ -13,7 +14,7 @@ "name": "Reception Phone", "takeable": false, "readable": true, - "text": "Voicemail: 'Security alert: Unauthorized access detected in the biometrics lab. All personnel must verify identity at security checkpoints. Server room PIN changed to 5923. - Security Team'", + "text": "Voicemail: 'Security alert: Unauthorized access detected in the biometrics lab. All personnel must verify identity at security checkpoints. Server room PIN changed to 5923. Security lockdown initiated. - Security Team'", "observations": "The reception phone's message light is blinking with an urgent message" }, { @@ -21,7 +22,7 @@ "name": "Security Log", "takeable": true, "readable": true, - "text": "Unusual access patterns detected:\n- Lab 1: 23:45 PM\n- Biometrics Lab: 01:30 AM\n- Server Room: 02:15 AM", + "text": "Unusual access patterns detected:\n- Lab 1: 23:45 PM\n- Biometrics Lab: 01:30 AM\n- Server Room: 02:15 AM\n- Loading Dock: 03:05 AM\n- Director's Office: 03:22 AM", "observations": "A concerning security log from last night" }, { @@ -46,13 +47,28 @@ "takeable": true, "inInventory": true, "observations": "A tool for picking locks" + }, + { + "type": "workstation", + "name": "Crypto Analysis Station", + "takeable": true, + "inInventory": true, + "observations": "A powerful workstation for cryptographic analysis" + }, + { + "type": "notes", + "name": "Facility Map", + "takeable": true, + "readable": true, + "text": "Facility Layout:\n- Reception (Main Entrance)\n- Main Office (North of Reception)\n- Administrative Office (North of Main Office)\n- Research Wing (North of Main Office)\n- Director's Office (North of Administrative Office)\n- Server Room (North of Research Wing)\n- Storage Closet (North of Director's Office)", + "observations": "A map of the facility showing all major areas" } ] }, - "lab1": { + "office1": { "type": "room_office", "connections": { - "north": ["biolab", "server"], + "north": ["office2", "office3"], "south": "reception" }, "objects": [ @@ -70,7 +86,7 @@ "name": "Research Notes", "takeable": true, "readable": true, - "text": "Project Sentinel: Biometric security breakthrough. Final test results stored in secure server. Access requires Level 3 clearance or backup key.", + "text": "Project Sentinel: Biometric security breakthrough. Final test results stored in secure server. Access requires Level 3 clearance or backup key. The prototype scanner is stored in the Director's office.", "observations": "Important research notes about a biometric security project" }, { @@ -85,24 +101,37 @@ "type": "key", "name": "Biolab Key", "takeable": true, - "key_id": "biolab_key", + "key_id": "ceo_office_key", "observations": "A backup key for the biometrics lab, kept for emergencies" + }, + { + "type": "photo", + "name": "Team Photo", + "takeable": true, + "readable": true, + "text": "Project Sentinel Team:\nDr. Eleanor Chen (Director)\nDr. Marcus Patel (Lead Researcher)\nDr. Wei Zhang (Biometrics Specialist)\nAlex Morgan (Security Consultant)", + "observations": "A framed photo of the Project Sentinel research team" + }, + { + "type": "notes", + "name": "Security Guard Schedule", + "takeable": true, + "readable": true, + "text": "Night Shift (00:00-08:00):\n- John Reynolds: Front Entrance\n- Mark Stevens: Lab Wing (ON LEAVE)\n- Sarah Chen: Server Room\n\nNOTE: Due to staffing shortage, server room checks reduced to hourly instead of every 30 minutes.", + "observations": "The security guard rotation schedule for last night" } ] }, - "biolab": { + "office2": { "type": "room_office", "connections": { - "south": "lab1" + "north": "ceo", + "south": "office1" }, - "locked": true, - "lockType": "key", - "requires": "biolab_key", - "difficulty": "medium", "objects": [ { "type": "pc", - "name": "Biometrics Research Station", + "name": "Biometrics Workstation", "takeable": false, "hasFingerprint": true, "fingerprintOwner": "intruder", @@ -117,38 +146,191 @@ "text": "Unusual access pattern detected: Admin credentials used during off-hours. Timestamp matches security alert. Safe PIN code: 8741", "observations": "A log showing suspicious access to the biometrics lab" }, + { + "type": "notes", + "name": "Fingerprint Comparison Report", + "takeable": true, + "readable": true, + "text": "Fingerprint Analysis:\nRecent unauthorized access shows fingerprints matching consultant Alex Morgan (74% confidence).\n\nNOTE: Further analysis needed for confirmation. Check server room terminal for complete database.", + "observations": "A report analyzing fingerprints found on breached equipment" + } + ] + }, + "office3": { + "type": "room_office", + "connections": { + "north": "server1", + "south": "office1" + }, + "objects": [ { "type": "workstation", "name": "Fingerprint Analysis Station", "takeable": false, "observations": "A specialized workstation for analyzing fingerprint samples" }, + { + "type": "notes", + "name": "Biometric Override Codes", + "takeable": true, + "readable": true, + "text": "Emergency Override Procedure:\n1. Director's Office Biometric Scanner: Code 72958\n2. Loading Dock Security Gate: Code 36714\n\nWARNING: Use only in emergency situations. All uses are logged and reviewed.", + "observations": "A highly sensitive document with emergency override codes" + }, { "type": "key", "name": "Server Room Key", "takeable": true, - "key_id": "server_key", + "key_id": "briefcase_key", "observations": "A key to the server room, carelessly left behind by someone" + }, + { + "type": "notes", + "name": "Maintenance Log", + "takeable": true, + "readable": true, + "text": "03/07 - HVAC repairs completed\n03/08 - Replaced server room cooling unit\n03/09 - Fixed office lighting circuits\n\nNOTE: Need to repair loading dock camera - currently offline due to power fluctuations.", + "observations": "A maintenance log for the facility" } ] }, - "server": { - "type": "room_servers", + "ceo": { + "type": "room_ceo", "connections": { - "south": "lab1" + "north": "closet", + "south": "office2" }, "locked": true, "lockType": "key", - "requires": "server_key", + "requires": "ceo_office_key", "difficulty": "easy", + "objects": [ + { + "type": "pc", + "name": "Director's Computer", + "takeable": false, + "hasFingerprint": true, + "fingerprintOwner": "director", + "fingerprintQuality": 0.95, + "observations": "The director's high-security computer. Multiple fingerprints visible on the keyboard." + }, + { + "type": "phone", + "name": "Director's Phone", + "takeable": false, + "readable": true, + "text": "Last call: Incoming from Security Office at 02:37 AM. Call log shows Security reporting unauthorized access to server room.", + "observations": "The director's phone with call history displayed" + }, + { + "type": "cabinet", + "name": "Secure Cabinet", + "takeable": false, + "locked": true, + "lockType": "key", + "requires": "safe_key", + "difficulty": "medium", + "observations": "A high-security cabinet where the prototype would normally be stored", + "contents": [ + { + "type": "notes", + "name": "Empty Prototype Case", + "takeable": true, + "readable": true, + "text": "PROJECT SENTINEL PROTOTYPE\nProperty of Biometric Research Division\nAUTHORIZED ACCESS ONLY\n\nCase opened at 03:26 AM - SECURITY ALERT TRIGGERED", + "observations": "An empty case that previously held the prototype device", + "important": true + }, + { + "type": "notes", + "name": "Project Investors", + "takeable": true, + "readable": true, + "text": "Project Sentinel Investors:\n- US Department of Defense: $15M\n- Northcrest Security Solutions: $8M\n- Rivera Technologies: $5M\n\nNOTE: Alex Morgan previously worked for Rivera Technologies for 3 years before becoming our consultant. Passed all background checks.", + "observations": "A confidential list of project investors and funding sources" + } + ] + }, + { + "type": "notes", + "name": "Director's Calendar", + "takeable": true, + "readable": true, + "text": "Today:\n9:00 AM - Staff Briefing\n11:00 AM - DOD Representative Visit\n2:00 PM - Demo of Project Sentinel Prototype\n\nNOTE: Ensure prototype is prepared for demonstration. Security consultant Alex Morgan to assist with setup.", + "observations": "The director's schedule for today" + } + ] + }, + "closet": { + "type": "room_closet", + "connections": { + "south": "ceo" + }, + "locked": true, + "lockType": "pin", + "requires": "72958", + "objects": [ + { + "type": "safe", + "name": "Hidden Safe", + "takeable": false, + "locked": true, + "lockType": "pin", + "requires": "8741", + "difficulty": "hard", + "observations": "A well-hidden wall safe behind a painting", + "contents": [ + { + "type": "notes", + "name": "Escape Plan", + "takeable": true, + "readable": true, + "text": "4:00 AM - Meet contact at loading dock\n4:15 AM - Transfer prototype and data\n4:30 AM - Leave separately\n\nBackup plan: If compromised, use maintenance tunnel fire exit. Car parked at south lot.", + "observations": "A detailed escape plan with timing information", + "important": true + }, + { + "type": "key", + "name": "Safe Key", + "takeable": true, + "key_id": "safe_key", + "observations": "A small key with 'Secure Cabinet' written on it" + } + ] + }, + { + "type": "notes", + "name": "Scribbled Note", + "takeable": true, + "readable": true, + "text": "A = Meet at dock, 4AM\nN = Bring everything\nM = Getaway car ready\n\nLH will pay other half when delivered.", + "observations": "A hastily scribbled note, partially crumpled" + }, + { + "type": "fingerprint_kit", + "name": "Advanced Fingerprint Kit", + "takeable": true, + "observations": "A more advanced fingerprint collection kit with higher resolution scanning" + } + ] + }, + "server1": { + "type": "room_servers", + "connections": { + "south": "office3" + }, + "locked": true, + "lockType": "key", + "requires": "briefcase_key", + "difficulty": "medium", "objects": [ { "type": "pc", "name": "Server Terminal", "takeable": false, "hasFingerprint": true, - "fingerprintOwner": "admin", - "fingerprintQuality": 0.95, + "fingerprintOwner": "intruder", + "fingerprintQuality": 0.98, "observations": "The main server terminal controlling access to research data. There are clear fingerprints on the screen." }, { @@ -157,7 +339,7 @@ "takeable": false, "locked": true, "lockType": "pin", - "requires": "8741", + "requires": "5923", "difficulty": "medium", "observations": "A secure safe containing the sensitive research data", "contents": [ @@ -167,14 +349,16 @@ "takeable": true, "readable": true, "text": "Complete research data for Project Sentinel biometric security system. Evidence shows unauthorized copy was made at 02:17 AM by someone using spoofed admin credentials.", - "observations": "The complete research data for the biometric security project" + "observations": "The complete research data for the biometric security project", + "important": true }, { - "type": "key", - "name": "Case Key", + "type": "notes", + "name": "Security Camera Log", "takeable": true, - "key_id": "case_key", - "observations": "A small key with a strange logo etched on it" + "readable": true, + "text": "Camera footage deleted for the following time periods:\n- Loading Dock: 03:00 AM - 03:30 AM\n- Maintenance Tunnel: 03:10 AM - 03:25 AM\n- Director's Office: 03:20 AM - 03:40 AM\n\nSystem shows credentials used: Alex Morgan, Security Consultant", + "observations": "A report of deleted security camera footage" } ] }, @@ -183,18 +367,29 @@ "name": "Suspicious Case", "takeable": false, "locked": true, - "lockType": "key", - "requires": "case_key", + "lockType": "pin", + "requires": "36714", "difficulty": "hard", "observations": "A suspicious case hidden behind server racks", "contents": [ { "type": "notes", - "name": "Stolen Data", + "name": "Project Sentinel Prototype", "takeable": true, "readable": true, - "text": "Copy of Project Sentinel data and instructions for delivery to competitor. Payment confirmation included.", - "observations": "Evidence of corporate espionage and data theft" + "text": "PROJECT SENTINEL BIOMETRIC SCANNER PROTOTYPE\nSERIAL: PS-001-X\nCLASSIFICATION: TOP SECRET\n\nWARNING: Authorized handling only. Technology contains classified components.", + "observations": "The stolen prototype device, ready to be smuggled out", + "important": true, + "isEndGoal": true + }, + { + "type": "notes", + "name": "Buyer Details", + "takeable": true, + "readable": true, + "text": "Buyer: Lazarus Hacking Group\nPayment: $2.5M total, $500K advance paid\nDelivery instructions: Loading dock 4:00 AM, March 10\nContact code name: Nighthawk\n\nDeliverable: Project Sentinel prototype + all research data", + "observations": "Details of the buyer and the transaction", + "important": true } ] } diff --git a/index.html b/index.html index 803f159..29a4200 100644 --- a/index.html +++ b/index.html @@ -1109,11 +1109,19 @@ // Add a note to the notes panel function addNote(title, text, important = false) { // Check if a note with the same title and text already exists - const noteExists = gameNotes.some(note => note.title === title && note.text === text); + const existingNote = gameNotes.find(note => note.title === title && note.text === text); - // If the note already exists, don't add it again - if (noteExists) { - debugLog(`Note "${title}" already exists, not adding duplicate`, 2); + // If the note already exists, don't add it again but mark it as read + if (existingNote) { + debugLog(`Note "${title}" already exists, not adding duplicate`, existingNote, 2); + + // Mark as read if it wasn't already + if (!existingNote.read) { + existingNote.read = true; + updateNotesPanel(); + updateNotesCount(); + } + return null; } @@ -1535,8 +1543,8 @@ this.load.image('fingerprint_kit', 'assets/objects/fingerprint_kit.png'); this.load.image('lockpick', 'assets/objects/lockpick.png'); - //this.load.json('gameScenarioJSON', 'assets/scenarios/biometric_breach.json'); - this.load.json('gameScenarioJSON', 'assets/scenarios/ceo_exfil.json'); + this.load.json('gameScenarioJSON', 'assets/scenarios/biometric_breach.json'); + //this.load.json('gameScenarioJSON', 'assets/scenarios/ceo_exfil.json'); gameScenario = this.cache.json.get('gameScenarioJSON'); } @@ -2766,6 +2774,18 @@ } }, 1000); } + } else { + // If the note was a duplicate and it's a note in the room (not inventory), + // still remove it from the room even though we didn't add it to notes again + if (!isInventoryItem && data.type === 'notes' && currentRoom && + rooms[currentRoom] && rooms[currentRoom].objects && + rooms[currentRoom].objects[sprite.name]) { + + const roomObj = rooms[currentRoom].objects[sprite.name]; + roomObj.setVisible(false); + roomObj.active = false; + debugLog(`Note "${data.name}" was a duplicate, but still removed from room`, 2); + } } } } @@ -2813,6 +2833,9 @@ roomObj.setVisible(false); roomObj.active = false; + // Also set the internal property to indicate it's been collected + sprite.collected = true; + // Show notification about adding to notes instead of inventory gameAlert(`Information recorded in your notes.`, 'success', 'Note Recorded', 3000); } @@ -4654,7 +4677,7 @@ .sort(() => Math.random() - 0.5); const gameState = { - tensionLevel: 1, // Start with light tension instead of none + tensionLevel: 1, // Start with light tension (1) pinStates: Array(numPins).fill(0), // 0 = down, 1 = moving, 2 = set pinPressTime: Array(numPins).fill(0), // Track how long each pin is pressed currentBindingIndex: 0, @@ -4679,7 +4702,7 @@ tensionWrench.style.cssText = ` width: 100px; height: 30px; - background: ${gameState.tensionLevel === 1 ? '#666' : gameState.tensionLevel === 2 ? '#888' : '#aaa'}; + background: #666; border: 2px solid #888; border-radius: 5px; cursor: pointer; @@ -4687,8 +4710,9 @@ text-align: center; line-height: 30px; color: white; + transform: rotate(2deg); `; - tensionWrench.textContent = 'Tension: OFF'; + tensionWrench.textContent = 'Tension: LIGHT'; // Function to reset pins function resetPins(showVisual = true) { From c68130cc03374d1e1fc0cd32f0256ba6d36cc48e Mon Sep 17 00:00:00 2001 From: Damian-I Date: Sun, 9 Mar 2025 18:09:53 +0000 Subject: [PATCH 10/10] Add biometric authentication mechanism for locks and safes --- assets/scenarios/biometric_breach.json | 20 ++++---- index.html | 65 ++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 14 deletions(-) diff --git a/assets/scenarios/biometric_breach.json b/assets/scenarios/biometric_breach.json index c99058b..306d757 100644 --- a/assets/scenarios/biometric_breach.json +++ b/assets/scenarios/biometric_breach.json @@ -203,7 +203,7 @@ "locked": true, "lockType": "key", "requires": "ceo_office_key", - "difficulty": "easy", + "difficulty": "medium", "objects": [ { "type": "pc", @@ -275,10 +275,10 @@ "name": "Hidden Safe", "takeable": false, "locked": true, - "lockType": "pin", - "requires": "8741", + "lockType": "biometric", + "requires": "intruder", "difficulty": "hard", - "observations": "A well-hidden wall safe behind a painting", + "observations": "A well-hidden wall safe behind a painting with a fingerprint scanner", "contents": [ { "type": "notes", @@ -338,10 +338,10 @@ "name": "Secure Data Safe", "takeable": false, "locked": true, - "lockType": "pin", - "requires": "5923", + "lockType": "biometric", + "requires": "intruder", "difficulty": "medium", - "observations": "A secure safe containing the sensitive research data", + "observations": "A secure safe with a fingerprint scanner containing the sensitive research data", "contents": [ { "type": "notes", @@ -367,10 +367,10 @@ "name": "Suspicious Case", "takeable": false, "locked": true, - "lockType": "pin", - "requires": "36714", + "lockType": "biometric", + "requires": "intruder", "difficulty": "hard", - "observations": "A suspicious case hidden behind server racks", + "observations": "A suspicious case hidden behind server racks with a fingerprint scanner", "contents": [ { "type": "notes", diff --git a/index.html b/index.html index 29a4200..2d8e836 100644 --- a/index.html +++ b/index.html @@ -3237,6 +3237,9 @@ } // Get lock requirements based on type + // lockRequirements should contain: + // - lockType: 'key', 'pin', 'password', 'bluetooth', or 'biometric' + // - requires: Key ID, PIN code, password, MAC address, or fingerprint owner name const lockRequirements = type === 'door' ? getLockRequirementsForDoor(lockable) : getLockRequirementsForItem(lockable); @@ -3328,6 +3331,60 @@ } break; + case 'biometric': + debugLog('BIOMETRIC AUTHENTICATION REQUESTED', null, 2); + // Check if player has fingerprint kit + const hasFingerPrintKit = inventory.items.some(item => + item && item.scenarioData && + item.scenarioData.type === 'fingerprint_kit' + ); + + if (!hasFingerPrintKit) { + gameAlert("You need a fingerprint kit to use biometric scanners.", 'warning', 'Missing Equipment', 4000); + return; + } + + // Check if player has required fingerprint sample + const requiredFingerprint = lockRequirements.requires; + debugLog('FINGERPRINT REQUIRED', requiredFingerprint, 2); + + // Check if player has a valid fingerprint sample + const validSample = gameState.biometricSamples.find(sample => + sample.type === 'fingerprint' && + sample.owner === requiredFingerprint && + sample.quality >= 0.7 // Quality threshold + ); + + if (validSample) { + debugLog('BIOMETRIC UNLOCK SUCCESS', validSample, 1); + unlockTarget(lockable, type, lockable.layer); + gameAlert(`You successfully used ${validSample.owner}'s fingerprint to unlock the ${type}.`, + 'success', 'Biometric Authentication Successful', 5000); + + // Play success sound and visual effect + const successEffect = lockable.scene ? lockable.scene.add.circle( + lockable.x, + lockable.y, + 32, + 0x00ff00, + 0.5 + ) : null; + + if (successEffect) { + lockable.scene.tweens.add({ + targets: successEffect, + alpha: 0, + scale: 2, + duration: 1000, + onComplete: () => successEffect.destroy() + }); + } + } else { + debugLog('BIOMETRIC UNLOCK FAILED', null, 2); + gameAlert(`You don't have the required fingerprint sample.`, 'error', 'Biometric Authentication Failed', 4000); + } + break; + case 'bluetooth': if (lockable.scenarioData?.locked) { // Try to spoof the Bluetooth device @@ -3544,8 +3601,8 @@ if (lockedRooms.length > 0) { const targetRoom = lockedRooms[0]; const requirements = { - lockType: targetRoom.lockType, - requires: targetRoom.requires + lockType: targetRoom.lockType, // Can be: 'key', 'pin', 'password', 'bluetooth', or 'biometric' + requires: targetRoom.requires // Key ID, PIN code, password, BT MAC address, or fingerprint owner name }; debugLog('LOCK REQUIREMENTS', requirements, 2); return requirements; @@ -3557,8 +3614,8 @@ function getLockRequirementsForItem(item) { return { - lockType: item.lockType || item.scenarioData?.lockType, - requires: item.requires || item.scenarioData?.requires, + lockType: item.lockType || item.scenarioData?.lockType, // Can be: 'key', 'pin', 'password', 'bluetooth', or 'biometric' + requires: item.requires || item.scenarioData?.requires, // Key ID, PIN code, password, BT MAC address, or fingerprint owner name isUnlockedButNotCollected: false }; }