const config = window.SeasonalsPluginConfig?.Sports || {}; const sports = config.EnableSports !== undefined ? config.EnableSports : true; const symbolCount = config.SymbolCount || 5; const useRandomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true; const enableRandomMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false; const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // Pre-declare and manage image assets const SPORTS_ASSETS = { badminton: ['badminton_1', 'badminton_2'], baseball: ['baseball_1', 'baseball_2'], basketball: ['basketball_1', 'basketball_2'], billiard: Array.from({length: 14}, (_, i) => `billiard_ball_${i + 1}`), bowling: ['bowling_1', 'bowling_2'], football: Array.from({length: 5}, (_, i) => `football_${i + 1}`), golf: ['golf_ball_1', 'golf_ball_2'], rugby: ['rugby_ball_1', 'rugby_ball_2'], table_tennis: ['table_tennis_ball_1', 'table_tennis_ball_2'], tennis: ['tennis_ball_1', 'tennis_ball_2'], volleyball: ['volleyball_1', 'volleyball_2'], waterball: ['waterball_1', 'waterball_2'] }; const turfColorHex = config.TurfColor || '#228b22'; let msgPrinted = false; function toggleSports() { const container = document.querySelector('.sports-container'); if (!container) return; const videoPlayer = document.querySelector('.videoPlayerContainer'); const trailerPlayer = document.querySelector('.youtubePlayerContainer'); const isDashboard = document.body.classList.contains('dashboardDocument'); const hasUserMenu = document.querySelector('#app-user-menu'); if (videoPlayer || trailerPlayer || isDashboard || hasUserMenu) { container.style.display = 'none'; if (!msgPrinted) { console.log('Sports hidden'); msgPrinted = true; } } else { container.style.display = 'block'; if (msgPrinted) { console.log('Sports visible'); msgPrinted = false; } } } const observer = new MutationObserver(toggleSports); observer.observe(document.body, { childList: true, subtree: true, attributes: true }); function createSports() { const container = document.querySelector('.sports-container') || document.createElement('div'); if (!document.querySelector('.sports-container')) { container.className = 'sports-container'; container.setAttribute("aria-hidden", "true"); document.body.appendChild(container); } // Parse turf color config // Create a turf/grass overlay at the bottom using the provided hex const turf = document.createElement('div'); turf.className = 'sports-turf'; // Using hex with transparency (e.g., 4D = 30%, CC = 80%) turf.style.background = `linear-gradient(180deg, transparent 0%, ${turfColorHex}4D 30%, ${turfColorHex}CC 100%)`; container.appendChild(turf); const standardCount = 15; const totalSymbols = symbolCount + standardCount; let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches; let finalCount = totalSymbols; if (isMobile) { finalCount = enableRandomMobile ? totalSymbols : standardCount; } const useRandomDuration = enableDifferentDuration !== false; // Map standard sports balls to spawn based on category configuration const rawSportsBalls = config.SportsBalls || 'football,basketball,tennis,volleyball'; const chosenCategories = rawSportsBalls.split(',').map(s => s.trim()).filter(s => s !== ''); // Assemble activeItems from categories let activeItems = []; chosenCategories.forEach(category => { if (SPORTS_ASSETS[category]) { activeItems.push(...SPORTS_ASSETS[category]); } else { // Legacy fallback (in case older explicit filenames remain in config string) activeItems.push(category); } }); if (activeItems.length === 0) activeItems.push(...SPORTS_ASSETS['football']); // fallback // Track items we still need to show at least once let guaranteedItems = [...activeItems]; // Create falling sports balls for (let i = 0; i < finalCount; i++) { let symbol = document.createElement('div'); // Pick a guaranteed ball first, otherwise pick completely randomly let randomItem; if (guaranteedItems.length > 0) { const index = Math.floor(Math.random() * guaranteedItems.length); randomItem = guaranteedItems[index]; guaranteedItems.splice(index, 1); } else { randomItem = activeItems[Math.floor(Math.random() * activeItems.length)]; } symbol.className = `sports-symbol sports-${randomItem}`; // Create inner div for spinning rotation let innerDiv = document.createElement('div'); innerDiv.className = 'sports-inner'; // Try load image let img = document.createElement('img'); img.src = `../Seasonals/Resources/sport_assets/${randomItem}.png`; img.onerror = function() { this.style.display = 'none'; // hide broken image icon this.parentElement.innerHTML = getEmojiFallback(randomItem); // inject emoji fallback }; innerDiv.appendChild(img); // Balls should bounce infinitely symbol.style.animationName = 'sports-bounce'; symbol.style.animationIterationCount = 'infinite'; innerDiv.style.animationName = 'sports-spin'; innerDiv.style.animationIterationCount = 'infinite'; symbol.appendChild(innerDiv); const leftPos = Math.random() * 95; const delaySeconds = Math.random() * 10; let durationSeconds = 8; if (useRandomDuration) { durationSeconds = Math.random() * 4 + 6; // 6 to 10 seconds } // Add a random spin const spinRot = (Math.random() > 0.5 ? 360 : -360) + "deg"; innerDiv.style.setProperty('--spin-rot', spinRot); // Duration for the spin should be different from fall to look natural const spinDuration = Math.random() * 2 + 2; innerDiv.style.animationDuration = `${spinDuration}s`; symbol.style.left = `${leftPos}vw`; symbol.style.animationDuration = `${durationSeconds}s`; symbol.style.animationDelay = `${delaySeconds}s`; container.appendChild(symbol); } // Create the periodic flying trophy arc function launchTrophy() { if (!document.querySelector('.sports-container')) return; const flyFromLeft = Math.random() > 0.5; let trophySymbol = document.createElement('div'); trophySymbol.className = "sports-symbol sports-trophy-wrapper"; let trophyInner = document.createElement('div'); trophyInner.className = "sports-inner sports-trophy-inner"; let trophyImg = document.createElement('img'); trophyImg.src = `../Seasonals/Resources/sport_assets/trophy.gif`; // Randomly scale trophy slightly larger trophyImg.style.transform = `scale(${Math.random() * 0.5 + 0.8})`; trophyImg.onerror = function() { this.style.display = 'none'; }; trophyInner.appendChild(trophyImg); trophySymbol.appendChild(trophyInner); if (flyFromLeft) { trophySymbol.style.animationName = "sports-arc-x-right"; trophySymbol.style.left = "-15vw"; } else { trophySymbol.style.animationName = "sports-arc-x-left"; trophySymbol.style.left = "115vw"; } trophyInner.style.animationName = "sports-arc-y"; // Appearance timing const arcDuration = 6 + Math.random() * 2; trophySymbol.style.animationDuration = `${arcDuration}s`; trophyInner.style.animationDuration = `${arcDuration}s`; // Prevent looping for the trophy trophySymbol.style.animationIterationCount = "1"; trophyInner.style.animationIterationCount = "1"; trophySymbol.style.animationFillMode = "forwards"; trophyInner.style.animationFillMode = "forwards"; container.appendChild(trophySymbol); // Remove node after animation completes setTimeout(() => { if (trophySymbol && trophySymbol.parentNode) { trophySymbol.parentNode.removeChild(trophySymbol); } }, arcDuration * 1000 + 500); // Schedule the next trophy setTimeout(launchTrophy, Math.random() * 20000 + 10000); // Wait 10-30s until next trophy } // Launch initial trophy after a short delay setTimeout(launchTrophy, Math.random() * 5000 + 2000); // Add Germany Colored confetti (Black, Red, Gold) const confettiColors = ['#000000', '#FF0000', '#FFCC00']; const confettiCount = isMobile ? 30 : 60; for (let i = 0; i < confettiCount; i++) { let confetti = document.createElement('div'); confetti.className = 'sports-confetti'; const color = confettiColors[Math.floor(Math.random() * confettiColors.length)]; confetti.style.backgroundColor = color; // Random shape generator for varied confetti const shape = Math.random(); if (shape > 0.66) { confetti.classList.add('circle'); const size = Math.random() * 5 + 5; // 5-10px confetti.style.width = `${size}px`; confetti.style.height = `${size}px`; } else if (shape > 0.33) { confetti.classList.add('rect'); const width = Math.random() * 4 + 4; // 4-8px const height = Math.random() * 5 + 8; // 8-13px confetti.style.width = `${width}px`; confetti.style.height = `${height}px`; } else { confetti.classList.add('triangle'); } const leftPos = Math.random() * 100; const delaySeconds = Math.random() * 8; const duration = Math.random() * 3 + 4; // 4 to 7 seconds confetti.style.left = `${leftPos}vw`; confetti.style.animationDuration = `${duration}s`; confetti.style.animationDelay = `${delaySeconds}s`; // Random 3D Rotation for flutter confetti.style.setProperty('--rx', Math.random().toFixed(2)); confetti.style.setProperty('--ry', Math.random().toFixed(2)); confetti.style.setProperty('--rz', (Math.random() * 0.5).toFixed(2)); confetti.style.setProperty('--rot-dir', `${(Math.random() > 0.5 ? 1 : -1) * 360}deg`); container.appendChild(confetti); } } function getEmojiFallback(type) { if (type.includes('soccer') || type.includes('football')) return '⚽'; if (type.includes('baseball')) return '⚾'; if (type.includes('basketball')) return '🏀'; if (type.includes('billiard')) return '🎱'; if (type.includes('bowling')) return '🎳'; if (type.includes('golf')) return '⛳'; if (type.includes('rugby')) return '🏈'; if (type.includes('tennis')) return '🎾'; if (type.includes('volleyball')) return '🏐'; if (type.includes('badminton')) return '🏸'; if (type.includes('waterball')) return '🤽'; return ''; } function initializeSports() { if (!sports) return; createSports(); toggleSports(); } initializeSports();