import React, { useState } from "react"; import "./Board.css"; const base = process.env.PUBLIC_URL; const assetsPath = `${base}/assets`; const Board = ({ table, game }) => { const rows = [3, 4, 5, 4, 3, 2]; /* The final row of 2 is to place roads and corners */ const [signature, setSignature] = useState(""); const [pips, setPips] = useState(<>); const [borders, setBorders] = useState(<>); const [tiles, setTiles] = useState(<>); const [corners, setCorners] = useState(<>); const [roads, setRoads] = useState(<>); const [transform, setTransform] = useState(1); const hexRatio = 1.1547, tileWidth = 67, tileHalfWidth = tileWidth * 0.5, tileHeight = tileWidth * hexRatio, tileHalfHeight = tileHeight * 0.5, radius = tileHeight * 2, borderOffsetX = 86, /* ~1/10th border image width... hand tuned */ borderOffsetY = 3; /* Actual sizing */ const tileImageWidth = 90, /* Based on hand tuned and image width */ tileImageHeight = tileImageWidth/hexRatio, borderImageWidth = (2 + 2/3) * tileImageWidth, /* 2.667 * .Tile.width */ borderImageHeight = borderImageWidth * 0.29; /* 0.29 * .Border.height */ const Tile = ({tile}) => { const onClick = (event) => { console.log(`Tile clicked: ${tile.index}`); }; return
; }; const Road = ({road}) => { const onClick = (event) => { console.log(`Road clicked: ${road.index}`); table.placeRoad(road.index); }; return
; }; const Corner = ({corner}) => { const onClick = (event) => { console.log(`Corner ${corner.index}:`, game.layout.corners[corner.index]); table.placeSettlement(corner.index); return; }; return
; }; const generateRoads = () => { let row = 0, rowCount = 0; let y = -2.5 + tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, x = -tileHalfHeight -(rows[row] - 1) * 0.5 * tileHeight; let index = 0; let road; const corners = []; for (let i = 0; i < 21; i++) { const lastRow = row === rows.length - 1; if (row > 2 && rowCount === 0) { road = { index: index++, angle: -60, top: y-0.5*tileHalfHeight, left: x-tileHalfHeight }; corners.push(); } road = { index: index++, angle: 240, top: y, left: x }; corners.push(); road = { index: index++, angle: -60, top: y-0.5*tileHalfHeight, left: x+tileHalfHeight }; corners.push(); if (!lastRow) { road = { index: index++, angle: 0, top: y, left: x }; corners.push(); } if (++rowCount === rows[row]) { if (!lastRow) { road = { index: index++, angle: 0, top: y, left: x+2.*tileHalfHeight }; corners.push(); } if (row > 2) { road = { index: index++, angle: 60, top: y-0.5*tileHalfHeight, left: x+3.*tileHalfHeight }; corners.push(); } row++; rowCount = 0; y += tileHeight - 10.5; x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight; } else { x += tileHeight; } } return corners; } const generateCorners = () => { let row = 0, rowCount = 0; let y = -8 + 0.5 * tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, x = -tileHalfHeight -(rows[row] - 1) * 0.5 * tileHeight; let index = 0; const corners = []; let corner; for (let i = 0; i < 21; i++) { if (row > 2 && rowCount === 0) { corner = { index: index++, top: y-0.5*tileHalfHeight, left: x-tileHalfHeight }; corners.push(); } corner = { index: index++, top: y, left: x }; corners.push(); corner = { index: index++, top: y-0.5*tileHalfHeight, left: x+tileHalfHeight }; corners.push(); if (++rowCount === rows[row]) { corner = { index: index++, top: y, left: x+2.*tileHalfHeight }; corners.push(); if (row > 2) { corner = { index: index++, top: y-0.5*tileHalfHeight, left: x+3.*tileHalfHeight }; corners.push(); } row++; rowCount = 0; y += tileHeight - 10.5; x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight; } else { x += tileHeight; } } return corners; } const generatePips = () => { let row = 0, rowCount = 0; let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, x = -(rows[row] - 1) * 0.5 * tileHeight; return game.pipOrder.map(order => { const pip = game.pips[order]; const div =
; if (++rowCount === rows[row]) { row++; rowCount = 0; y += tileWidth; x = - (rows[row] - 1) * 0.5 * tileHeight; } else { x += tileHeight; } return div; }); }; const generateTiles = () => { let row = 0, rowCount = 0; let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, x = -(rows[row] - 1) * 0.5 * tileHeight; let index = 0; return game.tileOrder.map(order => { const tile = Object.assign({}, game.tiles[order], { index: index++, left: x, top: y}); let div = ; if (++rowCount === rows[row]) { row++; rowCount = 0; y += tileWidth; x = - (rows[row] - 1) * 0.5 * tileHeight; } else { x += tileHeight; } return div; }); }; const generateBorders = () => { const sides = 6; let side = -1; return game.borderOrder.map(order => { const border = game.borders[order]; side++; let x = + Math.sin(Math.PI - side / sides * 2. * Math.PI) * radius, y = Math.cos(Math.PI - side / sides * 2. * Math.PI) * radius; let prev = (order === 0) ? 6 : order; const file = `borders-${order+1}.${prev}.png`; return
; }); }; /* If the game is loaded, and the signature is different, * regenerate everything */ if (game && game.signature !== signature) { console.log(`Generate for ${game.signature}`); setPips(generatePips); setBorders(generateBorders); setTiles(generateTiles); setCorners(generateCorners); setRoads(generateRoads); setSignature(game.signature); } else { if (!game) { console.log(`No game in Board`); } } /* Adjust the 'transform: scale' for the BoardBox * so the board fills the Board * * The board is H tall, and H * hexRatio wide */ const board = document.querySelector('.Board'); if (board) { const width = board.offsetWidth, height = board.offsetHeight; let _transform; if (height * hexRatio > width) { _transform = width / (450. * hexRatio); } else { _transform = height / (450.); } if (_transform !== transform) { const boardBox = board.querySelector('.BoardBox'); if (boardBox) { console.log(`Setting transofrm scale to ${_transform}`); boardBox.style.transform = `scale(${_transform})`; } setTransform(_transform); } } if (game && game.placements) { /* Set color and type based on placement data from the server */ game.placements.corners.forEach((corner, index) => { const el = document.querySelector(`.Corner[data-index="${index}"]`); if (!el) { return; } if (!corner.color) { el.removeAttribute('data-color'); el.removeAttribute('data-type'); } else { el.setAttribute('data-color', corner.color); el.setAttribute('data-type', corner.type); } }); game.placements.roads.forEach((road, index) => { const el = document.querySelector(`.Road[data-index="${index}"]`); if (!el) { return; } if (!road.color) { el.removeAttribute('data-color'); } else { el.setAttribute('data-color', road.color); } }); /* Clear all 'Option' targets */ const nodes = document.querySelectorAll(`.Option`); for (let i = 0; i < nodes.length; i++) { nodes[i].classList.remove('Option'); } /* Add 'Option' based on game.turn.limits */ if (game.turn && game.turn.limits) { if (game.turn.limits['roads']) { game.turn.limits['roads'].forEach(index => { const el = document.querySelector(`.Road[data-index="${index}"]`); if (!el) { return; } el.classList.add('Option'); }); } if (game.turn.limits['corners']) { game.turn.limits['corners'].forEach(index => { const el = document.querySelector(`.Corner[data-index="${index}"]`); if (!el) { return; } el.classList.add('Option'); }); } } } const canAction = (action) => { return (game && game.turn && Array.isArray(game.turn.actions) && game.turn.actions.indexOf(action) !== -1); }; return (
{ borders } { tiles } { pips } { game && <>
{ corners }
{ roads }
}
); }; export default Board;