From 38c2a0476fb20564308d6adf5cbbc652461ceca8 Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Tue, 12 Aug 2025 16:37:41 +0100 Subject: [PATCH] Remove legacy lockpicking minigame files: Deleted lockpicking-comparison.html and lockpicking-game.js, along with associated CSS styles in lockpicking.css. Updated minigames index to only include the Phaser version of the lockpicking minigame, ensuring a cleaner codebase and improved maintainability. Added new lockpick feedback styling in minigames-framework.css for enhanced user experience. --- css/lockpicking.css | 515 ------------------ css/minigames-framework.css | 32 +- js/minigames/index.js | 3 - .../lockpicking/lockpicking-game-phaser.js | 15 +- js/minigames/lockpicking/lockpicking-game.js | 278 ---------- lockpicking-comparison.html | 228 -------- 6 files changed, 34 insertions(+), 1037 deletions(-) delete mode 100644 css/lockpicking.css delete mode 100644 js/minigames/lockpicking/lockpicking-game.js delete mode 100644 lockpicking-comparison.html diff --git a/css/lockpicking.css b/css/lockpicking.css deleted file mode 100644 index 8ee623f..0000000 --- a/css/lockpicking.css +++ /dev/null @@ -1,515 +0,0 @@ -/* Lockpicking Minigame Styles */ - -/* Override header positioning for lockpicking */ -.minigame-header { - position: relative !important; - background: rgba(34, 34, 34, 0.95); - padding: 10px 20px; - margin-bottom: 20px; - border-radius: 5px; -} - -.minigame-header h3 { - font-family: 'Press Start 2P', monospace; - font-size: 16px; - margin: 0 0 10px 0; -} - -.minigame-header p { - font-family: 'VT323', monospace; - font-size: 18px; - margin: 0; -} - -.lock-visual { - display: flex; - justify-content: space-evenly; - align-items: center; - gap: 20px; - height: 300px; /* Taller for better visibility */ - background: #f0e6a6; /* Light yellow/beige background */ - border-radius: 5px; - padding: 25px; - position: relative; - margin: 20px auto; /* Center and add margins */ - border: 2px solid #887722; - max-width: 800px; /* Reasonable maximum width */ - width: 90%; /* Responsive width */ -} - -.pin { - width: 40px; - height: 200px; /* Taller to match container */ - position: relative; - background: transparent; - border-radius: 4px 4px 0 0; - overflow: visible; - cursor: pointer; - transition: transform 0.1s; - margin: 0 15px; -} - -.pin:hover { - opacity: 0.9; -} - -.shear-line { - position: absolute; - width: 100%; - height: 2px; - background: #aa8833; - bottom: 60px; /* Match driver pin starting position */ - z-index: 5; -} - -.key-pin { - position: absolute; - bottom: 0; - width: 100%; - height: 0px; /* Start at 0px, grows dynamically via JavaScript */ - background: #dd3333; /* Red for key pins */ - border-radius: 0 0 0 0; - clip-path: polygon(0 0, 100% 0, 100% 70%, 50% 100%, 0 70%); /* Pointed bottom */ - transition: height 0.1s ease; /* Smooth height animation */ -} - -.driver-pin { - position: absolute; - width: 100%; - height: 40px; /* Smaller height for better proportion */ - background: #3388dd; /* Blue for driver pins */ - bottom: 60px; /* Start at shear line level */ - border-radius: 4px 4px 0 0; - transition: bottom 0.1s ease, background-color 0.3s; -} - -.spring { - position: absolute; - bottom: 100px; /* Positioned above driver pin */ - width: 100%; - height: 30px; - background: repeating-linear-gradient( - to bottom, - #cccccc 0px, - #cccccc 2px, - #999999 2px, - #999999 4px - ); - transition: transform 0.1s ease; -} - -.pin.binding { - box-shadow: 0 0 8px 2px #ffcc00; -} - -/* Keep driver pin (blue) above the shear line when set */ -.pin.set .driver-pin { - background: #22aa22; /* Green to indicate set */ -} - -/* Key pin turns green when set */ -.pin.set .key-pin { - background: #22aa22; /* Green to indicate set */ -} - -.cylinder { - display: flex; - justify-content: center; - align-items: center; - width: 100%; - height: 30px; - background: #ddbb77; - border-radius: 5px; - margin-top: 5px; - position: relative; - z-index: 0; - border: 2px solid #887722; -} - -.cylinder-inner { - width: 80%; - height: 20px; - background: #ccaa66; - border-radius: 3px; - transform-origin: center; - transition: transform 0.3s; -} - -.cylinder.rotated .cylinder-inner { - transform: rotate(15deg); -} - -.lockpick-feedback { - padding: 15px; - background: #333; - border-radius: 5px; - text-align: center; - min-height: 30px; - margin-top: 20px; - font-family: 'VT323', monospace; - font-size: 18px; -} - -.tension-control { - display: grid; - grid-template-columns: auto 1fr; - gap: 20px; - align-items: center; - background: #333; - padding: 20px; - border-radius: 5px; - margin-top: 20px; -} - -.tension-wrench-container { - display: flex; - flex-direction: column; - align-items: center; - gap: 10px; - position: relative; - width: 150px; - height: 60px; -} - -.tension-track { - width: 100%; - height: 10px; - background: #444; - border-radius: 5px; - position: relative; - overflow: hidden; -} - -.tension-progress { - position: absolute; - height: 100%; - width: 0%; - background: linear-gradient(to right, #666, #2196F3); - transition: width 0.3s; -} - -.tension-status { - font-size: 16px; - text-align: left; - padding-left: 10px; -} - -.tension-wrench { - width: 60px; - height: 40px; - background: #666; - border-radius: 4px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: transform 0.3s, background-color 0.3s; - position: absolute; - left: 0; - top: 20px; - z-index: 2; - box-shadow: 0 2px 5px rgba(0,0,0,0.3); -} - -.tension-wrench:hover { - background: #777; -} - -.tension-wrench.active { - background: #2196F3; -} - -.wrench-handle { - width: 60%; - height: 10px; - background: #999; - position: absolute; -} - -.wrench-tip { - width: 20px; - height: 30px; - background: #999; - position: absolute; - left: 5px; -} - -.instructions { - text-align: center; - margin-bottom: 10px; - font-size: 12px; - color: #ccc; -} - - -/* General success/failure message styles */ -.lockpicking-success-message { - font-weight: bold; - font-size: 18px; - margin-bottom: 10px; - color: #2ecc71; -} - -.lockpicking-success-subtitle { - font-size: 14px; - margin-bottom: 15px; - color: #fff; -} - -.lockpicking-success-details { - font-size: 12px; - color: #aaa; -} - -.lockpicking-failure-message { - font-weight: bold; - margin-bottom: 10px; - color: #e74c3c; -} - -.lockpicking-failure-subtitle { - font-size: 16px; - margin-top: 5px; - color: #fff; -} - - -.tension-control { - display: grid; - grid-template-columns: auto 1fr; - gap: 20px; - align-items: center; - background: #333; - padding: 20px; - border-radius: 5px; - margin-top: 20px; -} - -.tension-wrench-container { - display: flex; - flex-direction: column; - align-items: center; - gap: 10px; - position: relative; - width: 150px; - height: 60px; -} - -.tension-track { - width: 100%; - height: 10px; - background: #444; - border-radius: 5px; - position: relative; - overflow: hidden; -} - -.tension-progress { - position: absolute; - height: 100%; - width: 0%; - background: linear-gradient(to right, #666, #2196F3); - transition: width 0.3s; - } - -.tension-status { - font-size: 16px; - text-align: left; - padding-left: 10px; - } - - .tension-wrench { - width: 60px; - height: 40px; - background: #666; - border-radius: 4px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: transform 0.3s, background-color 0.3s; - position: absolute; - left: 0; - top: 20px; - z-index: 2; - box-shadow: 0 2px 5px rgba(0,0,0,0.3); -} - -.tension-wrench:hover { - background: #777; -} - -.tension-wrench.active { - background: #2196F3; -} - -.wrench-handle { - width: 60%; - height: 10px; - background: #999; - position: absolute; -} - -.wrench-tip { - width: 20px; - height: 30px; - background: #999; - position: absolute; - left: 5px; -} - -.cylinder { - height: 20px; - margin-top: -5px; -} - -.lock-visual { - display: flex; - justify-content: space-evenly; - align-items: center; - gap: 10px; - height: 160px; - background: #f0e6a6; /* Light yellow/beige background */ - border-radius: 5px; - padding: 15px; - position: relative; - margin-bottom: 10px; - border: 2px solid #887722; -} - -.pin { - width: 30px; - height: 110px; - position: relative; - background: transparent; - border-radius: 4px 4px 0 0; - overflow: visible; - cursor: pointer; - transition: transform 0.1s; - margin: 0 5px; -} - -.pin:hover { - opacity: 0.9; -} - -.shear-line { - position: absolute; - width: 100%; - height: 2px; - background: #aa8833; - bottom: 50px; - z-index: 5; -} - -.key-pin { - position: absolute; - bottom: 0; - width: 100%; - height: 0px; - background: #dd3333; /* Red for key pins */ - transition: height 0.05s; - border-radius: 0 0 0 0; - clip-path: polygon(0 0, 100% 0, 100% 70%, 50% 100%, 0 70%); /* Pointed bottom */ -} - -.driver-pin { - position: absolute; - width: 100%; - height: 50px; - background: #3388dd; /* Blue for driver pins */ - transition: bottom 0.05s; - bottom: 50px; - border-radius: 0 0 0 0; -} - -.spring { - position: absolute; - bottom: 100px; - width: 100%; - height: 25px; - background: linear-gradient(to bottom, - #cccccc 0%, #cccccc 20%, - #999999 20%, #999999 25%, - #cccccc 25%, #cccccc 40%, - #999999 40%, #999999 45%, - #cccccc 45%, #cccccc 60%, - #999999 60%, #999999 65%, - #cccccc 65%, #cccccc 80%, - #999999 80%, #999999 85%, - #cccccc 85%, #cccccc 100% - ); - transition: height 0.05s; -} - -.pin.binding { - box-shadow: 0 0 8px 2px #ffcc00; -} - -.pin.set .driver-pin { - bottom: 52px; /* Just above shear line */ - background: #22aa22; /* Green to indicate set */ -} - -.pin.set .key-pin { - height: 49px; /* Just below shear line */ - background: #22aa22; /* Green to indicate set */ - clip-path: polygon(0 0, 100% 0, 100% 70%, 50% 100%, 0 70%); -} - -.cylinder { - display: flex; - justify-content: center; - align-items: center; - width: 100%; - height: 30px; - background: #ddbb77; - border-radius: 5px; - margin-top: 5px; - position: relative; - z-index: 0; - border: 2px solid #887722; -} - -.cylinder-inner { - width: 80%; - height: 20px; - background: #ccaa66; - border-radius: 3px; - transform-origin: center; - transition: transform 0.3s; -} - -.cylinder.rotated .cylinder-inner { - transform: rotate(15deg); -} - -.lockpick-feedback { - padding: 15px; - background: #333; - border-radius: 5px; - text-align: center; - min-height: 30px; - margin-top: 20px; - font-family: 'VT323', monospace; - font-size: 18px; -} - -/* Phaser-specific styles */ -.phaser-game-container { - width: 100%; - height: 400px; - background: #1a1a1a; - border-radius: 5px; - margin: 20px 0; - display: flex; - justify-content: center; - align-items: center; - border: 2px solid #444; -} - -.phaser-game-container canvas { - border-radius: 5px; - max-width: 100%; - max-height: 100%; -} \ No newline at end of file diff --git a/css/minigames-framework.css b/css/minigames-framework.css index d8516ab..400b7f1 100644 --- a/css/minigames-framework.css +++ b/css/minigames-framework.css @@ -42,13 +42,13 @@ .minigame-game-container { width: 80%; max-width: 600px; - height: 60%; + height: 55%; margin: 20px auto; background: #1a1a1a; border-radius: 5px; box-shadow: 0 0 15px rgba(0, 0, 0, 0.5) inset; position: relative; - overflow: hidden; + overflow: visible; } .minigame-message-container { @@ -192,3 +192,31 @@ transition: width 0.3s ease; border-radius: 5px; } + +/* Lockpicking feedback styling */ +.lockpick-feedback { + background: rgba(0, 0, 0, 0.8); + color: #00ff00; + padding: 10px 15px; + border-radius: 5px; + margin: 10px 0; + font-family: 'VT323', monospace; + font-size: 16px; + text-align: center; + border: 1px solid #00ff00; + min-height: 20px; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 0 10px rgba(0, 255, 0, 0.3); + position: relative; + z-index: 1000; + width: 100%; + max-width: 600px; + margin-left: auto; + margin-right: auto; +} + +.lockpick-feedback:empty { + display: none; +} diff --git a/js/minigames/index.js b/js/minigames/index.js index 5352b5f..c795e85 100644 --- a/js/minigames/index.js +++ b/js/minigames/index.js @@ -3,13 +3,11 @@ export { MinigameFramework } from './framework/minigame-manager.js'; export { MinigameScene } from './framework/base-minigame.js'; // Export minigame implementations -export { LockpickingMinigame } from './lockpicking/lockpicking-game.js'; export { LockpickingMinigamePhaser } from './lockpicking/lockpicking-game-phaser.js'; export { DustingMinigame } from './dusting/dusting-game.js'; // Initialize the global minigame framework for backward compatibility import { MinigameFramework } from './framework/minigame-manager.js'; -import { LockpickingMinigame } from './lockpicking/lockpicking-game.js'; import { LockpickingMinigamePhaser } from './lockpicking/lockpicking-game-phaser.js'; // Make the framework available globally @@ -20,6 +18,5 @@ import { DustingMinigame } from './dusting/dusting-game.js'; // Register minigames MinigameFramework.registerScene('lockpicking', LockpickingMinigamePhaser); // Use Phaser version as default -MinigameFramework.registerScene('lockpicking-legacy', LockpickingMinigame); // Keep old version for backward compatibility MinigameFramework.registerScene('lockpicking-phaser', LockpickingMinigamePhaser); // Keep explicit phaser name MinigameFramework.registerScene('dusting', DustingMinigame); \ No newline at end of file diff --git a/js/minigames/lockpicking/lockpicking-game-phaser.js b/js/minigames/lockpicking/lockpicking-game-phaser.js index 3cf0f4b..55f85a0 100644 --- a/js/minigames/lockpicking/lockpicking-game-phaser.js +++ b/js/minigames/lockpicking/lockpicking-game-phaser.js @@ -1,14 +1,5 @@ import { MinigameScene } from '../framework/base-minigame.js'; -// Load lockpicking-specific CSS -const lockpickingCSS = document.createElement('link'); -lockpickingCSS.rel = 'stylesheet'; -lockpickingCSS.href = 'css/lockpicking.css'; -lockpickingCSS.id = 'lockpicking-css'; -if (!document.getElementById('lockpicking-css')) { - document.head.appendChild(lockpickingCSS); -} - // Phaser Lockpicking Minigame Scene implementation export class LockpickingMinigamePhaser extends MinigameScene { constructor(container, params) { @@ -130,10 +121,12 @@ export class LockpickingMinigamePhaser extends MinigameScene { // Create a container for the Phaser game this.gameContainer.innerHTML = `
-
`; - this.feedback = this.gameContainer.querySelector('.lockpick-feedback'); + // Create feedback element in the minigame container + this.feedback = document.createElement('div'); + this.feedback.className = 'lockpick-feedback'; + this.gameContainer.appendChild(this.feedback); console.log('Setting up Phaser game...'); diff --git a/js/minigames/lockpicking/lockpicking-game.js b/js/minigames/lockpicking/lockpicking-game.js deleted file mode 100644 index c863ef2..0000000 --- a/js/minigames/lockpicking/lockpicking-game.js +++ /dev/null @@ -1,278 +0,0 @@ -import { MinigameScene } from '../framework/base-minigame.js'; - -// Load lockpicking-specific CSS -const lockpickingCSS = document.createElement('link'); -lockpickingCSS.rel = 'stylesheet'; -lockpickingCSS.href = 'css/lockpicking.css'; -lockpickingCSS.id = 'lockpicking-css'; -if (!document.getElementById('lockpicking-css')) { - document.head.appendChild(lockpickingCSS); -} - -// Lockpicking Minigame Scene implementation -export class LockpickingMinigame extends MinigameScene { - constructor(container, params) { - super(container, params); - - this.lockable = params.lockable; - this.difficulty = params.difficulty || 'medium'; - this.pinCount = this.difficulty === 'easy' ? 3 : this.difficulty === 'medium' ? 4 : 5; - - this.pins = []; - this.lockState = { - tensionApplied: false, - pinsSet: 0, - currentPin: null - }; - } - - init() { - super.init(); - - this.headerElement.innerHTML = ` -

Lockpicking

-

Apply tension and hold click on pins to lift them to the shear line

- `; - - this.setupLockpickingInterface(); - this.createPins(); - this.updateFeedback("Apply tension first, then click and hold on pins to lift them"); - } - - setupLockpickingInterface() { - this.gameContainer.innerHTML = ` -
Apply tension first, then click and hold on pins to lift them to the shear line
-
-
-
-
-
- Tension Wrench -
-
Ready to pick
- `; - - this.lockVisual = this.gameContainer.querySelector('.lock-visual'); - this.feedback = this.gameContainer.querySelector('.lockpick-feedback'); - - // Set up tension wrench - const tensionWrench = document.getElementById('tension-wrench'); - this.addEventListener(tensionWrench, 'click', () => { - this.lockState.tensionApplied = !this.lockState.tensionApplied; - tensionWrench.classList.toggle('active', this.lockState.tensionApplied); - this.updateBindingPins(); - this.updateFeedback(this.lockState.tensionApplied ? - "Tension applied. Now lift pins to the shear line." : - "Apply tension first."); - }); - } - - createPins() { - // Create random binding order - const bindingOrder = []; - for (let i = 0; i < this.pinCount; i++) { - bindingOrder.push(i); - } - this.shuffleArray(bindingOrder); - - // Create pins - for (let i = 0; i < this.pinCount; i++) { - const pin = { - index: i, - binding: bindingOrder[i], - isSet: false, - currentHeight: 0, - targetHeight: 30 + Math.random() * 30, // Random cut depth - elements: {} - }; - - // Create pin DOM elements - const pinElement = document.createElement('div'); - pinElement.className = 'pin'; - pinElement.style.order = i; - - const keyPin = document.createElement('div'); - keyPin.className = 'key-pin'; - - const driverPin = document.createElement('div'); - driverPin.className = 'driver-pin'; - - const spring = document.createElement('div'); - spring.className = 'spring'; - - pinElement.appendChild(keyPin); - pinElement.appendChild(driverPin); - pinElement.appendChild(spring); - - pin.elements = { - container: pinElement, - keyPin: keyPin, - driverPin: driverPin, - spring: spring - }; - - // Add event listeners - this.addEventListener(pinElement, 'mousedown', (e) => { - e.preventDefault(); - if (this.lockState.tensionApplied) { - this.lockState.currentPin = pin; - this.gameState.mouseDown = true; - this.liftPin(); - } - }); - - this.addEventListener(document, 'mouseup', () => { - if (this.lockState.currentPin) { - this.checkPinSet(this.lockState.currentPin); - this.lockState.currentPin = null; - } - this.gameState.mouseDown = false; - }); - - this.lockVisual.appendChild(pinElement); - this.pins.push(pin); - } - } - - liftPin() { - if (!this.lockState.currentPin || !this.gameState.mouseDown) return; - - const pin = this.lockState.currentPin; - pin.currentHeight = Math.min(pin.currentHeight + 2, 80); - - // Update visual - pin.elements.keyPin.style.height = `${pin.currentHeight}px`; - pin.elements.driverPin.style.bottom = `${60 + pin.currentHeight}px`; - - // Check if close to shear line - const distanceToShearLine = Math.abs(pin.currentHeight - 60); - if (distanceToShearLine < 5) { - pin.elements.container.style.boxShadow = "0 0 5px #ffffff"; - } else { - pin.elements.container.style.boxShadow = ""; - } - - if (this.gameState.mouseDown) { - requestAnimationFrame(() => this.liftPin()); - } - } - - checkPinSet(pin) { - const distanceToShearLine = Math.abs(pin.currentHeight - 60); - const shouldBind = this.shouldPinBind(pin); - - if (distanceToShearLine < 8 && shouldBind) { - // Pin set successfully - pin.isSet = true; - pin.elements.container.classList.add('set'); - this.lockState.pinsSet++; - - this.updateFeedback(`Pin ${pin.index + 1} set! (${this.lockState.pinsSet}/${this.pinCount})`); - this.updateBindingPins(); - - if (this.lockState.pinsSet === this.pinCount) { - this.lockPickingSuccess(); - } - } else if (this.lockState.tensionApplied && !shouldBind) { - // Wrong pin - reset all pins - this.resetAllPins(); - this.updateFeedback("Wrong pin! All pins reset."); - } else { - // Pin falls back down - pin.currentHeight = 0; - pin.elements.keyPin.style.height = '0px'; - pin.elements.driverPin.style.bottom = '60px'; - pin.elements.container.style.boxShadow = ""; - } - } - - shouldPinBind(pin) { - if (!this.lockState.tensionApplied) return false; - - // Find the next unset pin in binding order - for (let order = 0; order < this.pinCount; order++) { - const nextPin = this.pins.find(p => p.binding === order && !p.isSet); - if (nextPin) { - return pin.index === nextPin.index; - } - } - return false; - } - - updateBindingPins() { - if (!this.lockState.tensionApplied) { - this.pins.forEach(pin => { - pin.elements.container.classList.remove('binding'); - }); - return; - } - - // Find the next unset pin in binding order - for (let order = 0; order < this.pinCount; order++) { - const nextPin = this.pins.find(p => p.binding === order && !p.isSet); - if (nextPin) { - this.pins.forEach(pin => { - pin.elements.container.classList.toggle('binding', pin.index === nextPin.index); - }); - return; - } - } - - // All pins set - this.pins.forEach(pin => { - pin.elements.container.classList.remove('binding'); - }); - } - - resetAllPins() { - this.pins.forEach(pin => { - if (!pin.isSet) { - pin.currentHeight = 0; - pin.elements.keyPin.style.height = '0px'; - pin.elements.driverPin.style.bottom = '60px'; - pin.elements.container.style.boxShadow = ""; - } - }); - } - - updateFeedback(message) { - this.feedback.textContent = message; - } - - lockPickingSuccess() { - this.gameState.isActive = false; - this.updateFeedback("Lock picked successfully!"); - - const successHTML = ` -
Lock picked successfully!
-
All pins set at the shear line
-
- Difficulty: ${this.difficulty.charAt(0).toUpperCase() + this.difficulty.slice(1)}
- Pins: ${this.pinCount} -
- `; - - this.showSuccess(successHTML, true, 2000); - this.gameResult = { lockable: this.lockable }; - } - - start() { - super.start(); - this.gameState.isActive = true; - this.lockState.tensionApplied = false; - this.lockState.pinsSet = 0; - this.updateProgress(0, this.pinCount); - } - - complete(success) { - super.complete(success, this.gameResult); - } - - shuffleArray(array) { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; - } - return array; - } -} \ No newline at end of file diff --git a/lockpicking-comparison.html b/lockpicking-comparison.html deleted file mode 100644 index d16a934..0000000 --- a/lockpicking-comparison.html +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - Lockpicking Minigame Comparison - - - -
-

Lockpicking Minigame Comparison

-

Compare the original HTML/JS version with the new Phaser.js implementation

-
- -
-
-

Original HTML/JS Version

-
- -
-
- - -
-
-

Features

-
    -
  • ✓ Lightweight - no additional dependencies
  • -
  • ✓ Simple DOM manipulation
  • -
  • ✓ Easy to customize with CSS
  • -
  • ✗ Limited animation capabilities
  • -
  • ✗ Basic graphics rendering
  • -
  • ✗ Manual input handling
  • -
-
-
- -
-

Phaser.js Version

-
- -
-
- - -
-
-

Features

-
    -
  • ✓ Rich graphics and animations
  • -
  • ✓ Built-in game engine features
  • -
  • ✓ Professional game development tools
  • -
  • ✗ Larger bundle size
  • -
  • ✗ More complex setup
  • -
  • ✗ Learning curve for Phaser API
  • -
-
-
-
- - - - - - - - \ No newline at end of file