mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-21 11:18:08 +00:00
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.
This commit is contained in:
@@ -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%;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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 = `
|
||||
<div class="phaser-game-container" id="phaser-game-container"></div>
|
||||
<div class="lockpick-feedback"></div>
|
||||
`;
|
||||
|
||||
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...');
|
||||
|
||||
|
||||
@@ -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 = `
|
||||
<h3>Lockpicking</h3>
|
||||
<p>Apply tension and hold click on pins to lift them to the shear line</p>
|
||||
`;
|
||||
|
||||
this.setupLockpickingInterface();
|
||||
this.createPins();
|
||||
this.updateFeedback("Apply tension first, then click and hold on pins to lift them");
|
||||
}
|
||||
|
||||
setupLockpickingInterface() {
|
||||
this.gameContainer.innerHTML = `
|
||||
<div class="instructions">Apply tension first, then click and hold on pins to lift them to the shear line</div>
|
||||
<div class="lock-visual">
|
||||
<div class="shear-line"></div>
|
||||
</div>
|
||||
<div class="tension-control">
|
||||
<div class="tension-wrench" id="tension-wrench"></div>
|
||||
<span>Tension Wrench</span>
|
||||
</div>
|
||||
<div class="lockpick-feedback">Ready to pick</div>
|
||||
`;
|
||||
|
||||
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 = `
|
||||
<div style="font-weight: bold; font-size: 18px; margin-bottom: 10px;">Lock picked successfully!</div>
|
||||
<div style="font-size: 14px; margin-bottom: 15px;">All pins set at the shear line</div>
|
||||
<div style="font-size: 12px; color: #aaa;">
|
||||
Difficulty: ${this.difficulty.charAt(0).toUpperCase() + this.difficulty.slice(1)}<br>
|
||||
Pins: ${this.pinCount}
|
||||
</div>
|
||||
`;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Lockpicking Minigame Comparison</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background: #1a1a1a;
|
||||
color: #ffffff;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.comparison-container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.minigame-section {
|
||||
flex: 1;
|
||||
background: #2a2a2a;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
border: 2px solid #444;
|
||||
}
|
||||
|
||||
.minigame-section h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
color: #00ff00;
|
||||
}
|
||||
|
||||
.minigame-container {
|
||||
background: #333;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #00ff00;
|
||||
color: #000;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #00cc00;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
background: #666;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.info-panel {
|
||||
background: #444;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.info-panel h3 {
|
||||
margin-top: 0;
|
||||
color: #00ff00;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.feature-list li {
|
||||
padding: 5px 0;
|
||||
border-bottom: 1px solid #555;
|
||||
}
|
||||
|
||||
.feature-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.feature-list .pro {
|
||||
color: #00ff00;
|
||||
}
|
||||
|
||||
.feature-list .con {
|
||||
color: #ff4444;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
color: #00ff00;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.header p {
|
||||
color: #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>Lockpicking Minigame Comparison</h1>
|
||||
<p>Compare the original HTML/JS version with the new Phaser.js implementation</p>
|
||||
</div>
|
||||
|
||||
<div class="comparison-container">
|
||||
<div class="minigame-section">
|
||||
<h2>Original HTML/JS Version</h2>
|
||||
<div class="minigame-container" id="original-container">
|
||||
<!-- Original minigame will be loaded here -->
|
||||
</div>
|
||||
<div class="controls">
|
||||
<button class="btn" onclick="startOriginal()">Start Original</button>
|
||||
<button class="btn" onclick="stopOriginal()">Stop</button>
|
||||
</div>
|
||||
<div class="info-panel">
|
||||
<h3>Features</h3>
|
||||
<ul class="feature-list">
|
||||
<li class="pro">✓ Lightweight - no additional dependencies</li>
|
||||
<li class="pro">✓ Simple DOM manipulation</li>
|
||||
<li class="pro">✓ Easy to customize with CSS</li>
|
||||
<li class="con">✗ Limited animation capabilities</li>
|
||||
<li class="con">✗ Basic graphics rendering</li>
|
||||
<li class="con">✗ Manual input handling</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="minigame-section">
|
||||
<h2>Phaser.js Version</h2>
|
||||
<div class="minigame-container" id="phaser-container">
|
||||
<!-- Phaser minigame will be loaded here -->
|
||||
</div>
|
||||
<div class="controls">
|
||||
<button class="btn" onclick="startPhaser()">Start Phaser</button>
|
||||
<button class="btn" onclick="stopPhaser()">Stop</button>
|
||||
</div>
|
||||
<div class="info-panel">
|
||||
<h3>Features</h3>
|
||||
<ul class="feature-list">
|
||||
<li class="pro">✓ Rich graphics and animations</li>
|
||||
<li class="pro">✓ Built-in game engine features</li>
|
||||
<li class="pro">✓ Professional game development tools</li>
|
||||
<li class="con">✗ Larger bundle size</li>
|
||||
<li class="con">✗ More complex setup</li>
|
||||
<li class="con">✗ Learning curve for Phaser API</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Load Phaser.js -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser.min.js"></script>
|
||||
|
||||
<!-- Load minigame framework -->
|
||||
<script type="module">
|
||||
import { MinigameFramework } from './js/minigames/index.js';
|
||||
|
||||
let originalMinigame = null;
|
||||
let phaserMinigame = null;
|
||||
|
||||
window.startOriginal = function() {
|
||||
if (originalMinigame) {
|
||||
originalMinigame.cleanup();
|
||||
}
|
||||
|
||||
const container = document.getElementById('original-container');
|
||||
container.setAttribute('data-external', 'true');
|
||||
originalMinigame = MinigameFramework.startMinigame('lockpicking-legacy', container, {
|
||||
lockable: 'test-lock',
|
||||
difficulty: 'medium'
|
||||
});
|
||||
};
|
||||
|
||||
window.stopOriginal = function() {
|
||||
if (originalMinigame) {
|
||||
originalMinigame.complete(false);
|
||||
originalMinigame = null;
|
||||
}
|
||||
};
|
||||
|
||||
window.startPhaser = function() {
|
||||
if (phaserMinigame) {
|
||||
phaserMinigame.cleanup();
|
||||
}
|
||||
|
||||
const container = document.getElementById('phaser-container');
|
||||
container.setAttribute('data-external', 'true');
|
||||
phaserMinigame = MinigameFramework.startMinigame('lockpicking', container, {
|
||||
lockable: 'test-lock',
|
||||
difficulty: 'medium'
|
||||
});
|
||||
};
|
||||
|
||||
window.stopPhaser = function() {
|
||||
if (phaserMinigame) {
|
||||
phaserMinigame.complete(false);
|
||||
phaserMinigame = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Auto-start both minigames after a short delay
|
||||
setTimeout(() => {
|
||||
startOriginal();
|
||||
startPhaser();
|
||||
}, 1000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user