gjnhtedr
This commit is contained in:
parent
a85ac02f25
commit
ebb08e1160
@ -596,7 +596,7 @@ function registerArenaHandlers(io, socket) {
|
|||||||
const nextSlot = slot === "player1" ? "player2" : "player1";
|
const nextSlot = slot === "player1" ? "player2" : "player1";
|
||||||
|
|
||||||
/* ── Kampfphase berechnen ── */
|
/* ── Kampfphase berechnen ── */
|
||||||
const combatEvents = runCombatPhase(boardState, leftSlot);
|
const combatEvents = runCombatPhase(boardState, leftSlot, slot); // slot = aktiver Spieler
|
||||||
|
|
||||||
// boardCards nach Kampf aktualisieren (Karten die gestorben sind fehlen jetzt)
|
// boardCards nach Kampf aktualisieren (Karten die gestorben sind fehlen jetzt)
|
||||||
room.boardCards = boardStateToCards(boardState);
|
room.boardCards = boardStateToCards(boardState);
|
||||||
|
|||||||
@ -1,20 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* sockets/combat.js – Server-seitige Kampfphasen-Logik für 1v1
|
* sockets/combat.js – Server-seitige Kampfphasen-Logik für 1v1
|
||||||
*
|
*
|
||||||
* boardState-Format (server-seitig):
|
* ZWEI PHASEN PRO ZUG:
|
||||||
* { [slotId]: { card: { name, attack, defends, range, race, ... }, owner: 'player1'|'player2' } }
|
|
||||||
*
|
*
|
||||||
* Bewegungsrichtung:
|
* Phase 1 – BEWEGUNG (nur Karten des aktiven Spielers, vorderste zuerst)
|
||||||
* leftSlot-Spieler → dir = +1 (Slot 1 → 11)
|
* Phase 2 – ANGRIFF (nur Karten des aktiven Spielers, Slot 11→1)
|
||||||
* rightSlot-Spieler → dir = −1 (Slot 11 → 1)
|
|
||||||
*
|
|
||||||
* Verarbeitungs-Reihenfolge:
|
|
||||||
* Slot 11 → 1, pro Slot: row1 zuerst, dann row2
|
|
||||||
*
|
|
||||||
* Jede Karte wird genau einmal verarbeitet (Snapshot der Startreihenfolge).
|
|
||||||
* Bewegung: race Schritte vorwärts, stoppt vor eigener UND feindlicher Karte.
|
|
||||||
* Angriff: scannt range Felder vorwärts, überspringt eigene Karten,
|
|
||||||
* greift die erste feindliche Karte an (nur eine pro Zug).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -22,63 +12,93 @@
|
|||||||
/**
|
/**
|
||||||
* @param {Object} boardState – wird in-place verändert
|
* @param {Object} boardState – wird in-place verändert
|
||||||
* @param {string} leftSlot – 'player1' oder 'player2' (wer links steht)
|
* @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
|
* @returns {Array} – geordnete Event-Liste für den Client
|
||||||
*/
|
*/
|
||||||
function runCombatPhase(boardState, leftSlot) {
|
function runCombatPhase(boardState, leftSlot, activeSlot) {
|
||||||
const events = [];
|
const events = [];
|
||||||
|
|
||||||
/* ── Reihenfolge einmalig snapshot-en ──────────────────────────── */
|
/* ════════════════════════════════════════════════════════
|
||||||
const processingOrder = [];
|
PHASE 1: BEWEGUNG
|
||||||
for (let slotIndex = 11; slotIndex >= 1; slotIndex--) {
|
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']) {
|
for (const row of ['row1', 'row2']) {
|
||||||
const slotId = `${row}-slot-${slotIndex}`;
|
const slotId = `${row}-slot-${slotIndex}`;
|
||||||
if (boardState[slotId]) {
|
if (boardState[slotId]?.owner === activeSlot) {
|
||||||
processingOrder.push(slotId);
|
myCards.push(slotId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Jede Karte einzeln verarbeiten ────────────────────────────── */
|
const isActiveLeft = activeSlot === leftSlot;
|
||||||
for (const startSlotId of processingOrder) {
|
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];
|
const entry = boardState[startSlotId];
|
||||||
if (!entry) continue; // wurde in dieser Runde bereits getötet
|
if (!entry) continue;
|
||||||
|
|
||||||
const { card, owner } = entry;
|
const { card } = entry;
|
||||||
const isLeft = owner === leftSlot;
|
const row = startSlotId.split('-slot-')[0];
|
||||||
const dir = isLeft ? 1 : -1;
|
const race = card.race ?? 0;
|
||||||
const row = startSlotId.split('-slot-')[0]; // 'row1' oder 'row2'
|
|
||||||
|
|
||||||
let currentPos = parseInt(startSlotId.split('-slot-')[1], 10);
|
let currentPos = parseInt(startSlotId.split('-slot-')[1], 10);
|
||||||
let currentSlotId = startSlotId;
|
let currentSlotId = startSlotId;
|
||||||
|
|
||||||
/* ── BEWEGUNG (race) ──────────────────────────────────────────── */
|
|
||||||
const race = card.race ?? 0;
|
|
||||||
|
|
||||||
for (let step = 0; step < race; step++) {
|
for (let step = 0; step < race; step++) {
|
||||||
const nextPos = currentPos + dir;
|
const nextPos = currentPos + dir;
|
||||||
if (nextPos < 1 || nextPos > 11) break;
|
if (nextPos < 1 || nextPos > 11) break;
|
||||||
|
|
||||||
const nextSlotId = `${row}-slot-${nextPos}`;
|
const nextSlotId = `${row}-slot-${nextPos}`;
|
||||||
|
if (boardState[nextSlotId]) break; // eigene oder feindliche Karte blockiert
|
||||||
|
|
||||||
// Blockiert durch eigene ODER feindliche Karte → stehen bleiben
|
|
||||||
if (boardState[nextSlotId]) break;
|
|
||||||
|
|
||||||
// Slot frei → Karte verschieben
|
|
||||||
delete boardState[currentSlotId];
|
delete boardState[currentSlotId];
|
||||||
boardState[nextSlotId] = entry;
|
boardState[nextSlotId] = entry;
|
||||||
|
|
||||||
events.push({
|
events.push({ type: 'move', from: currentSlotId, to: nextSlotId, owner: activeSlot });
|
||||||
type : 'move',
|
|
||||||
from : currentSlotId,
|
|
||||||
to : nextSlotId,
|
|
||||||
owner,
|
|
||||||
});
|
|
||||||
|
|
||||||
currentSlotId = nextSlotId;
|
currentSlotId = nextSlotId;
|
||||||
currentPos = nextPos;
|
currentPos = nextPos;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ── ANGRIFF (range) ──────────────────────────────────────────── */
|
/* ════════════════════════════════════════════════════════
|
||||||
|
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;
|
const range = card.range ?? 0;
|
||||||
|
|
||||||
for (let r = 1; r <= range; r++) {
|
for (let r = 1; r <= range; r++) {
|
||||||
@ -88,37 +108,27 @@ function runCombatPhase(boardState, leftSlot) {
|
|||||||
const targetSlotId = `${row}-slot-${targetPos}`;
|
const targetSlotId = `${row}-slot-${targetPos}`;
|
||||||
const target = boardState[targetSlotId];
|
const target = boardState[targetSlotId];
|
||||||
|
|
||||||
// Leeres Feld → weiter scannen
|
if (!target) continue; // leeres Feld → weiter scannen
|
||||||
if (!target) continue;
|
if (target.owner === activeSlot) continue; // eigene Karte → Range geht hindurch
|
||||||
|
|
||||||
// Eigene Karte → Range geht hindurch (keine Aktion, weiter scannen)
|
// Feindliche Karte → Angriff
|
||||||
if (target.owner === owner) continue;
|
|
||||||
|
|
||||||
/* ── Feindliche Karte gefunden → Angriff ─────────────────── */
|
|
||||||
const atk = card.attack ?? 0;
|
const atk = card.attack ?? 0;
|
||||||
target.card = {
|
target.card = { ...target.card, defends: (target.card.defends ?? 0) - atk };
|
||||||
...target.card,
|
|
||||||
defends: (target.card.defends ?? 0) - atk,
|
|
||||||
};
|
|
||||||
|
|
||||||
events.push({
|
events.push({
|
||||||
type : 'attack',
|
type : 'attack',
|
||||||
from : currentSlotId,
|
from : slotId,
|
||||||
to : targetSlotId,
|
to : targetSlotId,
|
||||||
damage : atk,
|
damage : atk,
|
||||||
remainingDef: target.card.defends,
|
remainingDef: target.card.defends,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Karte sterben lassen wenn defends ≤ 0
|
|
||||||
if (target.card.defends <= 0) {
|
if (target.card.defends <= 0) {
|
||||||
delete boardState[targetSlotId];
|
delete boardState[targetSlotId];
|
||||||
events.push({
|
events.push({ type: 'die', slotId: targetSlotId });
|
||||||
type : 'die',
|
|
||||||
slotId: targetSlotId,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break; // Nur die erste feindliche Karte pro Runde angreifen
|
break; // nur erste feindliche Karte angreifen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,57 +136,3 @@ function runCombatPhase(boardState, leftSlot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { runCombatPhase };
|
module.exports = { runCombatPhase };
|
||||||
|
|
||||||
|
|
||||||
/* ═══════════════════════════════════════════════════════════════════
|
|
||||||
INTEGRATION IN DEN BESTEHENDEN SOCKET-SERVER
|
|
||||||
(nur als Referenz-Snippet – in die eigentliche arena-socket.js einbauen)
|
|
||||||
═══════════════════════════════════════════════════════════════════ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
const { runCombatPhase } = require('./combat');
|
|
||||||
|
|
||||||
// Pro Match einen boardState auf dem Server halten:
|
|
||||||
// matchBoards[matchId] = { [slotId]: { card, owner } }
|
|
||||||
const matchBoards = {};
|
|
||||||
const matchLeftSlot = {}; // matchLeftSlot[matchId] = 'player1' | 'player2'
|
|
||||||
|
|
||||||
// Wenn eine Karte gespielt wird → server-seitigen boardState aktualisieren:
|
|
||||||
socket.on('card_played', data => {
|
|
||||||
const { matchId, slot, boardSlot, card } = data;
|
|
||||||
if (!matchBoards[matchId]) matchBoards[matchId] = {};
|
|
||||||
matchBoards[matchId][boardSlot] = { card, owner: slot };
|
|
||||||
// ...weiter wie bisher (an Gegner broadcasten, boardSync etc.)
|
|
||||||
});
|
|
||||||
|
|
||||||
// leftSlot merken sobald er feststeht (z.B. in ready_status oder start_turn_request):
|
|
||||||
socket.on('start_turn_request', data => {
|
|
||||||
matchLeftSlot[data.matchId] = data.starterSlot;
|
|
||||||
// ...Zug starten wie bisher
|
|
||||||
});
|
|
||||||
|
|
||||||
// Nach end_turn: Kampfphase starten, dann Zug wechseln:
|
|
||||||
socket.on('end_turn', data => {
|
|
||||||
const { matchId, slot } = data;
|
|
||||||
const board = matchBoards[matchId] ?? {};
|
|
||||||
const leftSlot = matchLeftSlot[matchId] ?? 'player1';
|
|
||||||
|
|
||||||
// Kampfphase berechnen
|
|
||||||
const events = runCombatPhase(board, leftSlot);
|
|
||||||
|
|
||||||
// finalBoard als flaches Array für den boardSync senden
|
|
||||||
const finalBoard = Object.entries(board).map(([boardSlot, entry]) => ({
|
|
||||||
boardSlot,
|
|
||||||
card : entry.card,
|
|
||||||
owner: entry.owner,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// An BEIDE Spieler senden (Reihenfolge & Ergebnis ist identisch)
|
|
||||||
io.to(matchId).emit('combat_phase', { events, finalBoard });
|
|
||||||
|
|
||||||
// Cooldowns / Zug wechseln wie bisher
|
|
||||||
// ...
|
|
||||||
});
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user