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',