dok/sockets/combat.js
2026-04-13 17:30:53 +01:00

139 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* sockets/combat.js Server-seitige Kampfphasen-Logik für 1v1
*
* ZWEI PHASEN PRO ZUG:
*
* Phase 1 BEWEGUNG (nur Karten des aktiven Spielers, vorderste zuerst)
* Phase 2 ANGRIFF (nur Karten des aktiven Spielers, Slot 11→1)
*/
'use strict';
/**
* @param {Object} boardState wird in-place verändert
* @param {string} leftSlot 'player1' oder 'player2' (wer links steht)
* @param {string} activeSlot 'player1' oder 'player2' (wer gerade am Zug ist)
* @returns {Array} geordnete Event-Liste für den Client
*/
function runCombatPhase(boardState, leftSlot, activeSlot) {
const events = [];
/* ════════════════════════════════════════════════════════
PHASE 1: BEWEGUNG
Nur Karten des aktiven Spielers bewegen sich.
Vorderste Karte zuerst → Kette kann aufrücken.
Linker Spieler (dir +1): höchste Slot-Zahl zuerst
Rechter Spieler (dir -1): niedrigste Slot-Zahl zuerst
════════════════════════════════════════════════════════ */
const myCards = [];
for (let slotIndex = 1; slotIndex <= 11; slotIndex++) {
for (const row of ['row1', 'row2']) {
const slotId = `${row}-slot-${slotIndex}`;
if (boardState[slotId]?.owner === activeSlot) {
myCards.push(slotId);
}
}
}
const isActiveLeft = activeSlot === leftSlot;
const dir = isActiveLeft ? 1 : -1;
// Vorderste Karte zuerst
myCards.sort((a, b) => {
const ia = parseInt(a.split('-slot-')[1], 10);
const ib = parseInt(b.split('-slot-')[1], 10);
return isActiveLeft ? ib - ia : ia - ib; // links: 11→1 | rechts: 1→11
});
for (const startSlotId of myCards) {
const entry = boardState[startSlotId];
if (!entry) continue;
const { card } = entry;
const row = startSlotId.split('-slot-')[0];
const race = card.race ?? 0;
let currentPos = parseInt(startSlotId.split('-slot-')[1], 10);
let currentSlotId = startSlotId;
for (let step = 0; step < race; step++) {
const nextPos = currentPos + dir;
if (nextPos < 1 || nextPos > 11) break;
const nextSlotId = `${row}-slot-${nextPos}`;
if (boardState[nextSlotId]) break; // eigene oder feindliche Karte blockiert
delete boardState[currentSlotId];
boardState[nextSlotId] = entry;
events.push({ type: 'move', from: currentSlotId, to: nextSlotId, owner: activeSlot });
currentSlotId = nextSlotId;
currentPos = nextPos;
}
}
/* ════════════════════════════════════════════════════════
PHASE 2: ANGRIFF
Nur Karten des aktiven Spielers greifen an.
Feste Reihenfolge: Slot 11 → 1, row1 vor row2.
Snapshot nach den Bewegungen.
════════════════════════════════════════════════════════ */
const attackOrder = [];
for (let slotIndex = 11; slotIndex >= 1; slotIndex--) {
for (const row of ['row1', 'row2']) {
const slotId = `${row}-slot-${slotIndex}`;
if (boardState[slotId]?.owner === activeSlot) {
attackOrder.push(slotId);
}
}
}
for (const slotId of attackOrder) {
const entry = boardState[slotId];
if (!entry) continue;
const { card } = entry;
const row = slotId.split('-slot-')[0];
const currentPos = parseInt(slotId.split('-slot-')[1], 10);
const range = card.range ?? 0;
for (let r = 1; r <= range; r++) {
const targetPos = currentPos + dir * r;
if (targetPos < 1 || targetPos > 11) break;
const targetSlotId = `${row}-slot-${targetPos}`;
const target = boardState[targetSlotId];
if (!target) continue; // leeres Feld → weiter scannen
if (target.owner === activeSlot) continue; // eigene Karte → Range geht hindurch
// Feindliche Karte → Angriff
const atk = card.attack ?? 0;
target.card = { ...target.card, defends: (target.card.defends ?? 0) - atk };
events.push({
type : 'attack',
from : slotId,
to : targetSlotId,
damage : atk,
remainingDef: target.card.defends,
});
if (target.card.defends <= 0) {
delete boardState[targetSlotId];
events.push({ type: 'die', slotId: targetSlotId });
}
break; // nur erste feindliche Karte angreifen
}
}
return events;
}
module.exports = { runCombatPhase };