import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react'; import { useLocation } from 'react-router-dom'; export interface Achievement { id: string; name: string; description: string; icon: string; unlocked: boolean; unlockedAt?: number; secret?: boolean; } interface AchievementsContextType { achievements: Achievement[]; unlockAchievement: (id: string) => void; getUnlockedCount: () => number; getTotalCount: () => number; timeOnSite: number; } const defaultAchievements: Achievement[] = [ // Discovery achievements { id: 'first_visit', name: 'Hello World', description: 'Visit the site for the first time', icon: '๐Ÿ‘‹', unlocked: false }, { id: 'found_achievements', name: 'Achievement Hunter', description: 'Discover the secret achievements section', icon: '๐Ÿ†', unlocked: false }, { id: 'konami_master', name: 'Konami Master', description: 'Enter the legendary cheat code', icon: '๐ŸŽฎ', unlocked: false, secret: true }, { id: 'terminal_user', name: 'Terminal Jockey', description: 'Use the terminal command interface', icon: '๐Ÿ’ป', unlocked: false }, { id: 'hint_seeker', name: 'Hint Seeker', description: 'Ask for a hint in the terminal', icon: '๐Ÿ”', unlocked: false, secret: true }, // Navigation achievements { id: 'home_visitor', name: 'Home Base', description: 'Visit the home page', icon: '๐Ÿ ', unlocked: false }, { id: 'about_visitor', name: 'Getting Personal', description: 'Learn about the site owner', icon: '๐Ÿ‘ค', unlocked: false }, { id: 'projects_visitor', name: 'Project Explorer', description: 'Check out the projects', icon: '๐Ÿ“', unlocked: false }, { id: 'resources_visitor', name: 'Resource Collector', description: 'Browse the resources page', icon: '๐Ÿ“š', unlocked: false }, { id: 'links_visitor', name: 'Link Crawler', description: 'Visit the links page', icon: '๐Ÿ”—', unlocked: false }, { id: 'faq_visitor', name: 'Question Everything', description: 'Read the FAQ', icon: 'โ“', unlocked: false }, { id: 'music_visitor', name: 'DJ Mode', description: 'Open the music player', icon: '๐ŸŽต', unlocked: false }, { id: 'ai_visitor', name: 'AI Whisperer', description: 'Chat with the AI', icon: '๐Ÿค–', unlocked: false }, { id: 'arcade_visitor', name: 'Arcade Enthusiast', description: 'Visit the arcade', icon: '๐Ÿ•น๏ธ', unlocked: false }, { id: 'all_pages', name: 'Completionist', description: 'Visit every page on the site', icon: '๐Ÿ—บ๏ธ', unlocked: false, secret: true }, // Time achievements { id: 'time_15min', name: 'Quick Visit', description: 'Spend 15 minutes on the site', icon: 'โฑ๏ธ', unlocked: false }, { id: 'time_30min', name: 'Taking Your Time', description: 'Spend 30 minutes on the site', icon: 'โฐ', unlocked: false }, { id: 'time_1hour', name: 'Deep Dive', description: 'Spend 1 hour on the site', icon: '๐Ÿ•', unlocked: false }, { id: 'time_3hour', name: 'Marathon Session', description: 'Spend 3 hour on the site', icon: '๐Ÿ•‘', unlocked: false }, { id: 'time_24hour', name: 'No Life', description: 'Spend 24 hours on the site', icon: '๐Ÿ’€', unlocked: false, secret: true }, // Game achievements { id: 'tetris_played', name: 'Block Stacker', description: 'Play Tetris', icon: '๐Ÿงฑ', unlocked: false }, { id: 'pacman_played', name: 'Pac-Fan', description: 'Play Pac-Man', icon: '๐ŸŸก', unlocked: false }, { id: 'snake_played', name: 'Sssssnake', description: 'Play Snake', icon: '๐Ÿ', unlocked: false }, { id: 'breakout_played', name: 'Brick Breaker', description: 'Play Breakout', icon: '๐Ÿงจ', unlocked: false }, { id: 'all_games', name: 'Arcade Master', description: 'Play all four arcade games', icon: '๐Ÿ‘พ', unlocked: false }, // Score achievements { id: 'tetris_1000', name: 'Tetris Novice', description: 'Score 1,000 points in Tetris', icon: '๐Ÿฅ‰', unlocked: false }, { id: 'tetris_10000', name: 'Tetris Pro', description: 'Score 10,000 points in Tetris', icon: '๐Ÿฅˆ', unlocked: false }, { id: 'tetris_50000', name: 'Tetris Legend', description: 'Score 50,000 points in Tetris', icon: '๐Ÿฅ‡', unlocked: false, secret: true }, { id: 'pacman_1000', name: 'Pac-Rookie', description: 'Score 1,000 points in Pac-Man', icon: '๐Ÿฅ‰', unlocked: false }, { id: 'pacman_5000', name: 'Pac-Veteran', description: 'Score 5,000 points in Pac-Man', icon: '๐Ÿฅˆ', unlocked: false }, { id: 'pacman_10000', name: 'Pac-Champion', description: 'Score 10,000 points in Pac-Man', icon: '๐Ÿฅ‡', unlocked: false, secret: true }, { id: 'snake_500', name: 'Baby Snake', description: 'Score 500 points in Snake', icon: '๐Ÿฅ‰', unlocked: false }, { id: 'snake_2000', name: 'Growing Snake', description: 'Score 2,000 points in Snake', icon: '๐Ÿฅˆ', unlocked: false }, { id: 'snake_5000', name: 'Mega Snake', description: 'Score 5,000 points in Snake', icon: '๐Ÿฅ‡', unlocked: false, secret: true }, { id: 'breakout_1000', name: 'Brick Novice', description: 'Score 1,000 points in Breakout', icon: '๐Ÿฅ‰', unlocked: false }, { id: 'breakout_5000', name: 'Brick Crusher', description: 'Score 5,000 points in Breakout', icon: '๐Ÿฅˆ', unlocked: false }, { id: 'breakout_10000', name: 'Brick Destroyer', description: 'Score 10,000 points in Breakout', icon: '๐Ÿฅ‡', unlocked: false, secret: true }, // Special achievements { id: 'night_owl', name: 'Night Owl', description: 'Visit the site between midnight and 4 AM', icon: '๐Ÿฆ‰', unlocked: false, secret: true }, { id: 'early_bird', name: 'Early Bird', description: 'Visit the site between 5 AM and 7 AM', icon: '๐Ÿฆ', unlocked: false, secret: true }, { id: 'theme_switcher', name: 'Indecisive', description: 'Switch between red and green themes', icon: '๐ŸŽจ', unlocked: false }, { id: 'crt_toggler', name: 'Retro Purist', description: 'Toggle the CRT effect', icon: '๐Ÿ“บ', unlocked: false }, { id: 'sound_toggler', name: 'Audio Engineer', description: 'Toggle sound effects', icon: '๐Ÿ”Š', unlocked: false }, { id: 'music_listener', name: 'Radio Listener', description: 'Listen to a radio station', icon: '๐Ÿ“ป', unlocked: false }, { id: 'ai_conversation', name: 'Deep Thinker', description: 'Send 5 messages to the AI', icon: '๐Ÿ’ญ', unlocked: false }, { id: 'ai_long_chat', name: 'Chatterbox', description: 'Send 20 messages to the AI', icon: '๐Ÿ—ฃ๏ธ', unlocked: false, secret: true }, { id: 'project_detail', name: 'Project Inspector', description: 'View a project in detail', icon: '๐Ÿ”ฌ', unlocked: false }, { id: 'leaderboard_check', name: 'Competitive Spirit', description: 'Check the arcade leaderboard', icon: '๐Ÿ“Š', unlocked: false }, { id: 'max_score', name: 'Integer Overflow', description: 'Reach the maximum score in any game', icon: '๐Ÿ’ฅ', unlocked: false, secret: true }, { id: 'verified_human', name: 'Certified Human', description: 'Pass the human verification', icon: 'โœ…', unlocked: false }, ]; const AchievementsContext = createContext(undefined); export const AchievementsProvider = ({ children }: { children: ReactNode }) => { const [achievements, setAchievements] = useState(() => { const saved = localStorage.getItem('achievements'); if (saved) { const parsed = JSON.parse(saved); // Merge with defaults to handle new achievements return defaultAchievements.map(def => { const saved = parsed.find((a: Achievement) => a.id === def.id); return saved ? { ...def, unlocked: saved.unlocked, unlockedAt: saved.unlockedAt } : def; }); } return defaultAchievements; }); const [timeOnSite, setTimeOnSite] = useState(() => { const saved = localStorage.getItem('timeOnSite'); return saved ? parseInt(saved, 10) : 0; }); const [visitedPages, setVisitedPages] = useState>(() => { const saved = localStorage.getItem('visitedPages'); return saved ? new Set(JSON.parse(saved)) : new Set(); }); const location = useLocation(); // Track time on site useEffect(() => { const interval = setInterval(() => { setTimeOnSite(prev => { const newTime = prev + 1; localStorage.setItem('timeOnSite', newTime.toString()); return newTime; }); }, 1000); return () => clearInterval(interval); }, []); // Check time-based achievements useEffect(() => { if (timeOnSite >= 900) unlockAchievement('time_15min'); if (timeOnSite >= 1800) unlockAchievement('time_30min'); if (timeOnSite >= 3600) unlockAchievement('time_1hour'); if (timeOnSite >= 10800) unlockAchievement('time_3hour'); if (timeOnSite >= 86400) unlockAchievement('time_24hour'); }, [timeOnSite]); // Check time of day achievements useEffect(() => { const hour = new Date().getHours(); if (hour >= 0 && hour < 4) unlockAchievement('night_owl'); if (hour >= 5 && hour < 7) unlockAchievement('early_bird'); }, []); // Track page visits useEffect(() => { const path = location.pathname; setVisitedPages(prev => { const newSet = new Set(prev); newSet.add(path); localStorage.setItem('visitedPages', JSON.stringify([...newSet])); return newSet; }); // Page-specific achievements if (path === '/') unlockAchievement('home_visitor'); if (path === '/about') unlockAchievement('about_visitor'); if (path === '/projects') unlockAchievement('projects_visitor'); if (path === '/resources') unlockAchievement('resources_visitor'); if (path === '/links') unlockAchievement('links_visitor'); if (path === '/faq') unlockAchievement('faq_visitor'); if (path === '/music') unlockAchievement('music_visitor'); if (path === '/ai') unlockAchievement('ai_visitor'); if (path === '/games') unlockAchievement('arcade_visitor'); if (path.startsWith('/projects/')) unlockAchievement('project_detail'); if (path === '/games/leaderboard') unlockAchievement('leaderboard_check'); if (path === '/games/tetris') unlockAchievement('tetris_played'); if (path === '/games/pacman') unlockAchievement('pacman_played'); if (path === '/games/snake') unlockAchievement('snake_played'); if (path === '/games/breakout') unlockAchievement('breakout_played'); }, [location.pathname]); // Check all pages visited useEffect(() => { const requiredPages = ['/', '/about', '/projects', '/resources', '/links', '/faq', '/music', '/ai', '/games']; const allVisited = requiredPages.every(p => visitedPages.has(p)); if (allVisited) unlockAchievement('all_pages'); }, [visitedPages]); // Check all games played useEffect(() => { const gamePages = ['/games/tetris', '/games/pacman', '/games/snake', '/games/breakout']; const allPlayed = gamePages.every(p => visitedPages.has(p)); if (allPlayed) unlockAchievement('all_games'); }, [visitedPages]); // First visit achievement useEffect(() => { unlockAchievement('first_visit'); }, []); const [notification, setNotification] = useState(null); const unlockAchievement = useCallback((id: string) => { setAchievements(prev => { const achievement = prev.find(a => a.id === id); if (!achievement || achievement.unlocked) return prev; // Show notification setNotification(achievement); setTimeout(() => setNotification(null), 4000); const updated = prev.map(a => a.id === id ? { ...a, unlocked: true, unlockedAt: Date.now() } : a ); localStorage.setItem('achievements', JSON.stringify(updated)); return updated; }); }, []); const getUnlockedCount = useCallback(() => { return achievements.filter(a => a.unlocked).length; }, [achievements]); const getTotalCount = useCallback(() => { return achievements.length; }, [achievements]); // Save achievements useEffect(() => { localStorage.setItem('achievements', JSON.stringify(achievements)); }, [achievements]); return ( {children} {/* Achievement Notification */} {notification && (
{notification.icon}
ACHIEVEMENT UNLOCKED!
{notification.name}
{notification.description}
)}
); }; export const useAchievements = () => { const context = useContext(AchievementsContext); if (context === undefined) { throw new Error('useAchievements must be used within an AchievementsProvider'); } return context; };