feat(catan): add debug mode for free roads/ships and improve fog revelation
- Add DEBUG_FREE_ROADS_AND_SHIPS flag to bypass resource costs for testing - Extend fog hex revelation to include corner-adjacent hexes, not just edge-adjacent - Restructure button enable logic to support debug mode in UI - Initialize hexTileFrames map in CatanGame setup
This commit is contained in:
parent
c9192cda75
commit
1e607e5802
|
|
@ -132,6 +132,7 @@ export default class CatanGame extends Phaser.Scene {
|
||||||
this.hexImgs = [];
|
this.hexImgs = [];
|
||||||
this.hexLabels.forEach((t) => t.destroy());
|
this.hexLabels.forEach((t) => t.destroy());
|
||||||
this.hexLabels = [];
|
this.hexLabels = [];
|
||||||
|
this.hexTileFrames = {};
|
||||||
|
|
||||||
// Inset a convex hex polygon toward its center.
|
// Inset a convex hex polygon toward its center.
|
||||||
// s=0 collapses to point; s=1 is original. Uses inradius (79.7px) as scale reference.
|
// s=0 collapses to point; s=1 is original. Uses inradius (79.7px) as scale reference.
|
||||||
|
|
@ -1551,12 +1552,13 @@ export default class CatanGame extends Phaser.Scene {
|
||||||
const action = me && s.phase === 'action';
|
const action = me && s.phase === 'action';
|
||||||
const set = (k, on) => this.buttons[k]?.setEnabled(!!on);
|
const set = (k, on) => this.buttons[k]?.setEnabled(!!on);
|
||||||
const hasSettleSpot = action && L.legalSettlementNodes(s, 0, false).length > 0;
|
const hasSettleSpot = action && L.legalSettlementNodes(s, 0, false).length > 0;
|
||||||
|
const DEBUG_FREE_ROADS_AND_SHIPS = false;
|
||||||
const hasRoadSpot = action && L.legalRoadEdges(s, 0, false).length > 0;
|
const hasRoadSpot = action && L.legalRoadEdges(s, 0, false).length > 0;
|
||||||
set('roll', me && s.phase === 'rollPhase');
|
set('roll', me && s.phase === 'rollPhase');
|
||||||
set('road', (action && hasRoadSpot && L.canAfford(p, COSTS.road)) || (action && s.freeRoads > 0 && hasRoadSpot));
|
set('road', action && hasRoadSpot && (DEBUG_FREE_ROADS_AND_SHIPS && me || L.canAfford(p, COSTS.road) || s.freeRoads > 0));
|
||||||
const hasShipSpot = action && L.legalShipEdges(s, 0).length > 0;
|
const hasShipSpot = action && L.legalShipEdges(s, 0).length > 0;
|
||||||
const sCost = L.shipCost(s);
|
const sCost = L.shipCost(s);
|
||||||
set('ship', hasShipSpot && ((action && sCost && L.canAfford(p, sCost)) || (action && s.freeShips > 0)));
|
set('ship', hasShipSpot && action && (DEBUG_FREE_ROADS_AND_SHIPS && me || !sCost || L.canAfford(p, sCost) || s.freeShips > 0));
|
||||||
set('settlement', hasSettleSpot && L.canAfford(p, COSTS.settlement));
|
set('settlement', hasSettleSpot && L.canAfford(p, COSTS.settlement));
|
||||||
set('city', action && p.settlements.length > 0 && L.canAfford(p, COSTS.city));
|
set('city', action && p.settlements.length > 0 && L.canAfford(p, COSTS.city));
|
||||||
set('buyDev', action && s.devDeck.length > 0 && L.canAfford(p, COSTS.devCard));
|
set('buyDev', action && s.devDeck.length > 0 && L.canAfford(p, COSTS.devCard));
|
||||||
|
|
|
||||||
|
|
@ -414,13 +414,15 @@ export function moveRobber(state, hexId, targetSeat = null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── building ───────────────────────────────────────────────────────────────────
|
// ── building ───────────────────────────────────────────────────────────────────
|
||||||
|
const DEBUG_FREE_ROADS_AND_SHIPS = false;
|
||||||
|
|
||||||
export function buildRoad(state, seat, edgeId) {
|
export function buildRoad(state, seat, edgeId) {
|
||||||
const s = cloneState(state);
|
const s = cloneState(state);
|
||||||
if (s.phase !== 'action' || s.currentPlayer !== seat) return s;
|
if (s.phase !== 'action' || s.currentPlayer !== seat) return s;
|
||||||
if (!legalRoadEdges(s, seat, false).includes(edgeId)) return s;
|
if (!legalRoadEdges(s, seat, false).includes(edgeId)) return s;
|
||||||
const free = s.freeRoads > 0;
|
const free = s.freeRoads > 0;
|
||||||
if (!free && !canAfford(s.players[seat], COSTS.road)) return s;
|
if (!free && !canAfford(s.players[seat], COSTS.road) && !(DEBUG_FREE_ROADS_AND_SHIPS && seat === 0)) return s;
|
||||||
if (free) s.freeRoads--; else pay(s, s.players[seat], COSTS.road);
|
if (free) s.freeRoads--; else if (!(DEBUG_FREE_ROADS_AND_SHIPS && seat === 0)) pay(s, s.players[seat], COSTS.road);
|
||||||
s.players[seat].roads.push(edgeId);
|
s.players[seat].roads.push(edgeId);
|
||||||
revealFogHexes(s, edgeId);
|
revealFogHexes(s, edgeId);
|
||||||
recomputeLongestRoad(s);
|
recomputeLongestRoad(s);
|
||||||
|
|
@ -428,10 +430,14 @@ export function buildRoad(state, seat, edgeId) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reveal any fog hexes that share an edge with edgeId.
|
// Reveal any fog hexes that share an edge or a corner (node) with edgeId.
|
||||||
function revealFogHexes(s, edgeId) {
|
function revealFogHexes(s, edgeId) {
|
||||||
const geo = geoFor(s);
|
const geo = geoFor(s);
|
||||||
for (const hexId of geo.edges[edgeId].hexes) {
|
const [a, b] = geo.edges[edgeId].nodes;
|
||||||
|
// Check all hexes touching either endpoint node — this catches fog hexes
|
||||||
|
// that share only a corner with the road/ship edge.
|
||||||
|
const hexIds = new Set([...geo.nodes[a].hexes, ...geo.nodes[b].hexes]);
|
||||||
|
for (const hexId of hexIds) {
|
||||||
const hex = s.hexes[hexId];
|
const hex = s.hexes[hexId];
|
||||||
if (!hex || hex.kind !== 'fog') continue;
|
if (!hex || hex.kind !== 'fog') continue;
|
||||||
if (hex.fogData) {
|
if (hex.fogData) {
|
||||||
|
|
@ -496,8 +502,8 @@ export function buildShip(state, seat, edgeId) {
|
||||||
if (!legalShipEdges(s, seat).includes(edgeId)) return s;
|
if (!legalShipEdges(s, seat).includes(edgeId)) return s;
|
||||||
const cost = shipCost(s);
|
const cost = shipCost(s);
|
||||||
const free = s.freeShips > 0;
|
const free = s.freeShips > 0;
|
||||||
if (!free && !canAfford(s.players[seat], cost)) return s;
|
if (!free && !canAfford(s.players[seat], cost) && !(DEBUG_FREE_ROADS_AND_SHIPS && seat === 0)) return s;
|
||||||
if (free) s.freeShips--; else pay(s, s.players[seat], cost);
|
if (free) s.freeShips--; else if (!(DEBUG_FREE_ROADS_AND_SHIPS && seat === 0)) pay(s, s.players[seat], cost);
|
||||||
s.players[seat].ships.push(edgeId);
|
s.players[seat].ships.push(edgeId);
|
||||||
revealFogHexes(s, edgeId);
|
revealFogHexes(s, edgeId);
|
||||||
recomputeLongestRoad(s);
|
recomputeLongestRoad(s);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue