washington-s-crossing / index.html
Hypergenius's picture
Add 3 files
0c72638 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Washington's Crossing Simulator</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.river {
background: linear-gradient(to bottom, #1a237e, #0d47a1);
position: relative;
overflow: hidden;
}
.wave {
position: absolute;
width: 100%;
height: 20px;
background: rgba(255, 255, 255, 0.1);
animation: wave 3s infinite linear;
}
.wave:nth-child(2) {
top: 20px;
animation-delay: 0.5s;
}
.wave:nth-child(3) {
top: 40px;
animation-delay: 1s;
}
@keyframes wave {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
.boat {
transition: all 0.5s ease;
}
.fade-in {
animation: fadeIn 1s;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.snowflake {
position: absolute;
background-color: white;
border-radius: 50%;
pointer-events: none;
animation: fall linear infinite;
}
@keyframes fall {
to { transform: translateY(100vh); }
}
.ice-floe {
position: absolute;
background-color: rgba(255, 255, 255, 0.7);
border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
pointer-events: none;
}
.patrol {
position: absolute;
width: 40px;
height: 20px;
background-color: #8B4513;
border-radius: 5px;
pointer-events: none;
}
.achievement-badge {
transition: all 0.3s ease;
}
.achievement-badge:hover {
transform: scale(1.1);
}
.secret-found {
animation: pulse 1s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.timer-bar {
transition: width 1s linear;
}
.glow {
animation: glow 2s infinite alternate;
}
@keyframes glow {
from { box-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #e60073, 0 0 20px #e60073; }
to { box-shadow: 0 0 10px #fff, 0 0 20px #ff4da6, 0 0 30px #ff4da6, 0 0 40px #ff4da6; }
}
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen flex flex-col items-center justify-center p-4">
<div id="game-container" class="w-full max-w-4xl bg-gray-800 rounded-xl shadow-2xl overflow-hidden fade-in">
<!-- Title Screen -->
<div id="title-screen" class="p-8 text-center">
<h1 class="text-4xl md:text-6xl font-bold mb-6 text-yellow-400">WASHINGTON'S CROSSING</h1>
<div class="river h-32 my-8 rounded-lg relative">
<div class="wave"></div>
<div class="wave"></div>
<div class="wave"></div>
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Gilbert_Stuart_Williamstown_Portrait_of_George_Washington.jpg/800px-Gilbert_Stuart_Williamstown_Portrait_of_George_Washington.jpg"
class="h-24 absolute left-1/2 -translate-x-1/2 -top-4 rounded-full border-4 border-yellow-500 shadow-lg">
</div>
<p class="text-xl mb-8">December 25-26, 1776. Lead your troops across the Delaware River under cover of darkness to surprise the Hessians at Trenton.</p>
<div class="flex flex-col space-y-4 max-w-xs mx-auto">
<button onclick="startGame('easy')" class="bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-6 rounded-lg transition transform hover:scale-105">
Easy Crossing
</button>
<button onclick="startGame('medium')" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-3 px-6 rounded-lg transition transform hover:scale-105">
Standard Challenge
</button>
<button onclick="startGame('hard')" class="bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-6 rounded-lg transition transform hover:scale-105">
Hardcore Mode
</button>
<button onclick="showInstructions()" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg transition transform hover:scale-105">
Instructions
</button>
<button onclick="showAchievements()" class="bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 px-6 rounded-lg transition transform hover:scale-105">
Achievements
</button>
</div>
</div>
<!-- Instructions Screen -->
<div id="instructions-screen" class="hidden p-8">
<h2 class="text-3xl font-bold mb-6 text-yellow-400">How to Cross Like Washington</h2>
<div class="space-y-4 mb-8">
<div class="flex items-start">
<div class="bg-yellow-500 text-yellow-900 font-bold rounded-full w-8 h-8 flex items-center justify-center mr-4 mt-1 flex-shrink-0">1</div>
<p>Choose your difficulty level - easier modes have better weather and fewer patrols.</p>
</div>
<div class="flex items-start">
<div class="bg-yellow-500 text-yellow-900 font-bold rounded-full w-8 h-8 flex items-center justify-center mr-4 mt-1 flex-shrink-0">2</div>
<p>Select your crossing strategy - more boats are faster but more visible, night crossings are stealthier.</p>
</div>
<div class="flex items-start">
<div class="bg-yellow-500 text-yellow-900 font-bold rounded-full w-8 h-8 flex items-center justify-center mr-4 mt-1 flex-shrink-0">3</div>
<p>Navigate the river - watch for ice floes and British patrols. You must respond to events quickly!</p>
</div>
<div class="flex items-start">
<div class="bg-yellow-500 text-yellow-900 font-bold rounded-full w-8 h-8 flex items-center justify-center mr-4 mt-1 flex-shrink-0">4</div>
<p>Make tactical decisions during the crossing to avoid detection. Some choices may unlock secret achievements!</p>
</div>
<div class="flex items-start">
<div class="bg-yellow-500 text-yellow-900 font-bold rounded-full w-8 h-8 flex items-center justify-center mr-4 mt-1 flex-shrink-0">5</div>
<p>Watch the timer during events - if it runs out, you'll automatically fail the event!</p>
</div>
</div>
<button onclick="hideInstructions()" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-6 rounded-lg">
Back to Title
</button>
</div>
<!-- Achievements Screen -->
<div id="achievements-screen" class="hidden p-8">
<h2 class="text-3xl font-bold mb-6 text-yellow-400">Your Achievements</h2>
<div id="achievements-container" class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
<!-- Achievements will be added here dynamically -->
</div>
<div class="mt-6 p-4 bg-gray-700 rounded-lg">
<h3 class="text-xl font-semibold mb-2">Secret Achievements</h3>
<p class="text-gray-400">Some achievements are hidden! Discover them through special actions during your crossings.</p>
<div id="secret-achievements-container" class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
<!-- Secret achievements will be added here dynamically -->
</div>
</div>
<button onclick="hideAchievements()" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-6 rounded-lg mt-6">
Back to Title
</button>
</div>
<!-- Strategy Selection Screen -->
<div id="strategy-screen" class="hidden p-8">
<h2 class="text-3xl font-bold mb-6 text-yellow-400">Plan Your Crossing</h2>
<div id="weather-display" class="mb-6 p-4 rounded-lg bg-gray-700">
<h3 class="text-xl font-semibold mb-2">Weather Conditions:</h3>
<p id="weather-text"></p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<div class="bg-gray-700 p-4 rounded-lg">
<h3 class="text-xl font-semibold mb-3">Crossing Time</h3>
<div class="space-y-3">
<label class="flex items-center space-x-3">
<input type="radio" name="time" value="dusk" class="form-radio text-yellow-500" checked>
<span>Dusk (Moderate visibility, some patrols)</span>
</label>
<label class="flex items-center space-x-3">
<input type="radio" name="time" value="midnight" class="form-radio text-blue-500">
<span>Midnight (Best stealth, but colder)</span>
</label>
<label class="flex items-center space-x-3">
<input type="radio" name="time" value="dawn" class="form-radio text-red-500">
<span>Dawn (Worst stealth, but warmer)</span>
</label>
</div>
</div>
<div class="bg-gray-700 p-4 rounded-lg">
<h3 class="text-xl font-semibold mb-3">Boat Strategy</h3>
<div class="space-y-3">
<label class="flex items-center space-x-3">
<input type="radio" name="boats" value="few" class="form-radio text-green-500" checked>
<span>Few boats (Slow but stealthy)</span>
</label>
<label class="flex items-center space-x-3">
<input type="radio" name="boats" value="moderate" class="form-radio text-yellow-500">
<span>Moderate boats (Balanced)</span>
</label>
<label class="flex items-center space-x-3">
<input type="radio" name="boats" value="many" class="form-radio text-red-500">
<span>Many boats (Fast but visible)</span>
</label>
</div>
</div>
</div>
<div class="bg-gray-700 p-4 rounded-lg mb-8">
<h3 class="text-xl font-semibold mb-3">Special Options</h3>
<div class="space-y-3">
<label class="flex items-center space-x-3">
<input type="checkbox" id="secret-route" class="form-checkbox text-purple-500">
<span>Attempt secret route (Risky but potentially rewarding)</span>
</label>
</div>
</div>
<button onclick="beginCrossing()" class="bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-8 rounded-lg text-xl">
Begin Crossing
</button>
</div>
<!-- Crossing Screen -->
<div id="crossing-screen" class="hidden relative">
<div id="river-container" class="river h-64 w-full relative overflow-hidden">
<!-- Boat will be positioned here -->
<div id="boat" class="boat absolute bottom-4 left-8 w-16 h-16 bg-gray-300 rounded-lg">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Gilbert_Stuart_Williamstown_Portrait_of_George_Washington.jpg/800px-Gilbert_Stuart_Williamstown_Portrait_of_George_Washington.jpg"
class="h-10 absolute -top-4 left-1/2 -translate-x-1/2 rounded-full border-2 border-yellow-500">
</div>
<!-- Ice floes and obstacles will be added dynamically -->
</div>
<div class="bg-gray-800 p-4 flex justify-between items-center">
<div id="progress-container" class="w-full bg-gray-700 rounded-full h-4">
<div id="progress-bar" class="bg-yellow-500 h-4 rounded-full" style="width: 0%"></div>
</div>
<div id="distance-text" class="ml-4 font-bold">0%</div>
</div>
<div id="event-display" class="bg-gray-700 p-4 hidden">
<div class="flex justify-between items-center mb-2">
<h3 class="font-bold text-lg" id="event-title">Event Occurred!</h3>
<div class="flex items-center">
<div class="w-24 h-2 bg-gray-600 rounded-full mr-2">
<div id="event-timer" class="timer-bar h-2 bg-red-500 rounded-full" style="width: 100%"></div>
</div>
<span id="event-time-remaining" class="text-sm">5s</span>
</div>
</div>
<p id="event-description"></p>
<div id="event-choices" class="mt-4 space-y-2"></div>
</div>
<div id="status-display" class="bg-gray-900 p-4 grid grid-cols-4 gap-4 text-center">
<div>
<div class="text-sm text-gray-400">Visibility</div>
<div id="visibility-value" class="font-bold text-lg">Medium</div>
</div>
<div>
<div class="text-sm text-gray-400">Alert Level</div>
<div id="alert-value" class="font-bold text-lg">Low</div>
</div>
<div>
<div class="text-sm text-gray-400">Troop Morale</div>
<div id="morale-value" class="font-bold text-lg">High</div>
</div>
<div>
<div class="text-sm text-gray-400">Troops</div>
<div id="troops-value" class="font-bold text-lg">2400</div>
</div>
</div>
</div>
<!-- Results Screen -->
<div id="results-screen" class="hidden p-8 text-center">
<h2 id="result-title" class="text-4xl font-bold mb-6 text-yellow-400">Crossing Complete!</h2>
<div id="result-icon" class="text-8xl mb-6">🎖️</div>
<p id="result-description" class="text-xl mb-8">You successfully crossed the Delaware River!</p>
<div id="new-achievements" class="mb-8 hidden">
<h3 class="text-2xl font-semibold mb-4 text-yellow-400">New Achievements Unlocked!</h3>
<div id="achievements-earned" class="flex flex-wrap justify-center gap-4">
<!-- Achievements will be added here -->
</div>
</div>
<div id="stats-display" class="bg-gray-700 p-6 rounded-lg mb-8 text-left max-w-md mx-auto">
<h3 class="text-2xl font-semibold mb-4">Crossing Statistics</h3>
<div class="grid grid-cols-2 gap-4">
<div>Time Taken:</div>
<div id="stat-time" class="font-bold">12 hours</div>
<div>Troops Lost:</div>
<div id="stat-troops" class="font-bold">2</div>
<div>Alert Level:</div>
<div id="stat-alert" class="font-bold">Medium</div>
<div>Difficulty:</div>
<div id="stat-difficulty" class="font-bold">Standard</div>
<div>Morale:</div>
<div id="stat-morale" class="font-bold">High</div>
<div>Score:</div>
<div id="stat-score" class="font-bold">850</div>
</div>
</div>
<button onclick="returnToTitle()" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-lg text-xl">
Try Again
</button>
</div>
</div>
<!-- Achievement Toast Notification -->
<div id="achievement-toast" class="fixed bottom-4 right-4 bg-purple-700 text-white p-4 rounded-lg shadow-lg hidden max-w-xs transform translate-x-full transition-transform duration-300">
<div class="flex items-center">
<div class="mr-3 text-2xl">
<i class="fas fa-trophy"></i>
</div>
<div>
<div class="font-bold" id="toast-title">Achievement Unlocked!</div>
<div id="toast-description">Description here</div>
</div>
</div>
</div>
<script>
// Game state variables
let gameState = {
difficulty: 'medium',
crossingTime: 'dusk',
boatStrategy: 'few',
secretRoute: false,
progress: 0,
visibility: 50,
alertLevel: 20,
morale: 80,
troops: 2400,
events: [],
iceFloes: [],
patrols: [],
startTime: null,
endTime: null,
eventCooldown: 0,
eventTimer: null,
eventTimeLeft: 5,
achievements: [],
secretsFound: [],
score: 0
};
// Achievement database
const achievements = [
{
id: 'first_crossing',
title: 'First Crossing',
description: 'Complete your first crossing of the Delaware',
icon: 'fa-flag',
color: 'bg-blue-500',
earned: false,
secret: false
},
{
id: 'perfect_crossing',
title: 'Perfect Crossing',
description: 'Cross without losing any troops',
icon: 'fa-star',
color: 'bg-yellow-500',
earned: false,
secret: false
},
{
id: 'stealth_master',
title: 'Stealth Master',
description: 'Complete a crossing with alert level below 30',
icon: 'fa-user-secret',
color: 'bg-green-500',
earned: false,
secret: false
},
{
id: 'hardcore_victory',
title: 'Hardcore Victory',
description: 'Complete a crossing on Hardcore difficulty',
icon: 'fa-skull',
color: 'bg-red-500',
earned: false,
secret: false
},
{
id: 'midnight_crossing',
title: 'Midnight Crossing',
description: 'Complete a crossing starting at midnight',
icon: 'fa-moon',
color: 'bg-indigo-500',
earned: false,
secret: false
},
{
id: 'frozen_fingers',
title: 'Frozen Fingers',
description: 'Complete a crossing with morale below 30',
icon: 'fa-snowflake',
color: 'bg-blue-300',
earned: false,
secret: false
},
{
id: 'speed_demon',
title: 'Speed Demon',
description: 'Complete a crossing in under 30 seconds',
icon: 'fa-bolt',
color: 'bg-yellow-400',
earned: false,
secret: false
},
{
id: 'washington_reborn',
title: 'Washington Reborn',
description: 'Complete all standard achievements',
icon: 'fa-crown',
color: 'bg-purple-500',
earned: false,
secret: false
},
// Secret achievements
{
id: 'secret_route',
title: 'Secret Pathfinder',
description: 'Discover and use the secret route',
icon: 'fa-map',
color: 'bg-purple-600',
earned: false,
secret: true
},
{
id: 'full_alert',
title: 'Wanted: Dead or Alive',
description: 'Get caught with maximum alert level',
icon: 'fa-bullhorn',
color: 'bg-red-600',
earned: false,
secret: true
},
{
id: 'ice_breaker',
title: 'Ice Breaker',
description: 'Push through 5 ice floes successfully',
icon: 'fa-icicles',
color: 'bg-blue-400',
earned: false,
secret: true
},
{
id: 'patrol_baiter',
title: 'Patrol Baiter',
description: 'Get spotted by 3 patrols but still complete the crossing',
icon: 'fa-binoculars',
color: 'bg-yellow-600',
earned: false,
secret: true
},
{
id: 'last_minute',
title: 'Last Minute Hero',
description: 'Win an event with less than 1 second remaining',
icon: 'fa-clock',
color: 'bg-red-500',
earned: false,
secret: true
}
];
// Weather conditions for different difficulties
const weatherConditions = {
easy: {
description: "Cold but clear night with minimal wind. Good visibility but also easier for patrols to spot you.",
wind: 10,
temperature: 25, // Fahrenheit
ice: 3
},
medium: {
description: "Snowing with moderate wind. Reduced visibility helps stealth but makes navigation harder.",
wind: 20,
temperature: 15,
ice: 6
},
hard: {
description: "Blizzard conditions with high winds. Very difficult navigation but excellent cover.",
wind: 35,
temperature: 5,
ice: 10
}
};
// Event database
const events = [
{
name: "Ice Floe Ahead",
description: "Your scouts report a large ice floe directly in your path. Do you want to go around it or try to push through?",
conditions: (state) => state.progress > 10 && state.progress < 90 && Math.random() < 0.3,
choices: [
{
text: "Go around (slower but safer)",
effect: (state) => {
state.progress -= 5;
state.morale -= 5;
return "You successfully navigated around the ice floe, but it cost you time and chilled your troops.";
}
},
{
text: "Push through (faster but risky)",
effect: (state) => {
const success = Math.random() > 0.3;
if (success) {
state.progress += 10;
checkAchievementProgress('ice_breaker', state);
return "Your men pushed through the ice with minimal damage. The crossing continues!";
} else {
state.troops -= Math.floor(Math.random() * 50) + 10;
state.morale -= 15;
return "The ice damaged several boats and some men fell into the freezing water. You lost troops in the crossing.";
}
}
}
]
},
{
name: "British Patrol Spotted",
description: "A British patrol boat has been spotted in the distance. They haven't seen you yet. What do you do?",
conditions: (state) => state.progress > 30 && state.progress < 70 && Math.random() < 0.4,
choices: [
{
text: "Stop all movement and hide",
effect: (state) => {
state.alertLevel += 5;
const detected = Math.random() < 0.2;
if (detected) {
state.alertLevel = 100;
checkAchievementProgress('full_alert', state);
checkAchievementProgress('patrol_baiter', state);
return "The patrol spotted you despite your efforts! The alarm has been raised!";
} else {
return "You remained perfectly still and the patrol passed by without noticing you.";
}
}
},
{
text: "Continue quietly at reduced speed",
effect: (state) => {
state.alertLevel += 15;
state.progress += 2;
return "You continued moving slowly. The patrol seemed to notice some movement but couldn't identify you.";
}
},
{
text: "Full speed ahead!",
effect: (state) => {
state.alertLevel += 40;
state.progress += 10;
const detected = Math.random() < 0.7;
if (detected) {
state.alertLevel = 100;
checkAchievementProgress('full_alert', state);
checkAchievementProgress('patrol_baiter', state);
return "The patrol definitely saw you! They're raising the alarm!";
} else {
return "Against all odds, you sped past the patrol without being detected!";
}
}
}
]
},
{
name: "Troop Morale Crisis",
description: "Your men are freezing and exhausted. Some are talking about turning back.",
conditions: (state) => state.morale < 50 && Math.random() < 0.5,
choices: [
{
text: "Give an inspiring speech",
effect: (state) => {
const success = Math.random() > 0.3;
if (success) {
state.morale += 30;
return '"These are the times that try men\'s souls..." Your speech rallied the troops!';
} else {
state.morale -= 10;
return "Your words fell flat. The men remain discouraged.";
}
}
},
{
text: "Promise extra rations",
effect: (state) => {
state.morale += 15;
return "The promise of extra food lifted spirits somewhat, but you'll need to deliver later.";
}
},
{
text: "Threaten punishment",
effect: (state) => {
state.morale -= 20;
if (state.morale <= 0) {
state.morale = 0;
checkAchievementProgress('frozen_fingers', state);
}
return "The threats worked to keep order, but the men resent you for it.";
}
}
]
},
{
name: "Navigation Error",
description: "Your navigator reports you've drifted off course in the storm.",
conditions: (state) => state.progress > 20 && state.progress < 80 && Math.random() < 0.25,
choices: [
{
text: "Correct course immediately",
effect: (state) => {
state.progress -= 8;
state.morale -= 5;
return "You corrected course but lost valuable time doing so.";
}
},
{
text: "Press on and adjust gradually",
effect: (state) => {
const success = Math.random() > 0.5;
if (success) {
state.progress += 5;
return "Your gradual correction worked! You're back on course.";
} else {
state.progress -= 15;
state.morale -= 10;
return "The error compounded and you're now further off course than before!";
}
}
}
]
},
{
name: "Secret Route Discovery",
description: "Your scouts report finding a hidden path through the ice. It's risky but could save time.",
conditions: (state) => state.secretRoute && state.progress > 40 && state.progress < 60 && Math.random() < 0.5,
choices: [
{
text: "Take the secret route",
effect: (state) => {
const success = Math.random() > 0.4;
if (success) {
state.progress += 25;
unlockAchievement('secret_route', state);
return "The secret route worked perfectly! You've gained significant ground.";
} else {
state.troops -= Math.floor(Math.random() * 200) + 50;
state.morale -= 20;
return "The route was a trap! You lost many troops in the ambush.";
}
}
},
{
text: "Stick to the original plan",
effect: (state) => {
state.progress += 2;
return "You decided not to risk the unknown path. Progress is slow but steady.";
}
}
]
}
];
// Start game with selected difficulty
function startGame(difficulty) {
gameState = {
difficulty,
crossingTime: 'dusk',
boatStrategy: 'few',
secretRoute: document.getElementById('secret-route').checked,
progress: 0,
visibility: 50,
alertLevel: 20,
morale: 80,
troops: 2400,
events: [],
iceFloes: [],
patrols: [],
startTime: null,
endTime: null,
eventCooldown: 0,
eventTimer: null,
eventTimeLeft: 5,
achievements: [],
secretsFound: [],
score: 0
};
document.getElementById('title-screen').classList.add('hidden');
document.getElementById('strategy-screen').classList.remove('hidden');
// Set weather display
const weather = weatherConditions[difficulty];
document.getElementById('weather-text').textContent = weather.description;
// Reset secret route checkbox
document.getElementById('secret-route').checked = false;
}
// Show instructions
function showInstructions() {
document.getElementById('title-screen').classList.add('hidden');
document.getElementById('instructions-screen').classList.remove('hidden');
}
// Hide instructions
function hideInstructions() {
document.getElementById('instructions-screen').classList.add('hidden');
document.getElementById('title-screen').classList.remove('hidden');
}
// Show achievements
function showAchievements() {
document.getElementById('title-screen').classList.add('hidden');
document.getElementById('achievements-screen').classList.remove('hidden');
// Load achievements
loadAchievements();
}
// Hide achievements
function hideAchievements() {
document.getElementById('achievements-screen').classList.add('hidden');
document.getElementById('title-screen').classList.remove('hidden');
}
// Load achievements from localStorage
function loadAchievements() {
const savedAchievements = localStorage.getItem('achievements');
const savedSecrets = localStorage.getItem('secrets');
if (savedAchievements) {
gameState.achievements = JSON.parse(savedAchievements);
}
if (savedSecrets) {
gameState.secretsFound = JSON.parse(savedSecrets);
}
// Update achievements display
updateAchievementsDisplay();
}
// Update achievements display
function updateAchievementsDisplay() {
const container = document.getElementById('achievements-container');
const secretContainer = document.getElementById('secret-achievements-container');
container.innerHTML = '';
secretContainer.innerHTML = '';
achievements.forEach(ach => {
const earned = gameState.achievements.includes(ach.id) ||
(ach.secret && gameState.secretsFound.includes(ach.id));
const achievementDiv = document.createElement('div');
achievementDiv.className = `achievement-badge p-3 rounded-lg flex items-center ${earned ? ach.color : 'bg-gray-600'} ${earned ? '' : 'opacity-60'}`;
achievementDiv.innerHTML = `
<div class="mr-3 text-2xl">
<i class="fas ${ach.icon}"></i>
</div>
<div>
<div class="font-bold">${ach.title}</div>
<div class="text-sm">${earned ? ach.description : (ach.secret ? '???' : ach.description)}</div>
${earned ? '<div class="text-xs mt-1"><i class="fas fa-check"></i> Unlocked</div>' : ''}
</div>
`;
if (ach.secret) {
if (earned) {
secretContainer.appendChild(achievementDiv);
} else {
// Show locked secret achievements as unknown
const secretDiv = document.createElement('div');
secretDiv.className = 'achievement-badge p-3 rounded-lg flex items-center bg-gray-700 opacity-60';
secretDiv.innerHTML = `
<div class="mr-3 text-2xl">
<i class="fas fa-lock"></i>
</div>
<div>
<div class="font-bold">Secret Achievement</div>
<div class="text-sm">???</div>
</div>
`;
secretContainer.appendChild(secretDiv);
}
} else {
container.appendChild(achievementDiv);
}
});
}
// Save achievements to localStorage
function saveAchievements() {
localStorage.setItem('achievements', JSON.stringify(gameState.achievements));
localStorage.setItem('secrets', JSON.stringify(gameState.secretsFound));
}
// Unlock an achievement
function unlockAchievement(id, state) {
const achievement = achievements.find(a => a.id === id);
if (!achievement) return;
// Check if already unlocked
if ((!achievement.secret && state.achievements.includes(id)) ||
(achievement.secret && state.secretsFound.includes(id))) {
return;
}
// Add to appropriate list
if (achievement.secret) {
state.secretsFound.push(id);
} else {
state.achievements.push(id);
}
// Save to localStorage
saveAchievements();
// Show toast notification
showAchievementToast(achievement);
// Check for Washington Reborn achievement (all standard achievements)
if (!achievement.secret) {
const standardAchievements = achievements.filter(a => !a.secret && a.id !== 'washington_reborn');
const hasAll = standardAchievements.every(a => state.achievements.includes(a.id));
if (hasAll && !state.achievements.includes('washington_reborn')) {
unlockAchievement('washington_reborn', state);
}
}
}
// Check achievement progress (for achievements that require multiple actions)
function checkAchievementProgress(id, state) {
// For now, just unlock immediately - could be enhanced for multi-step achievements
unlockAchievement(id, state);
}
// Show achievement toast notification
function showAchievementToast(achievement) {
const toast = document.getElementById('achievement-toast');
const title = document.getElementById('toast-title');
const desc = document.getElementById('toast-description');
title.textContent = achievement.title;
desc.textContent = achievement.description;
toast.classList.remove('hidden');
toast.classList.remove('translate-x-full');
// Add glow effect for secret achievements
if (achievement.secret) {
toast.classList.add('glow');
} else {
toast.classList.remove('glow');
}
// Hide after 5 seconds
setTimeout(() => {
toast.classList.add('translate-x-full');
setTimeout(() => toast.classList.add('hidden'), 300);
}, 5000);
}
// Begin the crossing
function beginCrossing() {
// Get selected strategy
gameState.crossingTime = document.querySelector('input[name="time"]:checked').value;
gameState.boatStrategy = document.querySelector('input[name="boats"]:checked').value;
gameState.secretRoute = document.getElementById('secret-route').checked;
// Adjust initial stats based on choices
if (gameState.crossingTime === 'midnight') {
gameState.visibility = 30;
gameState.morale -= 10; // colder
} else if (gameState.crossingTime === 'dawn') {
gameState.visibility = 70;
}
if (gameState.boatStrategy === 'moderate') {
// balanced
} else if (gameState.boatStrategy === 'many') {
gameState.visibility += 20;
}
// Set start time
gameState.startTime = new Date();
// Switch to crossing screen
document.getElementById('strategy-screen').classList.add('hidden');
document.getElementById('crossing-screen').classList.remove('hidden');
// Start game loop
gameLoop();
// Create snow effect if hard difficulty
if (gameState.difficulty === 'hard') {
createSnowEffect();
}
// Create ice floes
createIceFloes();
// Create patrols
createPatrols();
}
// Create ice floes
function createIceFloes() {
const riverContainer = document.getElementById('river-container');
const weather = weatherConditions[gameState.difficulty];
for (let i = 0; i < weather.ice; i++) {
const ice = document.createElement('div');
ice.classList.add('ice-floe');
const size = Math.random() * 40 + 20;
ice.style.width = `${size}px`;
ice.style.height = `${size}px`;
ice.style.left = `${Math.random() * 90 + 5}%`;
ice.style.top = `${Math.random() * 60 + 10}%`;
riverContainer.appendChild(ice);
}
}
// Create patrols
function createPatrols() {
const riverContainer = document.getElementById('river-container');
const patrolCount = gameState.difficulty === 'easy' ? 2 :
gameState.difficulty === 'medium' ? 4 : 6;
for (let i = 0; i < patrolCount; i++) {
const patrol = document.createElement('div');
patrol.classList.add('patrol');
patrol.style.left = `${Math.random() * 90 + 5}%`;
patrol.style.top = `${Math.random() * 60 + 10}%`;
// Add animation
const duration = Math.random() * 10 + 10;
patrol.style.animation = `wave ${duration}s infinite linear`;
riverContainer.appendChild(patrol);
}
}
// Game loop
function gameLoop() {
// Update progress
const speed = getCrossingSpeed();
gameState.progress += speed;
// Update UI
updateUI();
// Check for events
checkForEvents();
// Update cooldown
if (gameState.eventCooldown > 0) {
gameState.eventCooldown--;
}
// Check for game over conditions
if (gameState.progress >= 100) {
endGame(true);
return;
}
if (gameState.alertLevel >= 100) {
endGame(false, "The British have spotted you! The element of surprise is lost.");
return;
}
if (gameState.morale <= 0) {
endGame(false, "Your troops mutinied and refused to continue!");
return;
}
if (gameState.troops <= 0) {
endGame(false, "You've lost all your troops! The crossing has failed.");
return;
}
// Continue loop
setTimeout(gameLoop, 200);
}
// Get crossing speed based on choices
function getCrossingSpeed() {
let speed = 0.5;
// Adjust for boat strategy
if (gameState.boatStrategy === 'moderate') {
speed = 0.8;
} else if (gameState.boatStrategy === 'many') {
speed = 1.2;
}
// Adjust for weather
const weather = weatherConditions[gameState.difficulty];
speed *= 1 - (weather.wind / 100);
// Adjust for morale
speed *= gameState.morale / 100;
// Random variation
speed *= (0.9 + Math.random() * 0.2);
return speed;
}
// Update UI elements
function updateUI() {
// Update progress bar
const progressBar = document.getElementById('progress-bar');
const clampedProgress = Math.min(100, Math.max(0, gameState.progress));
progressBar.style.width = `${clampedProgress}%`;
document.getElementById('distance-text').textContent = `${Math.floor(clampedProgress)}%`;
// Update boat position
const boat = document.getElementById('boat');
const riverWidth = document.getElementById('river-container').offsetWidth;
const boatPosition = (riverWidth - 64) * (clampedProgress / 100);
boat.style.left = `${boatPosition}px`;
// Update status values
document.getElementById('visibility-value').textContent =
gameState.visibility < 40 ? 'Low' :
gameState.visibility < 70 ? 'Medium' : 'High';
document.getElementById('alert-value').textContent =
gameState.alertLevel < 40 ? 'Low' :
gameState.alertLevel < 70 ? 'Medium' : 'High';
document.getElementById('morale-value').textContent =
gameState.morale < 40 ? 'Low' :
gameState.morale < 70 ? 'Medium' : 'High';
document.getElementById('troops-value').textContent = gameState.troops;
// Color code values
document.getElementById('visibility-value').className = 'font-bold text-lg ' +
(gameState.visibility < 40 ? 'text-green-500' :
gameState.visibility < 70 ? 'text-yellow-500' : 'text-red-500');
document.getElementById('alert-value').className = 'font-bold text-lg ' +
(gameState.alertLevel < 40 ? 'text-green-500' :
gameState.alertLevel < 70 ? 'text-yellow-500' : 'text-red-500');
document.getElementById('morale-value').className = 'font-bold text-lg ' +
(gameState.morale < 40 ? 'text-red-500' :
gameState.morale < 70 ? 'text-yellow-500' : 'text-green-500');
}
// Check for random events
function checkForEvents() {
if (gameState.eventCooldown > 0) return;
// Check each event to see if it should trigger
for (const event of events) {
if (event.conditions(gameState)) {
triggerEvent(event);
gameState.eventCooldown = 20; // Set cooldown
return;
}
}
}
// Trigger an event
function triggerEvent(event) {
const eventDisplay = document.getElementById('event-display');
document.getElementById('event-title').textContent = event.name;
document.getElementById('event-description').textContent = event.description;
// Clear previous choices
const choicesContainer = document.getElementById('event-choices');
choicesContainer.innerHTML = '';
// Start timer
gameState.eventTimeLeft = 5;
updateEventTimer();
if (gameState.eventTimer) {
clearInterval(gameState.eventTimer);
}
gameState.eventTimer = setInterval(() => {
gameState.eventTimeLeft -= 0.1;
updateEventTimer();
if (gameState.eventTimeLeft <= 0) {
clearInterval(gameState.eventTimer);
eventTimeout(event);
}
}, 100);
// Add new choices
event.choices.forEach((choice, index) => {
const button = document.createElement('button');
button.textContent = choice.text;
button.className = 'w-full bg-gray-600 hover:bg-gray-500 text-white font-bold py-2 px-4 rounded-lg transition';
button.onclick = () => {
clearInterval(gameState.eventTimer);
const result = choice.effect(gameState);
document.getElementById('event-description').textContent = result;
// Remove all buttons except the one clicked
Array.from(choicesContainer.children).forEach((child, i) => {
if (i !== index) child.remove();
});
// Add continue button
const continueButton = document.createElement('button');
continueButton.textContent = 'Continue';
continueButton.className = 'w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg transition mt-2';
continueButton.onclick = () => {
eventDisplay.classList.add('hidden');
updateUI();
};
choicesContainer.appendChild(continueButton);
};
choicesContainer.appendChild(button);
});
eventDisplay.classList.remove('hidden');
}
// Update event timer display
function updateEventTimer() {
const timerBar = document.getElementById('event-timer');
const timeText = document.getElementById('event-time-remaining');
const percentage = Math.max(0, (gameState.eventTimeLeft / 5) * 100);
timerBar.style.width = `${percentage}%`;
timeText.textContent = `${gameState.eventTimeLeft.toFixed(1)}s`;
// Change color based on time remaining
if (gameState.eventTimeLeft < 1) {
timerBar.className = 'timer-bar h-2 bg-red-700 rounded-full';
} else if (gameState.eventTimeLeft < 2) {
timerBar.className = 'timer-bar h-2 bg-red-500 rounded-full';
} else if (gameState.eventTimeLeft < 3) {
timerBar.className = 'timer-bar h-2 bg-yellow-500 rounded-full';
} else {
timerBar.className = 'timer-bar h-2 bg-green-500 rounded-full';
}
}
// Handle event timeout
function eventTimeout(event) {
const eventDisplay = document.getElementById('event-display');
const choicesContainer = document.getElementById('event-choices');
// Default negative outcome for timeout
let result = "You hesitated too long! ";
// Random negative effect
const effect = Math.floor(Math.random() * 3);
switch(effect) {
case 0:
gameState.troops -= Math.floor(Math.random() * 100) + 50;
result += `The delay caused ${gameState.troops < 0 ? "many" : "some"} of your troops to be lost.`;
break;
case 1:
gameState.alertLevel += 30;
result += "The enemy spotted you during your indecision!";
break;
case 2:
gameState.morale -= 25;
result += "Your troops lost confidence in your leadership.";
break;
}
document.getElementById('event-description').textContent = result;
// Clear choices
choicesContainer.innerHTML = '';
// Add continue button
const continueButton = document.createElement('button');
continueButton.textContent = 'Continue';
continueButton.className = 'w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg transition mt-2';
continueButton.onclick = () => {
eventDisplay.classList.add('hidden');
updateUI();
};
choicesContainer.appendChild(continueButton);
// Check for last minute achievement if very close
if (gameState.eventTimeLeft > -0.1) {
checkAchievementProgress('last_minute', gameState);
}
}
// End the game
function endGame(success, message = null) {
gameState.endTime = new Date();
document.getElementById('crossing-screen').classList.add('hidden');
document.getElementById('results-screen').classList.remove('hidden');
const resultTitle = document.getElementById('result-title');
const resultIcon = document.getElementById('result-icon');
const resultDescription = document.getElementById('result-description');
const newAchievements = document.getElementById('new-achievements');
// Check for achievements
const newAchievementsEarned = [];
if (success) {
resultTitle.textContent = "Crossing Successful!";
resultIcon.textContent = "🎖️";
resultDescription.textContent = message || "You successfully crossed the Delaware River and surprised the Hessians at Trenton!";
// Check for achievements
unlockAchievement('first_crossing', gameState);
if (gameState.troops === 2400) {
unlockAchievement('perfect_crossing', gameState);
newAchievementsEarned.push('perfect_crossing');
}
if (gameState.alertLevel < 30) {
unlockAchievement('stealth_master', gameState);
newAchievementsEarned.push('stealth_master');
}
if (gameState.difficulty === 'hard') {
unlockAchievement('hardcore_victory', gameState);
newAchievementsEarned.push('hardcore_victory');
}
if (gameState.crossingTime === 'midnight') {
unlockAchievement('midnight_crossing', gameState);
newAchievementsEarned.push('midnight_crossing');
}
if (gameState.morale < 30) {
unlockAchievement('frozen_fingers', gameState);
newAchievementsEarned.push('frozen_fingers');
}
// Check for speed demon (crossing in under 30 seconds)
const timeTaken = (gameState.endTime - gameState.startTime) / 1000;
if (timeTaken < 30) {
unlockAchievement('speed_demon', gameState);
newAchievementsEarned.push('speed_demon');
}
} else {
resultTitle.textContent = "Crossing Failed";
resultIcon.textContent = "💀";
resultDescription.textContent = message || "Your crossing was detected and the element of surprise was lost.";
// Check for full alert achievement
if (gameState.alertLevel >= 100) {
unlockAchievement('full_alert', gameState);
}
}
// Show new achievements if any
if (newAchievementsEarned.length > 0) {
newAchievements.classList.remove('hidden');
const container = document.getElementById('achievements-earned');
container.innerHTML = '';
newAchievementsEarned.forEach(achId => {
const achievement = achievements.find(a => a.id === achId);
if (achievement) {
const div = document.createElement('div');
div.className = `achievement-badge p-3 rounded-lg flex items-center ${achievement.color}`;
div.innerHTML = `
<div class="mr-3 text-2xl">
<i class="fas ${achievement.icon}"></i>
</div>
<div>
<div class="font-bold">${achievement.title}</div>
<div class="text-sm">${achievement.description}</div>
</div>
`;
container.appendChild(div);
}
});
} else {
newAchievements.classList.add('hidden');
}
// Update stats
const timeTaken = (gameState.endTime - gameState.startTime) / 1000;
document.getElementById('stat-time').textContent = `${timeTaken.toFixed(1)} seconds`;
document.getElementById('stat-troops').textContent = `${2400 - gameState.troops} lost (${gameState.troops} remaining)`;
document.getElementById('stat-alert').textContent =
gameState.alertLevel < 40 ? 'Low' :
gameState.alertLevel < 70 ? 'Medium' : 'High';
document.getElementById('stat-difficulty').textContent =
gameState.difficulty === 'easy' ? 'Easy' :
gameState.difficulty === 'medium' ? 'Standard' : 'Hardcore';
document.getElementById('stat-morale').textContent =
gameState.morale < 40 ? 'Low' :
gameState.morale < 70 ? 'Medium' : 'High';
// Calculate score
calculateScore(success, timeTaken);
}
// Calculate final score
function calculateScore(success, timeTaken) {
if (!success) {
gameState.score = 0;
document.getElementById('stat-score').textContent = '0';
return;
}
let score = 1000;
// Time bonus (faster is better)
score += Math.max(0, 500 - (timeTaken * 10));
// Troop preservation bonus
score += (gameState.troops / 2400) * 500;
// Morale bonus
score += (gameState.morale / 100) * 300;
// Alert level penalty
score -= gameState.alertLevel * 2;
// Difficulty multiplier
if (gameState.difficulty === 'medium') score *= 1.5;
if (gameState.difficulty === 'hard') score *= 2;
gameState.score = Math.floor(Math.max(0, score));
document.getElementById('stat-score').textContent = gameState.score;
}
// Return to title screen
function returnToTitle() {
document.getElementById('results-screen').classList.add('hidden');
document.getElementById('title-screen').classList.remove('hidden');
}
// Create snow effect for hard difficulty
function createSnowEffect() {
const riverContainer = document.getElementById('river-container');
for (let i = 0; i < 50; i++) {
createSnowflake(riverContainer);
}
setInterval(() => {
createSnowflake(riverContainer);
}, 300);
}
function createSnowflake(container) {
const snowflake = document.createElement('div');
snowflake.classList.add('snowflake');
const size = Math.random() * 5 + 2;
snowflake.style.width = `${size}px`;
snowflake.style.height = `${size}px`;
snowflake.style.left = `${Math.random() * 100}%`;
snowflake.style.opacity = Math.random() * 0.5 + 0.3;
const animationDuration = Math.random() * 5 + 5;
snowflake.style.animationDuration = `${animationDuration}s`;
container.appendChild(snowflake);
// Remove snowflake after it falls
setTimeout(() => {
snowflake.remove();
}, animationDuration * 1000);
}
// Initialize achievements
function initAchievements() {
const savedAchievements = localStorage.getItem('achievements');
const savedSecrets = localStorage.getItem('secrets');
if (savedAchievements) {
gameState.achievements = JSON.parse(savedAchievements);
} else {
gameState.achievements = [];
}
if (savedSecrets) {
gameState.secretsFound = JSON.parse(savedSecrets);
} else {
gameState.secretsFound = [];
}
}
// Initialize on load
initAchievements();
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Hypergenius/washington-s-crossing" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>