diff --git a/game_server.py b/game_server.py index ff81f3d..296057d 100644 --- a/game_server.py +++ b/game_server.py @@ -180,8 +180,8 @@ class SynthCoin: self.x = x self.y = y self.radius = 5 - self.follow_radius = 100 - self.follow_speed = 2 + self.follow_radius = 200 + self.follow_speed = 5 self.created_at = time.time() def update(self, players): @@ -1482,6 +1482,7 @@ def game_loop(): 'action': 'change', 'song': f"/{music_player.get_current_song()}", 'startTime': music_player.start_time, + 'serverTime': time.time(), 'songDuration': music_player.get_current_song_duration() }, room=main_room) @@ -1551,6 +1552,7 @@ def start_music(): 'action': 'start', 'song': music_player.get_current_song(), 'startTime': music_player.start_time, + 'serverTime': time.time(), 'songDuration': music_player.get_current_song_duration() }, room=main_room) @@ -1564,6 +1566,7 @@ def change_song(): 'action': 'change', 'song': new_song, 'startTime': music_player.start_time, + 'serverTime': time.time(), 'songDuration': music_player.get_current_song_duration() }, room=main_room) @@ -1649,8 +1652,19 @@ class MusicPlayer: self.current_song_index = (self.current_song_index + 1) % len(self.playlist) self.start_time = time.time() self.load_current_song() - send_discord_alert(f"🎵 Now playing: {self.get_current_song()}") - return self.get_current_song() + new_song = self.get_current_song() + send_discord_alert(f"🎵 Now playing: {new_song}") + + # Emit updated music sync information + socketio.emit('music_control', { + 'action': 'change', + 'song': new_song, + 'startTime': self.start_time, + 'serverTime': time.time(), + 'songDuration': self.get_current_song_duration() + }, room=main_room) + + return new_song @@ -1864,6 +1878,7 @@ class AdminConsole(cmd.Cmd): 'action': 'change', 'song': new_song, 'startTime': music_player.start_time, + 'serverTime': time.time(), 'songDuration': music_player.get_current_song_duration() }, room=main_room) @@ -1889,6 +1904,7 @@ class AdminConsole(cmd.Cmd): 'action': 'change', 'song': new_song, 'startTime': music_player.start_time, + 'serverTime': time.time(), 'songDuration': music_player.get_current_song_duration() }, room=main_room) diff --git a/index.html b/index.html index 022d3fa..ceeca15 100644 --- a/index.html +++ b/index.html @@ -183,5 +183,15 @@ + +
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/static/js/game.js b/static/js/game.js index c7bcda9..326aeb4 100644 --- a/static/js/game.js +++ b/static/js/game.js @@ -30,7 +30,8 @@ let gameStarted = false; let joystick = { active: false, startX: 0, startY: 0, endX: 0, endY: 0 }; let isDebugging = document.getElementById('debugCheckbox').checked; let socket; -let currentSongDuration = 180; // Default to 3 minutes +let currentSongDuration = 0; +let songStartTime = 0; let backgroundCanvas, backgroundCtx; let uiButton, uiWidget, menuButton; let isWidgetVisible = false; @@ -72,6 +73,7 @@ let shootingJoystick = { }; let lastUpdateTime = Date.now(); let impactEffects = []; +let currentSongName = ''; @@ -2188,6 +2190,15 @@ function startGame() { }); }); + socket.on('server_restart', (data) => { + notificationSystem.showNotification(data.message); + // Optionally, you could implement a reconnection attempt after a short delay + setTimeout(() => { + location.reload(); + }, 5000); // Wait for 5 seconds before reloading the page + }); + + socket.on('achievement_unlocked', handleAchievementUnlock); @@ -2232,8 +2243,13 @@ function startGame() { if (gameStarted) { const serverClientTimeDiff = Date.now() / 1000 - data.serverTime; currentSongDuration = data.songDuration || 180; // Use the provided duration or default to 3 minutes + songStartTime = data.startTime + serverClientTimeDiff; const songPosition = (Date.now() / 1000 - data.startTime - serverClientTimeDiff) % currentSongDuration; setupAudio(data.song, songPosition); + + currentSongName = data.song.split('/').pop(); + updateSongDurationBar(); + } }); @@ -2527,10 +2543,14 @@ socket.on('bullet_impact', (data) => { switch(data.action) { case 'start': case 'change': - const currentTime = Date.now() / 1000; - const elapsedTime = currentTime - data.startTime; + const serverClientTimeDiff = Date.now() / 1000 - data.serverTime; currentSongDuration = data.songDuration || 180; // Use the provided duration or default to 3 minutes - setupAudio(data.song, elapsedTime % currentSongDuration); + songStartTime = data.startTime + serverClientTimeDiff; + const songPosition = 0; // Start from the beginning for 'change' action + setupAudio(data.song, songPosition); + + currentSongName = data.song.split('/').pop(); + updateSongDurationBar(); break; case 'stop': if (audioElement) { @@ -2539,7 +2559,7 @@ socket.on('bullet_impact', (data) => { break; } }); - + socket.on('skin_update', (data) => { const { player_id, skin_data } = data; if (player_id === socket.id) { @@ -2550,7 +2570,7 @@ socket.on('bullet_impact', (data) => { otherPlayers[player_id].setSkin(skin_data); } }); - + showSongDurationBar(); } function hideShopButton() { @@ -3179,6 +3199,9 @@ function update() { if (gameStarted) { alertSystem.draw(ctx); } + if (gameStarted) { + updateSongDurationBar(); + } requestAnimationFrame(update); debugLog('Player position:', player.x, player.y); debugLog('Number of enemies:', serverEnemies.length); @@ -3798,6 +3821,34 @@ class ImpactEffect { } } +function updateSongDurationBar() { + const now = Date.now() / 1000; + const elapsed = now - songStartTime; + const remaining = Math.max(0, currentSongDuration - elapsed); + const progress = Math.min(1, elapsed / currentSongDuration); + + const fillElement = document.getElementById('songDurationFill'); + const timerElement = document.getElementById('songTimer'); + const songNameElement = document.querySelector('#songName .scrolling-text'); + + fillElement.style.width = `${(1 - progress) * 100}%`; + timerElement.textContent = formatTime(remaining); + songNameElement.textContent = `Now playing: ${currentSongName}`; +} + +function formatTime(seconds) { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = Math.floor(seconds % 60); + return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; +} + +function showSongDurationBar() { + document.getElementById('songDurationBar').style.display = 'block'; +} + +function hideSongDurationBar() { + document.getElementById('songDurationBar').style.display = 'none'; +} -init(); \ No newline at end of file +init(); diff --git a/static/styles.css b/static/styles.css index 3a9dada..64c6851 100644 --- a/static/styles.css +++ b/static/styles.css @@ -548,6 +548,68 @@ body { } } +.song-duration-bar { + position: fixed; + top: 10px; + left: 50%; + transform: translateX(-50%); + width: 300px; + height: 30px; + background-color: rgba(0, 0, 0, 0.5); + border: 2px solid #00ffff; + border-radius: 15px; + overflow: hidden; + display: none; + align-items: center; +} + +.song-duration-fill { + height: 100%; + background-color: rgba(0, 255, 255, 0.3); + transition: width 1s linear; +} + +.song-info { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 10px; + box-sizing: border-box; + font-family: 'Orbitron', sans-serif; + font-size: 14px; + color: #00ffff; +} + +#songName { + flex-grow: 1; + overflow: hidden; + white-space: nowrap; +} + +#songName .scrolling-text { + display: inline-block; + padding-left: 100%; + animation: scroll 15s linear infinite; +} + +@keyframes scroll { + 0% { + transform: translate(0, 0); + } + 100% { + transform: translate(-100%, 0); + } +} + +#songTimer { + flex-shrink: 0; +} + .skin-option.glow-effect { box-shadow: 0 0 10px 3px currentColor; animation: glow 1.5s ease-in-out infinite alternate;