diff --git a/public/js/buildings/1v1.js b/public/js/buildings/1v1.js index ab53d05..371d1f9 100644 --- a/public/js/buildings/1v1.js +++ b/public/js/buildings/1v1.js @@ -872,24 +872,25 @@ socket.on('hp_init', data => { /* Avatar getroffen */ socket.on('avatar_damaged', data => { - const { slot, damage, remainingHp, maxHp } = data; + const { slot, damage, remainingHp, maxHp, row } = data; updateHpDisplay(slot, remainingHp, maxHp); - console.log(`[HP] ${slot} -${damage} → ${remainingHp}/${maxHp}`); + console.log(`[HP] ${slot} (${row}) -${damage} → ${remainingHp}/${maxHp}`); - /* Schadens-Zahl einblenden */ + /* Schadens-Zahl einblenden – Reihe 1 oben, Reihe 2 etwas tiefer */ const isLeft = slot === (window._leftSlot || 'player1'); const avEl = document.getElementById(isLeft ? 'avLeft' : 'avRight'); + const topPct = row === 'row2' ? '38%' : '14%'; if (avEl) { const dmg = document.createElement('div'); dmg.textContent = `-${damage}`; dmg.style.cssText = ` - position:absolute;top:15%;left:50%;transform:translateX(-50%); + position:absolute;top:${topPct};left:50%;transform:translateX(-50%); font-family:'Cinzel',serif;font-size:calc(var(--s)*24);font-weight:700; color:#e74c3c;text-shadow:0 2px 10px rgba(0,0,0,0.95); pointer-events:none;z-index:30; - animation:dmg-float 1s ease forwards;`; + animation:dmg-float 2.5s ease forwards;`; avEl.appendChild(dmg); - setTimeout(() => dmg.remove(), 1000); + setTimeout(() => dmg.remove(), 2500); } }); @@ -946,8 +947,11 @@ socket.on('ht_ai_setup', data => { ═══════════════════════════════════════════════════════════ */ function closeToArena() { if (window.parent && window.parent !== window) { - window.parent.document.getElementById('arena-backdrop')?.remove(); - window.parent.document.getElementById('arena-popup')?.remove(); + const pd = window.parent.document; + /* Alle möglichen Popup-Varianten entfernen */ + ['arena-backdrop', 'arena-popup', + 'ht-daily-backdrop', 'ht-daily-popup', + 'ht-backdrop', 'ht-popup'].forEach(id => pd.getElementById(id)?.remove()); } else { window.location.href = '/launcher'; } @@ -1066,8 +1070,17 @@ function updateResultWithPoints(data) { } }).catch(() => {}); - /* Nach 3 Sekunden zur Arena weiterleiten */ - setTimeout(() => closeToArena(), 3000); + /* Nach 5 Sekunden: Overlay ausblenden und zur Arena weiterleiten */ + setTimeout(() => { + const el = document.getElementById('match-end-overlay'); + if (el) { + el.style.transition = 'opacity 0.6s ease'; + el.style.opacity = '0'; + setTimeout(() => { el.remove(); closeToArena(); }, 650); + } else { + closeToArena(); + } + }, 5000); } function closePopup() { closeToArena(); } diff --git a/sockets/arena.socket.js b/sockets/arena.socket.js index 2e4983e..76d214b 100644 --- a/sockets/arena.socket.js +++ b/sockets/arena.socket.js @@ -543,29 +543,30 @@ async function processAvatarAttacks(io, matchId, room, events) { const avatarEvents = events.filter(e => e.type === 'avatar_attack'); if (avatarEvents.length === 0) return false; - for (const ev of avatarEvents) { - const target = ev.target; // 'player1' | 'player2' + for (let i = 0; i < avatarEvents.length; i++) { + // Mehrere Avatar-Treffer im gleichen Zug: 500ms Abstand + if (i > 0) await new Promise(r => setTimeout(r, 500)); + + const ev = avatarEvents[i]; + const target = ev.target; - // Sicherheits-Fallback: HP noch nicht initialisiert if (room.hp[target] == null) { console.warn(`[HP] room.hp[${target}] nicht gesetzt – überspringe`); continue; } - // Schaden abziehen (niemals unter 0) room.hp[target] = Math.max(0, room.hp[target] - (ev.damage ?? 0)); - // Treffer an beide Clients melden emitToMatch(io, matchId, 'avatar_damaged', { slot : target, damage : ev.damage, remainingHp: room.hp[target], maxHp : room.maxHp[target] ?? 20, + row : ev.from?.split('-slot-')[0] ?? 'row1', // Reihe für Versatz }); - console.log(`[HP] ${target} -${ev.damage} → ${room.hp[target]}/${room.maxHp[target]}`); + console.log(`[HP] ${target} (${ev.from}) -${ev.damage} → ${room.hp[target]}/${room.maxHp[target]}`); - // Match-Ende wenn HP auf 0 if (room.hp[target] <= 0) { await handleMatchEnd(io, matchId, room, target); return true; diff --git a/sockets/combat.js b/sockets/combat.js index bff0dcd..c98aa2c 100644 --- a/sockets/combat.js +++ b/sockets/combat.js @@ -56,7 +56,7 @@ function runCombatPhase(boardState, leftSlot, activeSlot) { for (let r = 1; r <= range; r++) { const targetPos = currentPos + dir * r; - /* Avatar-Angriff: Range geht über das Spielfeld hinaus */ + /* Avatar-Angriff: Range geht über das Spielfeld */ if (targetPos < 1 || targetPos > 11) { events.push({ type: 'avatar_attack', from: currentSlotId, target: opponentSlot, damage: atk }); break; @@ -70,7 +70,6 @@ function runCombatPhase(boardState, leftSlot, activeSlot) { target.card = { ...target.card, defends: (target.card.defends ?? 0) - atk }; events.push({ type: 'attack', from: currentSlotId, to: targetSlotId, damage: atk, remainingDef: target.card.defends }); - if (target.card.defends <= 0) { delete boardState[targetSlotId]; events.push({ type: 'die', slotId: targetSlotId });