From 455cb8af69cb8f1d9f4c09d2dc36c807111a895b Mon Sep 17 00:00:00 2001 From: HikeMap User Date: Wed, 7 Jan 2026 16:29:50 -0600 Subject: [PATCH] Add combat animations and fix music overlap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add monster attack animation (rubber band snap towards player) - Fix animation direction (now snaps left towards player) - Add orange highlight on attacking monster - Fix animation persistence through DOM rebuilds - Prevent login music playing over game music on refresh - Check for existing auth before starting login music 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- index.html | 65 +++++++++++++++++++++++++++++++++++++++++++++-- service-worker.js | 2 +- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 3538ed8..72519d3 100644 --- a/index.html +++ b/index.html @@ -2574,6 +2574,32 @@ pointer-events: none; text-decoration: line-through; } + .monster-entry.attacking { + border-color: #ff6b35; + box-shadow: 0 0 15px rgba(255, 107, 53, 0.6); + background: rgba(255, 107, 53, 0.15); + } + /* Rubber band attack animation for monster icon */ + @keyframes monsterAttack { + 0% { + transform: translateX(0); + } + 20% { + transform: translateX(20px) scale(0.9); + } + 50% { + transform: translateX(-30px) scale(1.15); + } + 70% { + transform: translateX(-5px) scale(1.05); + } + 100% { + transform: translateX(0) scale(1); + } + } + .monster-entry.attacking .monster-entry-icon { + animation: monsterAttack 0.5s ease-out; + } .monster-entry-header { display: flex; align-items: center; @@ -10842,7 +10868,8 @@ let loginMusicStarted = false; function startLoginMusic() { - if (!loginMusicStarted && !gameMusic.muted) { + const alreadyLoggedIn = localStorage.getItem('accessToken') || sessionStorage.getItem('guestMode'); + if (!loginMusicStarted && !gameMusic.muted && !alreadyLoggedIn) { loginMusicStarted = true; playMusic('login'); } @@ -11016,8 +11043,10 @@ // Try to autostart login music immediately (works if user has interacted before) // Falls back to first interaction if autoplay is blocked + // Skip if user is already logged in (will go straight to game music) setTimeout(() => { - if (!loginMusicStarted && !gameMusic.muted) { + const alreadyLoggedIn = localStorage.getItem('accessToken') || sessionStorage.getItem('guestMode'); + if (!loginMusicStarted && !gameMusic.muted && !alreadyLoggedIn) { const loginAudio = gameMusic.login; loginAudio.play().then(() => { loginMusicStarted = true; @@ -13526,6 +13555,31 @@ } } + // Scroll to the attacking monster and trigger rubber band animation + function animateMonsterAttack(monsterIndex) { + try { + const container = document.getElementById('monsterList'); + if (!container) return; + + const entries = container.querySelectorAll('.monster-entry'); + const entry = entries[monsterIndex]; + if (!entry) return; + + // Scroll the monster into view smoothly + entry.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + + // Force restart the rubber band animation on the icon + const icon = entry.querySelector('.monster-entry-icon'); + if (icon) { + icon.style.animation = 'none'; + icon.offsetHeight; // Trigger reflow + icon.style.animation = 'monsterAttack 0.5s ease-out'; + } + } catch (e) { + console.error('Animation error:', e); + } + } + // Render the monster list in combat UI function renderMonsterList() { const container = document.getElementById('monsterList'); @@ -13546,6 +13600,10 @@ if (combatState.targetingMode && monster.hp > 0) { entry.classList.add('targeting-selectable'); } + // Highlight the currently attacking monster + if (combatState.turn === 'monster' && index === combatState.currentMonsterTurn && monster.hp > 0) { + entry.classList.add('attacking'); + } const hpPct = Math.max(0, (monster.hp / monster.maxHp) * 100); const mpPct = Math.max(0, (monster.mp / monster.maxMp) * 100); @@ -14201,6 +14259,9 @@ combatState.currentMonsterTurn = monsterIndex; updateCombatUI(); + // Scroll to and animate the attacking monster (after DOM update) + setTimeout(() => animateMonsterAttack(monsterIndex), 50); + // Decrement monster buff durations at start of its turn if (monster.buffs) { if (monster.buffs.defense && monster.buffs.defense.turnsLeft > 0) { diff --git a/service-worker.js b/service-worker.js index d2b2668..db477eb 100644 --- a/service-worker.js +++ b/service-worker.js @@ -1,6 +1,6 @@ // HikeMap Service Worker // Increment version to force cache refresh -const CACHE_NAME = 'hikemap-v1.0.8'; +const CACHE_NAME = 'hikemap-v1.1.0'; const urlsToCache = [ '/', '/index.html',