1122 lines
No EOL
45 KiB
HTML
1122 lines
No EOL
45 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Simple Final Solution Game</title>
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
background-color: black;
|
|
font-family: Arial, sans-serif;
|
|
}
|
|
#game-container {
|
|
position: relative;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
cursor: none;
|
|
background: url('https://pub-6affea2f837c47c2a8d1d16f2b8fa68e.r2.dev/911.jpg') no-repeat center center;
|
|
background-size: cover;
|
|
overflow: hidden;
|
|
}
|
|
.target {
|
|
position: absolute;
|
|
width: 70px;
|
|
height: 70px;
|
|
border-radius: 50%;
|
|
transition: transform 0.1s, opacity 0.2s;
|
|
background-size: cover;
|
|
background-position: center;
|
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.7);
|
|
}
|
|
|
|
.target::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 15px;
|
|
left: 15px;
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
background: rgba(0, 0, 0, 0.3);
|
|
z-index: 2;
|
|
}
|
|
|
|
.target::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 25px;
|
|
left: 25px;
|
|
width: 20px;
|
|
height: 20px;
|
|
border-radius: 50%;
|
|
background: rgba(0, 0, 0, 0.6);
|
|
z-index: 3;
|
|
}
|
|
|
|
.target-type-1 {
|
|
border: 6px solid #ff0000;
|
|
}
|
|
|
|
.target-type-2 {
|
|
border: 6px solid #00b7ff;
|
|
}
|
|
|
|
.target-type-3 {
|
|
border: 6px solid #ff9900;
|
|
}
|
|
|
|
.health-bar {
|
|
position: absolute;
|
|
bottom: -10px;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 5px;
|
|
background-color: #333;
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.health-fill {
|
|
height: 100%;
|
|
background-color: lime;
|
|
transition: width 0.2s;
|
|
}
|
|
|
|
.damage-indicator {
|
|
position: absolute;
|
|
font-size: 14px;
|
|
color: white;
|
|
font-weight: bold;
|
|
text-shadow: 0px 0px 3px black;
|
|
opacity: 1;
|
|
transition: opacity 1s, transform 1s;
|
|
}
|
|
.explosion {
|
|
position: absolute;
|
|
width: 50px;
|
|
height: 50px;
|
|
background: radial-gradient(circle, yellow, orange, red);
|
|
border-radius: 50%;
|
|
animation: explode 0.5s forwards;
|
|
z-index: 5;
|
|
}
|
|
@keyframes explode {
|
|
0% { transform: scale(0.5); opacity: 1; }
|
|
100% { transform: scale(2); opacity: 0; }
|
|
}
|
|
.bullet-hole {
|
|
position: absolute;
|
|
width: 8px;
|
|
height: 8px;
|
|
background-color: #333;
|
|
border-radius: 50%;
|
|
border: 1px solid #666;
|
|
z-index: 1;
|
|
}
|
|
.muzzle-flash {
|
|
position: absolute;
|
|
width: 60px;
|
|
height: 60px;
|
|
background: radial-gradient(circle, white 10%, yellow 40%, orange 70%, transparent 100%);
|
|
border-radius: 50%;
|
|
transform: translate(-30px, -30px);
|
|
animation: flash 0.15s forwards;
|
|
pointer-events: none;
|
|
z-index: 10;
|
|
}
|
|
@keyframes flash {
|
|
0% { opacity: 1; transform: translate(-30px, -30px) scale(0.6); }
|
|
100% { opacity: 0; transform: translate(-30px, -30px) scale(1); }
|
|
}
|
|
#hud {
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 20px;
|
|
color: white;
|
|
font-size: 20px;
|
|
pointer-events: none;
|
|
text-shadow: 0px 0px 5px black;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
#weapon-hud {
|
|
position: absolute;
|
|
bottom: 20px;
|
|
right: 20px;
|
|
color: white;
|
|
font-size: 18px;
|
|
pointer-events: none;
|
|
text-shadow: 0px 0px 5px black;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
#ammo-counter {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.bullet-icon {
|
|
width: 10px;
|
|
height: 20px;
|
|
background-color: #ffcc00;
|
|
border-radius: 2px;
|
|
margin-right: 3px;
|
|
position: relative;
|
|
}
|
|
|
|
.bullet-icon::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: -3px;
|
|
left: 2px;
|
|
width: 6px;
|
|
height: 6px;
|
|
background-color: #ffaa00;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.empty-bullet {
|
|
background-color: #555;
|
|
}
|
|
|
|
.empty-bullet::after {
|
|
background-color: #444;
|
|
}
|
|
|
|
#weapon-info {
|
|
margin-right: 15px;
|
|
}
|
|
|
|
#score-popup {
|
|
position: fixed;
|
|
color: white;
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
text-shadow: 0px 0px 5px black;
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
transition: transform 0.5s, opacity 0.5s;
|
|
z-index: 1000;
|
|
}
|
|
|
|
#hitmarker {
|
|
position: fixed;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
width: 30px;
|
|
height: 30px;
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
z-index: 1000;
|
|
}
|
|
|
|
#hitmarker::before,
|
|
#hitmarker::after {
|
|
content: '';
|
|
position: absolute;
|
|
background-color: white;
|
|
}
|
|
|
|
#hitmarker::before {
|
|
width: 2px;
|
|
height: 30px;
|
|
left: 14px;
|
|
top: 0;
|
|
}
|
|
|
|
#hitmarker::after {
|
|
width: 30px;
|
|
height: 2px;
|
|
left: 0;
|
|
top: 14px;
|
|
}
|
|
|
|
.screen-flash {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: rgba(255, 0, 0, 0.2);
|
|
pointer-events: none;
|
|
z-index: 999;
|
|
opacity: 0;
|
|
transition: opacity 0.2s;
|
|
}
|
|
#crosshair {
|
|
position: absolute;
|
|
width: 40px;
|
|
height: 40px;
|
|
pointer-events: none;
|
|
transform: translate(-20px, -20px);
|
|
opacity: 0.8;
|
|
z-index: 9999; /* Increased z-index to appear above targets */
|
|
}
|
|
#crosshair::before, #crosshair::after {
|
|
content: '';
|
|
position: absolute;
|
|
background-color: rgba(255, 255, 255, 0.8);
|
|
}
|
|
#crosshair::before {
|
|
width: 2px;
|
|
height: 40px;
|
|
left: 19px;
|
|
top: 0;
|
|
}
|
|
#crosshair::after {
|
|
width: 40px;
|
|
height: 2px;
|
|
left: 0;
|
|
top: 19px;
|
|
}
|
|
#crosshair-dot {
|
|
position: absolute;
|
|
width: 6px;
|
|
height: 6px;
|
|
background-color: rgba(255, 0, 0, 0.8);
|
|
border-radius: 50%;
|
|
left: 17px;
|
|
top: 17px;
|
|
}
|
|
.gun-model {
|
|
position: fixed;
|
|
bottom: 0;
|
|
right: 50%;
|
|
transform: translateX(100px);
|
|
width: 300px;
|
|
height: 200px;
|
|
background-image: url('/api/placeholder/300/200');
|
|
background-size: contain;
|
|
background-repeat: no-repeat;
|
|
background-position: bottom right;
|
|
z-index: 100;
|
|
pointer-events: none;
|
|
transition: transform 0.05s;
|
|
filter: drop-shadow(0 0 10px rgba(255, 165, 0, 0.5));
|
|
}
|
|
#game-over {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background-color: rgba(0, 0, 0, 0.8);
|
|
padding: 20px;
|
|
border-radius: 10px;
|
|
color: white;
|
|
text-align: center;
|
|
display: none;
|
|
}
|
|
button {
|
|
background-color: #00ff08;
|
|
border: none;
|
|
color: white;
|
|
padding: 10px 20px;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
font-size: 16px;
|
|
margin: 10px 2px;
|
|
cursor: pointer;
|
|
border-radius: 5px;
|
|
}
|
|
#instructions {
|
|
position: absolute;
|
|
top: 20px;
|
|
right: 20px;
|
|
background-color: rgba(0, 0, 0, 0.7);
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
color: white;
|
|
max-width: 300px;
|
|
}
|
|
#settings {
|
|
position: absolute;
|
|
top: 60px;
|
|
right: 430px;
|
|
background-color: rgba(0, 0, 0, 0.7);
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
color: white;
|
|
display: none;
|
|
}
|
|
.settings-option {
|
|
margin: 10px 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
.settings-button {
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 430px;
|
|
background-color: rgba(0, 0, 0, 0.7);
|
|
color: white;
|
|
border: 1px solid white;
|
|
border-radius: 5px;
|
|
padding: 5px 10px;
|
|
cursor: pointer;
|
|
}
|
|
/* Music player styles */
|
|
#music-toggle {
|
|
position: absolute;
|
|
bottom: 100px;
|
|
right: 50px;
|
|
width: 50px;
|
|
height: 50px;
|
|
background-color: rgba(0, 0, 0, 0.7);
|
|
color: white;
|
|
border: 1px solid white;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 24px;
|
|
cursor: pointer;
|
|
z-index: 1000;
|
|
}
|
|
|
|
#music-toggle.pulse {
|
|
animation: pulse 2s infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0% { transform: scale(1); }
|
|
50% { transform: scale(1.1); }
|
|
100% { transform: scale(1); }
|
|
}
|
|
|
|
.vinyl-spinning {
|
|
display: inline-block;
|
|
animation: spin 1.5s linear infinite;
|
|
}
|
|
|
|
.vinyl-ready {
|
|
display: inline-block;
|
|
}
|
|
|
|
@keyframes spin {
|
|
from { transform: rotate(0deg); }
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="game-container">
|
|
<div id="hud">
|
|
<div>Score: <span id="score">0</span></div>
|
|
<div>Time: <span id="time">60</span>s</div>
|
|
<div>Mission: Shoot all RED JEW targets!</div>
|
|
<div id="streak-counter">Streak: <span id="current-streak">0</span></div>
|
|
<div id="headshot-counter">Headshots: <span id="headshots">0</span></div>
|
|
</div>
|
|
<div id="weapon-hud">
|
|
<div id="weapon-info">
|
|
<div id="weapon-name">9mm Pistol</div>
|
|
<div id="fire-mode">Semi-Auto</div>
|
|
</div>
|
|
<div id="ammo-counter"></div>
|
|
<div id="reload-hint">(Press R to reload)</div>
|
|
</div>
|
|
<div id="crosshair"><div id="crosshair-dot"></div></div>
|
|
<div id="gun-model" class="gun-model"></div>
|
|
<div id="hitmarker"></div>
|
|
<div id="score-popup"></div>
|
|
<div class="screen-flash" id="damage-flash"></div>
|
|
<button class="settings-button" id="settings-button">⚙️ Settings</button>
|
|
<!-- Music Toggle Button -->
|
|
<div id="music-toggle" class="pulse">
|
|
<span class="vinyl-ready">📻</span>
|
|
</div>
|
|
<div id="instructions">
|
|
<h3>Instructions for Goyim:</h3>
|
|
<p>Click to shoot at the RED JEW targets. Avoid hitting BLUE targets as they will steal your points.</p>
|
|
<p>Avoid the ORANGE Hasbullah targets (big penalty)!</p>
|
|
<p>You have 60 seconds to get the highest score possible!</p>
|
|
<button id="start-game">Start Game</button>
|
|
</div>
|
|
<div id="settings">
|
|
<h3>Game Settings</h3>
|
|
<div class="settings-option">
|
|
<label for="auto-reload">Auto Reload:</label>
|
|
<input type="checkbox" id="auto-reload">
|
|
</div>
|
|
<div class="settings-option">
|
|
<label for="difficulty">Difficulty:</label>
|
|
<select id="difficulty">
|
|
<option value="easy">Easy</option>
|
|
<option value="medium" selected>Medium</option>
|
|
<option value="hard">Hard</option>
|
|
</select>
|
|
</div>
|
|
<button id="save-settings">Save Settings</button>
|
|
</div>
|
|
<div id="game-over">
|
|
<h2>You filthy Goyim!</h2>
|
|
<p>Final Score: <span id="final-score">0</span></p>
|
|
<button id="restart-game">Defend Watermelons 🍉</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const gameContainer = document.getElementById('game-container');
|
|
const scoreElement = document.getElementById('score');
|
|
const timeElement = document.getElementById('time');
|
|
const gameOverScreen = document.getElementById('game-over');
|
|
const finalScoreElement = document.getElementById('final-score');
|
|
const startGameButton = document.getElementById('start-game');
|
|
const restartGameButton = document.getElementById('restart-game');
|
|
const instructions = document.getElementById('instructions');
|
|
const crosshair = document.getElementById('crosshair');
|
|
const gunModel = document.getElementById('gun-model');
|
|
const settingsButton = document.getElementById('settings-button');
|
|
const settingsPanel = document.getElementById('settings');
|
|
const saveSettingsButton = document.getElementById('save-settings');
|
|
const autoReloadCheckbox = document.getElementById('auto-reload');
|
|
const difficultySelect = document.getElementById('difficulty');
|
|
|
|
const musicToggle = document.getElementById('music-toggle');
|
|
|
|
// Background music setup
|
|
const backgroundMusic = new Audio();
|
|
backgroundMusic.src = "https://pub-6affea2f837c47c2a8d1d16f2b8fa68e.r2.dev/throwthejewdownthewell.mp3";
|
|
backgroundMusic.loop = true;
|
|
backgroundMusic.volume = 0.7;
|
|
|
|
// Music player controls
|
|
function playAudio() {
|
|
console.log("Playing audio...");
|
|
|
|
// Only set the time to 26 seconds if it's at the beginning
|
|
if (backgroundMusic.currentTime === 0) {
|
|
backgroundMusic.currentTime = 26;
|
|
}
|
|
|
|
backgroundMusic.play().then(() => {
|
|
console.log("Audio playing successfully");
|
|
musicToggle.innerHTML = '<span class="vinyl-spinning">📀</span>';
|
|
musicToggle.classList.remove('pulse');
|
|
}).catch(error => {
|
|
console.error('Failed to play audio:', error);
|
|
musicToggle.innerHTML = '<span class="vinyl-ready">📻</span>';
|
|
musicToggle.classList.add('pulse');
|
|
});
|
|
}
|
|
|
|
function toggleMusic() {
|
|
if (backgroundMusic.paused) {
|
|
// Continue playing from where it was paused
|
|
backgroundMusic.play().then(() => {
|
|
console.log("Audio playing successfully");
|
|
musicToggle.innerHTML = '<span class="vinyl-spinning">📀</span>';
|
|
musicToggle.classList.remove('pulse');
|
|
}).catch(error => {
|
|
console.error('Failed to play audio:', error);
|
|
musicToggle.innerHTML = '<span class="vinyl-ready">📻</span>';
|
|
musicToggle.classList.add('pulse');
|
|
});
|
|
} else {
|
|
// Pause but don't reset the current time
|
|
backgroundMusic.pause();
|
|
musicToggle.innerHTML = '<span class="vinyl-ready">📻</span>';
|
|
musicToggle.classList.add('pulse');
|
|
}
|
|
}
|
|
|
|
// Add music toggle click event
|
|
musicToggle.addEventListener('click', toggleMusic);
|
|
|
|
// Custom target images
|
|
const targetImages = [
|
|
"https://pub-6affea2f837c47c2a8d1d16f2b8fa68e.r2.dev/happyjew.jpg",
|
|
"https://pub-6affea2f837c47c2a8d1d16f2b8fa68e.r2.dev/happyjew1.jpg",
|
|
"https://pub-6affea2f837c47c2a8d1d16f2b8fa68e.r2.dev/happyjew2.jpg",
|
|
"https://pub-6affea2f837c47c2a8d1d16f2b8fa68e.r2.dev/happyjew3.jpg",
|
|
"https://pub-6affea2f837c47c2a8d1d16f2b8fa68e.r2.dev/happyjew4.jpg"
|
|
];
|
|
|
|
// Hasbullah image to avoid
|
|
const hasbullahImage = "https://pub-6affea2f837c47c2a8d1d16f2b8fa68e.r2.dev/hasbullah.png";
|
|
|
|
let score = 0;
|
|
let timeRemaining = 60;
|
|
let gameActive = false;
|
|
let targets = [];
|
|
let targetGenerationInterval;
|
|
let countdownInterval;
|
|
let ammo = 6;
|
|
let maxAmmo = 6;
|
|
let reloading = false;
|
|
let lastShotTime = 0;
|
|
let shotDelay = 200; // ms between shots
|
|
let currentStreak = 0;
|
|
let bestStreak = 0;
|
|
let headshotCount = 0;
|
|
let difficultyLevel = 1;
|
|
let playerHealth = 100;
|
|
let damageFlashTimeout;
|
|
let scoreMultiplier = 1;
|
|
let hitmarkerSound;
|
|
let autoReload = false;
|
|
|
|
// Gun sounds
|
|
const gunshotSound = new Audio();
|
|
gunshotSound.src = "data:audio/wav;base64,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";
|
|
|
|
const emptyClickSound = new Audio();
|
|
emptyClickSound.src = "data:audio/wav;base64,UklGRpYDAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YXIDAAAAAAEGBgsLDxEWGBweISImKSstMDM1ODo8PUBCREVGR0hJSktNTk9QUVFSU1NUVVZWVldYWFlZWlpaW1tcXFxdXV1dXV1eXl5fX19fX19gYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYF9fX19fXl5eXl1dXVxcXFtbWlpaWVlYWFdXVlZVVFRTUlJRUE9PTk1MS0pJSEdGRURDQkFAPz49PDs6OTg3NjU0MzIxMC8uLSwrKikoJyYlJCMiISAfHh0cGxoZGBcWFRQTEhEQDw4ODQwLCgkIBwYGBQQDAgEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQICAwQEBQYHBwgJCgsLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSUlNUVVVWV1hYWVpbW1xdXV5eX19gYGFhYmJjY2RkZWVmZmZnZ2hoaWlqampra2xsbW1tbm5vb29wcHFxcXJycnNzc3R0dHV1dXZ2dnd3d3h4eHl5eXp6ent7e3x8fH19fX5+fn9/f4CAgIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouLi4yMjI2NjY6Ojo+Pj5CQkJGRkZKSkpOTk5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2dnZ6enp+fn6CgoKGhoaKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+vr7CwsLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5ubq6uru7u7y8vL29vb6+vr+/v8DAwMHBwcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zMzM3Nzc7Ozs/Pz9DQ0NHR0dLS0tPT09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f3+Dg4OHh4eLi4uPj4+Tk5OXl5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw8PHx8fLy8vPz8/T09PX19fb29vf39/j4+Pn5+fr6+vv7+/z8/P39/f7+/v8=";
|
|
|
|
const reloadSound = new Audio();
|
|
reloadSound.src = "data:audio/wav;base64,UklGRoIDAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YXYDAAB8fYF/hH2JfY17j3eVd5NzmG6capNlk2eccKJ1o3mmf6aDqoitibCNs5O4mLuevKTAqcOuxLTJusi/0MXVzNnS3tTh1ubZ6trv3PXe+uD/4ATiBeeI6orwjvSR95b6nP2h/6cCqQatCLEKtQ24D7wTwRXEGMgczSDRJNQn2CzaL+Ay5DXmOOg76T7rQexE7UbtSu1N7U7tUO5S7lPvU+9U8FXwVvBX8FfwV/BX8VjxWPFY8VnxWfFa8lryWvJa8lvyW/Jb8lzzXPNc813zXfNe817zXvNf81/zX/Ng82DzYPNh82HzYvNi82PzY/Nk82TzZPNl82XzZvNm82fzZ/No82jzafNp82rza/Ns823zbvNv83HzcvN083XzePJ683vzdPN183jyevJ883vyffJ+8YDxgvGE8YXxh/GJ8YrxjfGP8ZLxlPGX8Znxm/Ge8aHxpPGn8avxrvGy8bbxufG98cHxxfHJ8czx0PHU8djx3PHh8eXx6vHu8fPx9/H88QHyBvIL8hDyFfIa8h/yJfIq8jDyNfI78kHyR/JN8lPyWfJf8mbybbJz8nrygfKI8o/ylvKd8qXyq/Kz8rvywfLJ8tHy2fLh8uny8PL48wD0CfQR9Br0IvQr9DT0PPRFNk03TjhPOVA6UDtQPFA9UD9QQFBBUEJQRFBFUEZQRlBHUEdQSFBIUElQSVBKUEpQSlBLUEtQS1BLUEtQTFBMUExQTFBMUExQTFBMUE1QTVBNUE1QTVBNUE1QTVBNUE1QTVBNUE1QTVBNUE1QTVBNUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOUE5QTlBOU";
|
|
|
|
// Animation frames for recoil
|
|
let recoilAnimation = null;
|
|
|
|
// Settings panel toggle
|
|
settingsButton.addEventListener('click', () => {
|
|
if (settingsPanel.style.display === 'block') {
|
|
settingsPanel.style.display = 'none';
|
|
} else {
|
|
settingsPanel.style.display = 'block';
|
|
}
|
|
});
|
|
|
|
// Save settings
|
|
saveSettingsButton.addEventListener('click', () => {
|
|
autoReload = autoReloadCheckbox.checked;
|
|
const difficulty = difficultySelect.value;
|
|
|
|
// Apply difficulty settings
|
|
if (difficulty === 'easy') {
|
|
difficultyLevel = 0.7;
|
|
} else if (difficulty === 'medium') {
|
|
difficultyLevel = 1;
|
|
} else {
|
|
difficultyLevel = 1.5;
|
|
}
|
|
|
|
settingsPanel.style.display = 'none';
|
|
});
|
|
|
|
// Track mouse for crosshair
|
|
gameContainer.addEventListener('mousemove', (e) => {
|
|
crosshair.style.left = e.clientX + 'px';
|
|
crosshair.style.top = e.clientY + 'px';
|
|
|
|
// Subtle gun movement following mouse
|
|
if (gameActive) {
|
|
const centerX = window.innerWidth / 2;
|
|
const centerY = window.innerHeight / 2;
|
|
const offsetX = (e.clientX - centerX) / 20;
|
|
const offsetY = (e.clientY - centerY) / 20;
|
|
gunModel.style.transform = `translateX(${100 + offsetX}px) translateY(${offsetY}px)`;
|
|
}
|
|
});
|
|
|
|
function startGame() {
|
|
// Reset game state
|
|
score = 0;
|
|
timeRemaining = 60;
|
|
gameActive = true;
|
|
ammo = 6;
|
|
reloading = false;
|
|
targets.forEach(target => target.element.remove());
|
|
targets = [];
|
|
currentStreak = 0;
|
|
document.getElementById('current-streak').textContent = currentStreak;
|
|
headshotCount = 0;
|
|
document.getElementById('headshots').textContent = headshotCount;
|
|
|
|
// Update UI
|
|
scoreElement.textContent = score;
|
|
timeElement.textContent = timeRemaining;
|
|
instructions.style.display = 'none';
|
|
settingsPanel.style.display = 'none';
|
|
gameOverScreen.style.display = 'none';
|
|
updateAmmoDisplay();
|
|
|
|
// Make sure gun model is visible and properly positioned
|
|
gunModel.style.display = 'block';
|
|
gunModel.style.transform = 'translateX(100px)';
|
|
|
|
// Start generating targets
|
|
targetGenerationInterval = setInterval(generateTarget, 1000 / difficultyLevel);
|
|
|
|
// Start countdown
|
|
countdownInterval = setInterval(() => {
|
|
timeRemaining--;
|
|
timeElement.textContent = timeRemaining;
|
|
|
|
if (timeRemaining <= 0) {
|
|
endGame();
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
function endGame() {
|
|
gameActive = false;
|
|
clearInterval(targetGenerationInterval);
|
|
clearInterval(countdownInterval);
|
|
|
|
// Display game over screen
|
|
finalScoreElement.textContent = score;
|
|
gameOverScreen.style.display = 'block';
|
|
|
|
// Remove all targets
|
|
targets.forEach(target => target.element.remove());
|
|
targets = [];
|
|
}
|
|
|
|
function generateTarget() {
|
|
if (!gameActive) return;
|
|
|
|
// Random target type: 1=JEW (shoot), 2=BLUE (avoid), 3=HASBULLAH (big penalty)
|
|
// Adjust probability based on difficulty
|
|
let targetTypeRand = Math.random();
|
|
let targetType;
|
|
|
|
if (targetTypeRand < 0.7) {
|
|
targetType = 1; // JEW target (to shoot)
|
|
} else if (targetTypeRand < 0.9) {
|
|
targetType = 2; // BLUE target (to avoid)
|
|
} else {
|
|
targetType = 3; // HASBULLAH target (bigger penalty)
|
|
}
|
|
|
|
const targetElement = document.createElement('div');
|
|
targetElement.className = `target target-type-${targetType}`;
|
|
|
|
// Set the background image based on target type
|
|
if (targetType === 3) {
|
|
// Hasbullah image
|
|
targetElement.style.backgroundImage = `url(${hasbullahImage})`;
|
|
} else {
|
|
// Choose a random image from our collection for other targets
|
|
const randomImageIndex = Math.floor(Math.random() * targetImages.length);
|
|
targetElement.style.backgroundImage = `url(${targetImages[randomImageIndex]})`;
|
|
}
|
|
|
|
// Random position
|
|
const x = Math.random() * (gameContainer.offsetWidth - 50);
|
|
const y = Math.random() * (gameContainer.offsetHeight - 50);
|
|
targetElement.style.left = x + 'px';
|
|
targetElement.style.top = y + 'px';
|
|
|
|
// Add health bar
|
|
const healthBar = document.createElement('div');
|
|
healthBar.className = 'health-bar';
|
|
const healthFill = document.createElement('div');
|
|
healthFill.className = 'health-fill';
|
|
healthFill.style.width = '100%';
|
|
healthBar.appendChild(healthFill);
|
|
targetElement.appendChild(healthBar);
|
|
|
|
gameContainer.appendChild(targetElement);
|
|
|
|
// Target object
|
|
const target = {
|
|
element: targetElement,
|
|
type: targetType,
|
|
x: x,
|
|
y: y,
|
|
speed: (1 + Math.random() * 2) * difficultyLevel,
|
|
direction: Math.random() * Math.PI * 2,
|
|
health: targetType === 3 ? 150 : 100, // Hasbullah targets are tougher
|
|
healthBar: healthFill
|
|
};
|
|
|
|
targets.push(target);
|
|
|
|
// Remove target after random time (shorter time based on difficulty)
|
|
setTimeout(() => {
|
|
if (targets.includes(target)) {
|
|
targetElement.remove();
|
|
targets = targets.filter(t => t !== target);
|
|
}
|
|
}, (3000 + Math.random() * 2000) / difficultyLevel);
|
|
}
|
|
|
|
function updateTargets() {
|
|
targets.forEach(target => {
|
|
// Update position
|
|
target.x += Math.cos(target.direction) * target.speed;
|
|
target.y += Math.sin(target.direction) * target.speed;
|
|
|
|
// Bounce off walls
|
|
if (target.x < 0 || target.x > gameContainer.offsetWidth - 50) {
|
|
target.direction = Math.PI - target.direction;
|
|
target.x = Math.max(0, Math.min(target.x, gameContainer.offsetWidth - 50));
|
|
}
|
|
if (target.y < 0 || target.y > gameContainer.offsetHeight - 50) {
|
|
target.direction = -target.direction;
|
|
target.y = Math.max(0, Math.min(target.y, gameContainer.offsetHeight - 50));
|
|
}
|
|
|
|
// Update element position
|
|
target.element.style.left = target.x + 'px';
|
|
target.element.style.top = target.y + 'px';
|
|
});
|
|
|
|
if (gameActive) {
|
|
requestAnimationFrame(updateTargets);
|
|
}
|
|
}
|
|
|
|
function createExplosion(x, y) {
|
|
const explosion = document.createElement('div');
|
|
explosion.className = 'explosion';
|
|
explosion.style.left = x + 'px';
|
|
explosion.style.top = y + 'px';
|
|
gameContainer.appendChild(explosion);
|
|
|
|
setTimeout(() => {
|
|
explosion.remove();
|
|
}, 500);
|
|
}
|
|
|
|
// Update ammo display
|
|
function updateAmmoDisplay() {
|
|
const ammoCounter = document.getElementById('ammo-counter');
|
|
ammoCounter.innerHTML = '';
|
|
|
|
// Create bullet icons
|
|
for (let i = 0; i < maxAmmo; i++) {
|
|
const bulletIcon = document.createElement('div');
|
|
bulletIcon.className = i < ammo ? 'bullet-icon' : 'bullet-icon empty-bullet';
|
|
ammoCounter.appendChild(bulletIcon);
|
|
}
|
|
}
|
|
|
|
// Reload function
|
|
function reload() {
|
|
if (reloading || ammo === maxAmmo) return;
|
|
|
|
reloading = true;
|
|
reloadSound.currentTime = 0;
|
|
reloadSound.play();
|
|
|
|
// Show reload text
|
|
const reloadText = document.createElement('div');
|
|
reloadText.textContent = 'RELOADING...';
|
|
reloadText.style.position = 'absolute';
|
|
reloadText.style.bottom = '200px';
|
|
reloadText.style.right = '50%';
|
|
reloadText.style.transform = 'translateX(100px)';
|
|
reloadText.style.color = 'white';
|
|
reloadText.style.fontWeight = 'bold';
|
|
reloadText.style.fontSize = '24px';
|
|
gameContainer.appendChild(reloadText);
|
|
|
|
// Reload animation - gun tilts down
|
|
gunModel.style.transform = 'translateX(100px) translateY(30px) rotate(-10deg)';
|
|
|
|
setTimeout(() => {
|
|
ammo = maxAmmo;
|
|
updateAmmoDisplay();
|
|
reloading = false;
|
|
reloadText.remove();
|
|
gunModel.style.transform = 'translateX(100px)';
|
|
}, 1500);
|
|
}
|
|
|
|
// Handle weapon recoil
|
|
function applyRecoil() {
|
|
// Cancel any existing recoil animation
|
|
if (recoilAnimation) {
|
|
cancelAnimationFrame(recoilAnimation);
|
|
}
|
|
|
|
let recoilStrength = 20;
|
|
let recovery = 0;
|
|
|
|
function animateRecoil() {
|
|
if (recovery < 1) {
|
|
recovery += 0.1;
|
|
const currentRecoil = recoilStrength * (1 - recovery);
|
|
gunModel.style.transform = `translateX(${100 - currentRecoil}px) translateY(${currentRecoil/2}px)`;
|
|
recoilAnimation = requestAnimationFrame(animateRecoil);
|
|
} else {
|
|
gunModel.style.transform = 'translateX(100px)';
|
|
recoilAnimation = null;
|
|
}
|
|
}
|
|
|
|
recoilAnimation = requestAnimationFrame(animateRecoil);
|
|
}
|
|
|
|
// Show hit marker
|
|
function showHitMarker() {
|
|
const hitmarker = document.getElementById('hitmarker');
|
|
hitmarker.style.opacity = '1';
|
|
|
|
setTimeout(() => {
|
|
hitmarker.style.opacity = '0';
|
|
}, 100);
|
|
}
|
|
|
|
// Show score popup
|
|
function showScorePopup(x, y, amount, isHeadshot) {
|
|
const popup = document.getElementById('score-popup');
|
|
popup.textContent = `${isHeadshot ? 'HEADSHOT! ' : ''}${amount > 0 ? '+' : ''}${amount}`;
|
|
popup.style.left = x + 'px';
|
|
popup.style.top = (y - 30) + 'px';
|
|
popup.style.color = amount > 0 ? (isHeadshot ? '#ff0000' : '#ffffff') : '#ff5555';
|
|
popup.style.opacity = '1';
|
|
popup.style.transform = 'translateY(0)';
|
|
|
|
setTimeout(() => {
|
|
popup.style.opacity = '0';
|
|
popup.style.transform = 'translateY(-20px)';
|
|
}, 1000);
|
|
}
|
|
|
|
// Handle shots
|
|
gameContainer.addEventListener('click', (e) => {
|
|
if (!gameActive) return;
|
|
if (reloading) return;
|
|
|
|
const now = Date.now();
|
|
// Enforce minimum time between shots
|
|
if (now - lastShotTime < shotDelay) return;
|
|
lastShotTime = now;
|
|
|
|
const clickX = e.clientX;
|
|
const clickY = e.clientY;
|
|
|
|
// Check ammo
|
|
if (ammo <= 0) {
|
|
// Play empty click sound
|
|
emptyClickSound.currentTime = 0;
|
|
emptyClickSound.play();
|
|
|
|
// Auto reload if enabled
|
|
if (autoReload) {
|
|
reload();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Decrease ammo
|
|
ammo--;
|
|
updateAmmoDisplay();
|
|
|
|
// Auto reload if enabled and out of ammo
|
|
if (autoReload && ammo === 0) {
|
|
reload();
|
|
}
|
|
|
|
// Play gunshot sound
|
|
gunshotSound.currentTime = 0;
|
|
gunshotSound.play();
|
|
|
|
// Apply recoil effect
|
|
applyRecoil();
|
|
|
|
// Create muzzle flash
|
|
const flash = document.createElement('div');
|
|
flash.className = 'muzzle-flash';
|
|
flash.style.left = clickX + 'px';
|
|
flash.style.top = clickY + 'px';
|
|
gameContainer.appendChild(flash);
|
|
|
|
setTimeout(() => {
|
|
flash.remove();
|
|
}, 150);
|
|
|
|
// Add bullet hole to background
|
|
const bulletHole = document.createElement('div');
|
|
bulletHole.className = 'bullet-hole';
|
|
bulletHole.style.left = (clickX - 4) + 'px';
|
|
bulletHole.style.top = (clickY - 4) + 'px';
|
|
bulletHole.style.zIndex = '1'; // Below targets
|
|
gameContainer.appendChild(bulletHole);
|
|
|
|
// Remove bullet hole after some time
|
|
setTimeout(() => {
|
|
bulletHole.remove();
|
|
}, 10000);
|
|
|
|
let targetHit = false;
|
|
|
|
// Check for hit targets
|
|
for (let i = targets.length - 1; i >= 0; i--) {
|
|
const target = targets[i];
|
|
const targetCenterX = target.x + 35;
|
|
const targetCenterY = target.y + 35;
|
|
|
|
// Check if shot hit the target (circle collision)
|
|
const distance = Math.sqrt(
|
|
Math.pow(clickX - targetCenterX, 2) +
|
|
Math.pow(clickY - targetCenterY, 2)
|
|
);
|
|
|
|
// Determine if it's a headshot (hit near center)
|
|
const isHeadshot = distance < 15;
|
|
|
|
if (distance < 35) {
|
|
targetHit = true;
|
|
showHitMarker();
|
|
|
|
// Calculate damage based on distance from center
|
|
let damage = isHeadshot ? 100 : 25 + (35 - distance);
|
|
|
|
// Apply damage
|
|
target.health -= damage;
|
|
|
|
// Update health bar
|
|
target.healthBar.style.width = Math.max(0, target.health) + '%';
|
|
|
|
// Show damage indicator
|
|
const damageText = document.createElement('div');
|
|
damageText.className = 'damage-indicator';
|
|
damageText.textContent = Math.round(damage);
|
|
damageText.style.left = (target.x + 35) + 'px';
|
|
damageText.style.top = (target.y - 10) + 'px';
|
|
gameContainer.appendChild(damageText);
|
|
|
|
// Animate damage text
|
|
setTimeout(() => {
|
|
damageText.style.opacity = '0';
|
|
damageText.style.transform = 'translateY(-20px)';
|
|
setTimeout(() => {
|
|
damageText.remove();
|
|
}, 1000);
|
|
}, 10);
|
|
|
|
// Target is destroyed
|
|
if (target.health <= 0) {
|
|
// Calculate score based on target type
|
|
let pointsGained = 0;
|
|
|
|
if (target.type === 1) { // Red target (correct)
|
|
pointsGained = isHeadshot ? 30 : 10;
|
|
currentStreak++;
|
|
|
|
// Update streak counter
|
|
document.getElementById('current-streak').textContent = currentStreak;
|
|
|
|
// Update headshot counter if applicable
|
|
if (isHeadshot) {
|
|
headshotCount++;
|
|
document.getElementById('headshots').textContent = headshotCount;
|
|
}
|
|
|
|
// Bonus for streak
|
|
if (currentStreak > 3) {
|
|
pointsGained += 5 * Math.floor(currentStreak / 3);
|
|
}
|
|
} else if (target.type === 2) { // Blue target (wrong)
|
|
pointsGained = -5;
|
|
currentStreak = 0;
|
|
document.getElementById('current-streak').textContent = currentStreak;
|
|
} else if (target.type === 3) { // Hasbullah target (big penalty)
|
|
pointsGained = -20;
|
|
currentStreak = 0;
|
|
document.getElementById('current-streak').textContent = currentStreak;
|
|
|
|
// Flash screen red for hitting Hasbullah
|
|
const damageFlash = document.getElementById('damage-flash');
|
|
damageFlash.style.opacity = '1';
|
|
clearTimeout(damageFlashTimeout);
|
|
damageFlashTimeout = setTimeout(() => {
|
|
damageFlash.style.opacity = '0';
|
|
}, 200);
|
|
}
|
|
|
|
// Add points
|
|
score += pointsGained;
|
|
scoreElement.textContent = score;
|
|
|
|
// Show score popup
|
|
showScorePopup(target.x + 35, target.y, pointsGained, isHeadshot);
|
|
|
|
// Visual feedback
|
|
createExplosion(target.x, target.y);
|
|
|
|
// Remove the target
|
|
target.element.remove();
|
|
targets.splice(i, 1);
|
|
}
|
|
|
|
// Only hit one target per shot
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Handle keyboard controls
|
|
document.addEventListener('keydown', (e) => {
|
|
if (!gameActive) return;
|
|
|
|
// 'R' key for reload
|
|
if (e.key === 'r' || e.key === 'R') {
|
|
reload();
|
|
}
|
|
});
|
|
|
|
// Start and restart buttons
|
|
startGameButton.addEventListener('click', () => {
|
|
startGame();
|
|
requestAnimationFrame(updateTargets);
|
|
|
|
// Start music when game starts
|
|
if (backgroundMusic.paused) {
|
|
playAudio();
|
|
}
|
|
});
|
|
|
|
restartGameButton.addEventListener('click', () => {
|
|
startGame();
|
|
requestAnimationFrame(updateTargets);
|
|
|
|
// Make sure music is playing
|
|
if (backgroundMusic.paused) {
|
|
playAudio();
|
|
}
|
|
});
|
|
|
|
// Preload images
|
|
function preloadImages() {
|
|
targetImages.forEach(src => {
|
|
const img = new Image();
|
|
img.src = src;
|
|
});
|
|
|
|
// Preload Hasbullah
|
|
const hasbullahImg = new Image();
|
|
hasbullahImg.src = hasbullahImage;
|
|
}
|
|
|
|
// Initialize game
|
|
preloadImages();
|
|
updateAmmoDisplay();
|
|
});
|
|
|
|
// Preload audio
|
|
backgroundMusic.load();
|
|
gunshotSound.load();
|
|
emptyClickSound.load();
|
|
reloadSound.load();
|
|
|
|
// Display error message if music fails to load
|
|
backgroundMusic.addEventListener('error', function() {
|
|
console.error('Error loading music file');
|
|
musicToggle.innerHTML = '<span class="vinyl-ready">❌</span>';
|
|
musicToggle.title = "Music could not be loaded";
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>' |