diff --git a/frontend/src/lib/components/games/GameLauncher.svelte b/frontend/src/lib/components/games/GameLauncher.svelte index e8f91f4..ec3f103 100644 --- a/frontend/src/lib/components/games/GameLauncher.svelte +++ b/frontend/src/lib/components/games/GameLauncher.svelte @@ -2,6 +2,7 @@ import { onMount, onDestroy } from 'svelte'; import { fade, fly } from 'svelte/transition'; import SnakeGame from './SnakeGame.svelte'; + import PhishingGame from './PhishingGame.svelte'; // konami code sequence const konamiCode = [ @@ -16,18 +17,52 @@ ]; let konamiIndex = 0; + // track ctrl+shift+p shortcut + let ctrlPressed = false; + let shiftPressed = false; + let gameVisible = false; - const currentGame = { - name: 'snake', - title: 'slop cred snake', - component: SnakeGame, - emoji: '' - }; + let currentGame = null; + + const games = [ + { + name: 'snake', + title: 'slop cred snake', + component: SnakeGame + }, + { + name: 'phishing', + title: 'slopedition', + component: PhishingGame + } + ]; + + function getRandomGame() { + return games[Math.floor(Math.random() * games.length)]; + } function handleKeyDown(e) { + // track modifier keys + if (e.key === 'Control') { + ctrlPressed = true; + } + if (e.key === 'Shift') { + shiftPressed = true; + } + + // check for ctrl+shift+p to launch random game + if (ctrlPressed && shiftPressed && (e.key === 'p' || e.key === 'P')) { + e.preventDefault(); + currentGame = getRandomGame(); + gameVisible = true; + return; + } + + // check for konami code to launch random game if (e.key === konamiCode[konamiIndex]) { konamiIndex++; if (konamiIndex === konamiCode.length) { + currentGame = getRandomGame(); gameVisible = true; konamiIndex = 0; } @@ -36,6 +71,15 @@ } } + function handleKeyUp(e) { + if (e.key === 'Control') { + ctrlPressed = false; + } + if (e.key === 'Shift') { + shiftPressed = false; + } + } + function closeGame() { gameVisible = false; } @@ -46,14 +90,16 @@ onMount(() => { window.addEventListener('keydown', handleKeyDown); + window.addEventListener('keyup', handleKeyUp); }); onDestroy(() => { window.removeEventListener('keydown', handleKeyDown); + window.removeEventListener('keyup', handleKeyUp); }); -{#if gameVisible} +{#if gameVisible && currentGame}
- {currentGame.emoji} {currentGame.title} - {currentGame.emoji}

press esc to close

diff --git a/frontend/src/lib/components/games/PhishingGame.svelte b/frontend/src/lib/components/games/PhishingGame.svelte new file mode 100644 index 0000000..937dd23 --- /dev/null +++ b/frontend/src/lib/components/games/PhishingGame.svelte @@ -0,0 +1,830 @@ + + +
+ {#if gameStarted} +
+
+
score
+
{Math.floor(score)}
+
+
+
depth
+
{Math.floor(depth)}m
+
+
+ {/if} + +
+ + + {#if !gameStarted} +
+
+
+
🎣 how to play
+
    +
  • use ← → (or a/d) to move horizontally
  • +
  • + descending: catch an employee to start ascending +
  • +
  • hitting traps = instant death!
  • +
  • the deeper you go, the better targets appear
  • +
  • catch multiple employees on the way up for combos
  • +
  • reach max depth (10,000m) for the best catches!
  • +
+
+ +
+
+ 🎯 targets (deeper = better) +
+
+ {#each employeeTypes as emp} +
+ {emp.emoji} + {emp.title} + {emp.points}pts +
+ {/each} +
+
+ +
+
+ ⚠️ obstacles (instant death!) +
+
+ {#each trapTypes as trap} +
+ {trap.emoji} + {trap.title} +
+ {/each} +
+
+
+ + +
+ {:else if showHighScoreEntry} +
+
new high score! 🎉
+
{Math.floor(score)} points
+ +
+ + e.key === 'Enter' && submitHighScore()} + maxlength="20" + class="bg-black/60 border-2 border-pc-purple text-white px-4 py-2 rounded focus:outline-none focus:border-pc-pink w-64 text-center" + placeholder="elite_phisher" + /> +
+ + +
+ {:else if gameOver} +
+
phishing complete! 🎣
+
{Math.floor(score)} points
+ + {#if highScores.length > 0} +
+
+ 🏆 high scores +
+
+ {#each highScores as hs, i} +
+ {i + 1}. {hs.name} + {hs.score} +
+ {/each} +
+
+ {/if} + + +
+ {/if} +
+ + {#if gameStarted && !gameOver} +
+ use ← → or a/d to steer • {descending + ? 'catch an employee to start ascending! avoid traps!' + : 'catch more targets!'} +
+ {/if} +