From 8fe71efa89cec51a6603805f3bc8a24568473f9d Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Tue, 21 Oct 2025 12:17:28 +0100 Subject: [PATCH] Implement Notebook Functionality: Add a notebook button to the Password and Container minigames for saving post-it notes. Enhance inventory interactions with pulse animations instead of notifications for item collection. Update CSS for new animations and layout adjustments in various minigames to improve user experience. --- css/inventory.css | 20 ++++ css/notes.css | 1 + css/password-minigame.css | 15 +-- js/minigames/container/container-minigame.js | 89 +++++++++++++++++ js/minigames/notes/notes-minigame.js | 4 - js/minigames/password/password-minigame.js | 99 ++++++++++++++++++- js/minigames/phone/phone-messages-minigame.js | 4 +- js/minigames/text-file/text-file-minigame.js | 4 +- js/systems/interactions.js | 2 +- js/systems/inventory.js | 20 ++-- 10 files changed, 231 insertions(+), 27 deletions(-) diff --git a/css/inventory.css b/css/inventory.css index 3e463ab..7ce7985 100644 --- a/css/inventory.css +++ b/css/inventory.css @@ -38,6 +38,26 @@ background: rgb(149 157 216 / 80%); } +/* Pulse animation for newly added items */ +@keyframes pulse-slot { + 0% { + transform: scale(1); + box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7); + } + 50% { + transform: scale(1.5); + box-shadow: 0 0 0 10px rgba(255, 255, 255, 0); + } + 100% { + transform: scale(1); + box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); + } +} + +.inventory-slot.pulse { + animation: pulse-slot 0.6s ease-out; +} + .inventory-item { max-width: 48px; max-height: 48px; diff --git a/css/notes.css b/css/notes.css index b6962db..03f0712 100644 --- a/css/notes.css +++ b/css/notes.css @@ -77,6 +77,7 @@ margin: 0; overflow: auto; /* Allow scrolling if content is too long */ box-sizing: border-box; + height: 90%; /* so that it scolls before the bottom of the image */ } /* Text box container */ diff --git a/css/password-minigame.css b/css/password-minigame.css index cfd7c48..d19a856 100644 --- a/css/password-minigame.css +++ b/css/password-minigame.css @@ -180,11 +180,7 @@ background: rgba(0, 255, 0, 0.1); } -.icon-small { - width: 20px; - height: 20px; - object-fit: contain; -} + .icon-keyboard { width: 40px; @@ -226,6 +222,13 @@ transform: scale(0.95); } +.hint-controls { + display: flex; + gap: 10px; + align-items: center; + margin-bottom: 10px; +} + .password-hint-container { display: flex; flex-direction: column; @@ -236,7 +239,7 @@ background: #f39c12; color: white; border: none; - padding: 8px 16px; + padding: 12px 24px; /* border-radius: 5px; */ cursor: pointer; font-size: 18px; diff --git a/js/minigames/container/container-minigame.js b/js/minigames/container/container-minigame.js index 9fcd877..94e5e93 100644 --- a/js/minigames/container/container-minigame.js +++ b/js/minigames/container/container-minigame.js @@ -43,6 +43,15 @@ export class ContainerMinigame extends MinigameScene { `; } + // Add notebook button to minigame controls if postit note exists + if (this.controlsElement && this.containerItem.scenarioData.postitNote && this.containerItem.scenarioData.showPostit) { + const notebookBtn = document.createElement('button'); + notebookBtn.className = 'minigame-button'; + notebookBtn.id = 'minigame-notebook-postit'; + notebookBtn.innerHTML = 'Notebook Add to Notebook'; + this.controlsElement.appendChild(notebookBtn); + } + // Create the container minigame UI this.createContainerUI(); } @@ -235,6 +244,12 @@ export class ContainerMinigame extends MinigameScene { if (closeBtn) { this.addEventListener(closeBtn, 'click', () => this.complete(false)); } + + // Add to Notebook button + const addToNotebookBtn = document.getElementById('minigame-notebook-postit'); + if (addToNotebookBtn) { + this.addEventListener(addToNotebookBtn, 'click', () => this.addPostitToNotebook()); + } } isInteractiveItem(item) { @@ -396,6 +411,80 @@ export class ContainerMinigame extends MinigameScene { window.gameAlert('Crypto workstation not available', 'error', 'Error', 3000); } } + + addPostitToNotebook() { + console.log('Adding postit note to notebook:', this.containerItem.scenarioData.postitNote); + + const postitNote = this.containerItem.scenarioData.postitNote; + if (!postitNote || postitNote.trim() === '') { + this.showMessage('No postit note to add.', 'error'); + return; + } + + // Create comprehensive notebook content + const notebookTitle = `Postit Note - ${this.containerItem.scenarioData.name}`; + let notebookContent = `Postit Note:\n${'-'.repeat(50)}\n\n${postitNote}`; + + // Add container contents list + notebookContent += `\n\n${'='.repeat(20)}\n`; + notebookContent += `CONTAINER CONTENTS: ${this.containerItem.scenarioData.name}\n`; + notebookContent += `${'='.repeat(20)}\n`; + + if (this.contents && this.contents.length > 0) { + this.contents.forEach((item, index) => { + notebookContent += `${index + 1}. ${item.name || item.type}`; + if (item.description) { + notebookContent += ` - ${item.description}`; + } + notebookContent += '\n'; + }); + } else { + notebookContent += 'No items found\n'; + } + + notebookContent += `${'='.repeat(20)}\n`; + notebookContent += `Date: ${new Date().toLocaleString()}`; + + const notebookObservations = `Postit note found in ${this.containerItem.scenarioData.name}.`; + + // Check if notes minigame is available + if (window.startNotesMinigame) { + // Store the container state globally so we can return to it + const containerState = { + containerItem: this.containerItem, + contents: this.contents, + isTakeable: this.isTakeable + }; + + window.pendingContainerReturn = containerState; + + // Create a postit item for the notes minigame + const postitItem = { + scenarioData: { + type: 'postit_note', + name: notebookTitle, + text: notebookContent, + observations: notebookObservations, + important: true + } + }; + + // Start notes minigame + window.startNotesMinigame( + postitItem, + notebookContent, + notebookObservations, + null, + false, + false + ); + + this.showMessage("Added postit note to notebook", 'success'); + } else { + console.error('Notes minigame not available'); + this.showMessage('Notebook not available', 'error'); + } + } takeItem(item, itemElement) { console.log('Taking item from container:', item); diff --git a/js/minigames/notes/notes-minigame.js b/js/minigames/notes/notes-minigame.js index 85b3288..d460635 100644 --- a/js/minigames/notes/notes-minigame.js +++ b/js/minigames/notes/notes-minigame.js @@ -799,10 +799,6 @@ window.addNote = function(title, text, important = false) { window.gameState.notes.push(note); - // Show notification for new note - if (window.showNotification) { - window.showNotification(`New note added: ${title}`, 'info', 'Note Added', 3000); - } return note; }; diff --git a/js/minigames/password/password-minigame.js b/js/minigames/password/password-minigame.js index 70b10b1..873ed89 100644 --- a/js/minigames/password/password-minigame.js +++ b/js/minigames/password/password-minigame.js @@ -36,6 +36,15 @@ export class PasswordMinigame extends MinigameScene { // Set up the password interface this.setupPasswordInterface(); + // Add notebook button to minigame controls if postit note exists (before cancel button) + if (this.controlsElement && this.gameData.showPostit && this.gameData.postitNote) { + const notebookBtn = document.createElement('button'); + notebookBtn.className = 'minigame-button'; + notebookBtn.id = 'minigame-notebook-postit'; + notebookBtn.innerHTML = 'Notebook Add to Notebook'; + this.controlsElement.appendChild(notebookBtn); + } + // Set up event listeners this.setupEventListeners(); } @@ -61,8 +70,11 @@ export class PasswordMinigame extends MinigameScene { ${this.gameData.showHint ? ` -
+
+ +
+
@@ -78,12 +90,9 @@ export class PasswordMinigame extends MinigameScene { ` : ''}
- ${this.gameData.showHint ? ` - - ` : ''} ${this.gameData.showKeyboard ? ` ` : ''}
@@ -211,6 +220,14 @@ export class PasswordMinigame extends MinigameScene { this.handleKeyboardClick(event); }); } + + // Notebook button for postit (in minigame controls) + const notebookBtn = document.getElementById('minigame-notebook-postit'); + if (notebookBtn) { + this.addEventListener(notebookBtn, 'click', () => { + this.addPostitToNotebook(); + }); + } } start() { @@ -385,6 +402,78 @@ export class PasswordMinigame extends MinigameScene { }; } + addPostitToNotebook() { + if (!this.gameState.isActive) return; + + const postitNote = this.gameData.postitNote; + if (!postitNote || postitNote.trim() === '') { + this.showFailure("No postit note to add.", false, 2000); + return; + } + + // Get the device name from available sources + const deviceName = this.params.deviceName || + this.params.scenarioData?.name || + this.params.title || + 'Unknown Device'; + + // Create comprehensive notebook content + const notebookTitle = `Postit Note - ${deviceName}`; + let notebookContent = `Postit Note:\n${'-'.repeat(20)}\n\n${postitNote}`; + notebookContent += `\n\n${'='.repeat(20)}\n`; + notebookContent += `PASSWORD PROTECTED: ${deviceName}\n`; + notebookContent += `${'='.repeat(20)}\n`; + notebookContent += `Date: ${new Date().toLocaleString()}`; + + const notebookObservations = 'Postit note found during password entry.'; + + // Check if notes minigame is available + if (window.startNotesMinigame) { + // Store the password state globally so we can return to it + const passwordState = { + password: this.gameData.password, + passwordHint: this.gameData.passwordHint, + showHint: this.gameData.showHint, + showKeyboard: this.gameData.showKeyboard, + maxAttempts: this.gameData.maxAttempts, + attempts: this.gameData.attempts, + showPassword: this.gameData.showPassword, + postitNote: this.gameData.postitNote, + showPostit: this.gameData.showPostit, + capsLock: this.gameData.capsLock, + keyboardVisible: this.gameData.keyboardVisible, + params: this.params + }; + + window.pendingPasswordReturn = passwordState; + + // Create a postit item for the notes minigame + const postitItem = { + scenarioData: { + type: 'postit_note', + name: notebookTitle, + text: notebookContent, + observations: notebookObservations, + important: true + } + }; + + // Start notes minigame + window.startNotesMinigame( + postitItem, + notebookContent, + notebookObservations, + null, + false, + false + ); + + this.showSuccess("Added postit note to notebook", false, 2000); + } else { + this.showFailure("Notebook not available", false, 2000); + } + } + cleanup() { // Call parent cleanup (handles event listeners) super.cleanup(); diff --git a/js/minigames/phone/phone-messages-minigame.js b/js/minigames/phone/phone-messages-minigame.js index 4a397fa..3a5311e 100644 --- a/js/minigames/phone/phone-messages-minigame.js +++ b/js/minigames/phone/phone-messages-minigame.js @@ -776,7 +776,7 @@ export class PhoneMessagesMinigame extends MinigameScene { content += `Source: ${this.params?.title || 'Phone'}\n`; content += `Total Messages: ${this.phoneData.messages.length}\n`; content += `Date: ${new Date().toLocaleString()}\n\n`; - content += `${'='.repeat(50)}\n\n`; + content += `${'='.repeat(20)}\n\n`; this.phoneData.messages.forEach((message, index) => { content += `Message ${index + 1}:\n`; @@ -796,7 +796,7 @@ export class PhoneMessagesMinigame extends MinigameScene { } }); - content += `${'='.repeat(50)}\n`; + content += `${'='.repeat(20)}\n`; content += `End of Phone Messages Log`; return content; diff --git a/js/minigames/text-file/text-file-minigame.js b/js/minigames/text-file/text-file-minigame.js index e07a81f..01a4c61 100644 --- a/js/minigames/text-file/text-file-minigame.js +++ b/js/minigames/text-file/text-file-minigame.js @@ -340,11 +340,11 @@ export class TextFileMinigame extends MinigameScene { content += `Source: ${this.textFileData.source}\n`; content += `Type: ${this.textFileData.fileType.toUpperCase()}\n`; content += `Date: ${new Date().toLocaleString()}\n\n`; - content += `${'='.repeat(50)}\n\n`; + content += `${'='.repeat(20)}\n\n`; content += `FILE CONTENTS:\n`; content += `${'-'.repeat(20)}\n\n`; content += this.textFileData.fileContent; - content += `\n\n${'='.repeat(50)}\n`; + content += `\n\n${'='.repeat(20)}\n`; content += `End of File: ${this.textFileData.fileName}`; return content; diff --git a/js/systems/interactions.js b/js/systems/interactions.js index ea50632..7c77ded 100644 --- a/js/systems/interactions.js +++ b/js/systems/interactions.js @@ -375,7 +375,7 @@ export function handleObjectInteraction(sprite) { } // Show notification - window.gameAlert(message, 'info', data.name, 0); + window.gameAlert(message, 'info', data.name, 5000); } // Handle container item interactions diff --git a/js/systems/inventory.js b/js/systems/inventory.js index 389df98..bf1321e 100644 --- a/js/systems/inventory.js +++ b/js/systems/inventory.js @@ -170,10 +170,12 @@ export function addToInventory(sprite) { // Add to inventory array window.inventory.items.push(itemImg); - // Show notification - if (window.gameAlert) { - window.gameAlert(`Added ${sprite.scenarioData.name} to inventory`, 'success', 'Item Collected', 3000); - } + // Apply pulse animation to the slot instead of showing notification + slot.classList.add('pulse'); + // Remove the pulse class after the animation completes + setTimeout(() => { + slot.classList.remove('pulse'); + }, 600); // If this is the Bluetooth scanner, automatically open the minigame after adding to inventory if (sprite.scenarioData.type === "bluetooth_scanner" && window.startBluetoothScannerMinigame) { @@ -234,9 +236,13 @@ function addKeyToInventory(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); + // Apply pulse animation to the key ring slot instead of showing notification + const keyRingSlot = window.inventory.keyRing.slot; + if (keyRingSlot) { + keyRingSlot.classList.add('pulse'); + setTimeout(() => { + keyRingSlot.classList.remove('pulse'); + }, 600); } return true;