feat: Hex Wars - Schlangen-Mechanik, nur vom Kopf aus expandieren
This commit is contained in:
@@ -35,7 +35,7 @@ function HelpModal({ onClose }) {
|
||||
</p>
|
||||
|
||||
<p><strong style={{ color:'#fff' }}>Ablauf:</strong><br/>
|
||||
Beide starten in gegenüberliegenden Ecken. Reihum wählst du ein freies Feld das an dein Gebiet grenzt (auch diagonal) und besetzt es. Tippe es an, bestätige — fertig.
|
||||
Beide starten in gegenüberliegenden Ecken. Du hast einen <strong style={{ color:myColor }}>Kopf</strong> — dein letzter Zug, markiert mit einem leuchtenden Rahmen. Du kannst <strong>nur an den Kopf anbauen</strong> (alle 8 Richtungen). Dein Gebiet bleibt erhalten, aber du kannst nicht mehr von alten Feldern aus expandieren. Tippe ein Feld an, bestätige — fertig.
|
||||
</p>
|
||||
|
||||
<div style={{ background:'rgba(255,255,255,0.04)', borderRadius:8, padding:'12px 14px', marginBottom:12, border:'1px solid rgba(255,255,255,0.08)' }}>
|
||||
@@ -169,18 +169,27 @@ function GameBoard({ game, myId, onMove, toast }) {
|
||||
} catch {}
|
||||
}, [game.last_event]);
|
||||
|
||||
const isAdj = (r, c) => DIRS8.some(([dr,dc]) => {
|
||||
const nr=r+dr, nc=c+dc;
|
||||
return nr>=0&&nr<GRID&&nc>=0&&nc<GRID&&grid[nr][nc]===myId;
|
||||
});
|
||||
// Schlangen-Kopf aus Server-Response
|
||||
const myHeadStr = game.myHead;
|
||||
const myHead = myHeadStr ? myHeadStr.split(',').map(Number) : null;
|
||||
const [myHR, myHC] = myHead ?? [null, null];
|
||||
|
||||
const isAdjacentToHead = (r, c) => {
|
||||
if (myHR === null) return false;
|
||||
return Math.abs(r - myHR) <= 1 && Math.abs(c - myHC) <= 1 && !(r === myHR && c === myHC);
|
||||
};
|
||||
|
||||
const canClick = (r, c) => {
|
||||
if (!isMyTurn || game.status !== 'active') return false;
|
||||
if (grid[r][c] !== 0) return false;
|
||||
// T_ROCK kommt vom Server auch im Nebel nicht — Felsen sind immer sichtbar
|
||||
// T_FOG darf canClick NICHT blocken: Felder können klickbar aber noch im Nebel sein
|
||||
if (hasTerrain && terrain[r][c] === T_ROCK) return false;
|
||||
return isAdj(r, c);
|
||||
// Schlangen-Regel: nur Felder an den Kopf
|
||||
if (myHead) return isAdjacentToHead(r, c);
|
||||
// Fallback für alte Spiele ohne head
|
||||
return DIRS8.some(([dr,dc]) => {
|
||||
const nr=r+dr, nc=c+dc;
|
||||
return nr>=0&&nr<GRID&&nc>=0&&nc<GRID&&grid[nr][nc]===myId;
|
||||
});
|
||||
};
|
||||
|
||||
const handleCellClick = (r, c) => {
|
||||
@@ -243,6 +252,7 @@ function GameBoard({ game, myId, onMove, toast }) {
|
||||
const clic = canClick(r, c);
|
||||
const isPend = pending?.row === r && pending?.col === c;
|
||||
const isBlast = blastHighlight.has(`${r}-${c}`);
|
||||
const isHead = myHR === r && myHC === c; // eigener Kopf
|
||||
const isFog = t === T_FOG;
|
||||
const isRock = t === T_ROCK;
|
||||
const isGold = t === T_GOLD;
|
||||
@@ -271,8 +281,9 @@ function GameBoard({ game, myId, onMove, toast }) {
|
||||
}
|
||||
|
||||
if (isBlast) { bg = '#ff440066'; border = '2px solid #ff4400'; }
|
||||
if (isHead && !isPend) { border = `2px solid ${myColor}`; } // Kopf immer markieren
|
||||
if (isPend) { bg = myColor; border = `2px solid ${myColor}`; }
|
||||
else if (clic && !isPend && !isBlast) border = `1px solid ${myColor}44`;
|
||||
else if (clic && !isPend && !isBlast && !isHead) border = `1px solid ${myColor}44`;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -341,7 +352,7 @@ function GameBoard({ game, myId, onMove, toast }) {
|
||||
)}
|
||||
{isMyTurn && !pending && (
|
||||
<div style={{ color:myColor, fontFamily:'monospace', fontSize:11, textAlign:'center', padding:'4px 0' }}>
|
||||
▶ Wähle ein Feld — Vorsicht vor Minen! 💣
|
||||
▶ Baue vom Kopf aus — Vorsicht vor Minen! 💣
|
||||
</div>
|
||||
)}
|
||||
{pending && (
|
||||
|
||||
Reference in New Issue
Block a user