const BOARD_W = 600; const BOARD_H = 600; // these change with resize let BOARD_X = document.querySelector('#game-container').getBoundingClientRect().left + window.scrollX; let BOARD_Y = document.querySelector('#game-container').getBoundingClientRect().top + window.scrollY; // is 80 while in drawer, otherwise 40 const PIECE_WIDTH = 80; const PIECE_HEIGHT = 80; let isHoldingPiece = false; //https://stackoverflow.com/questions/11409895/whats-the-most-elegant-way-to-cap-a-number-to-a-segment Number.prototype.clamp = function(min, max) { return Math.min(Math.max(this, min), max); }; const Drawer = document.querySelector('#piece-drawer'); // Expects structure [{letter: '', score: int}] function addPiecesToDrawer(pieces) { let ret = []; for (const piece of pieces) { const domPiece = document.createElement('piece'); domPiece.innerText = piece.letter; domPiece.classList.add('unselectable'); domPiece.classList.add('unplayed-piece'); const score = document.createElement('score'); score.innerText = piece.score; domPiece.dataset.letter = piece.letter; domPiece.dataset.score = piece.score; domPiece.appendChild(score); Drawer.appendChild(domPiece); ret.push(domPiece); } setupPieces(); updatePieceEventListeners(); return ret; } // Removes regardless of vadility function removePiecesFromDrawer(pieces) { if (pieces === '*') { Drawer.innerHTML = ''; return; } for (const piece of pieces) { piece.remove(); } } function updateBoardCoords() { BOARD_X = document.querySelector('#game-container').getBoundingClientRect().left + window.scrollX; BOARD_Y = document.querySelector('#game-container').getBoundingClientRect().top + window.scrollY; } function isCoordInBoard(px, py, pw, ph) { updateBoardCoords(); // to make it more readable let x = BOARD_X; let y = BOARD_Y; let w = BOARD_W; let h = BOARD_H; // cheeky bit of AABB if (x < px + pw && x + w > px && y < py + ph && y + h > py) return true; return false; } function boardCoordsFromScreenSpace(ssx, ssy) { updateBoardCoords(); let x = ssx - BOARD_X; let y = ssy - BOARD_Y; // make 1-15 so can work out what tile it's in x /= (BOARD_W / 15); y /= (BOARD_H / 15); x = x.clamp(0, 14); y = y.clamp(0, 14); y = Math.floor(y); x = Math.floor(x); return {x: x, y: y}; } function renderBoardState(pieces) { // adds all lol for (const piece of pieces) { if (!getPieceFromBoard(piece.pos.x, piece.pos.y)) { const domPiece = document.createElement('piece'); domPiece.innerText = piece.letter; domPiece.classList.add('unselectable'); domPiece.classList.add('small-piece'); domPiece.classList.add('played-piece'); const score = document.createElement('score'); score.innerText = piece.score; domPiece.dataset.coords = JSON.stringify(piece.pos); domPiece.dataset.letter = piece.letter; domPiece.dataset.score = piece.score; domPiece.appendChild(score); Drawer.appendChild(domPiece); placePieceOnBoard(domPiece, piece.pos.x, piece.pos.y) } } setupPieces(); } function removeStagedPieces() { for (const piece of document.querySelectorAll('.staged-piece')) piece.remove(); } // places for board coordinate (0-14) function placePieceOnBoard(piece, x, y) { x = (x * 40) + BOARD_X + 1; y = (y * 40) + BOARD_Y + 1; // undo offset piece.style.left = `${x}px`; piece.style.top = `${y}px`; } function getPieceFromBoard(x, y) { for (const piece of document.querySelectorAll('piece')) { if (!piece.dataset.coords) continue; let coords = JSON.parse(piece.dataset.coords); if (coords.x === x && coords.y === y) return piece; } return false; } // staged pieces are played but the turn is not applied function getAllStagedPieces() { let ret = []; for (const piece of document.querySelectorAll('.staged-piece')) { ret.push(piece); } return ret; } function getAllPiecesOnBoard() { let ret = []; for (const piece of document.querySelectorAll('piece')) { if (piece.dataset.coords) { ret.push(piece); } } return ret; } // events from drag & drop api function piecePickedUp(piece) { if (!piece) return; if (isHoldingPiece) return; delete piece.dataset.coords; BoardSounds[2].play(); piece.classList.add('small-piece'); isHoldingPiece = true; } // events from drag & drop api function piecePlaced(piece) { if (!piece) return; if (!isHoldingPiece) return; // snap to board if in box if (isCoordInBoard(piece.offsetLeft, piece.offsetTop, 40, 40)) { updateBoardCoords(); let coords = boardCoordsFromScreenSpace(piece.offsetLeft + 20, piece.offsetTop + 20); if (getPieceFromBoard(coords.x, coords.y)) return false; BoardSounds[0].play(); placePieceOnBoard(piece, coords.x, coords.y); piece.classList.remove('unplayed-piece'); piece.classList.add('staged-piece'); piece.dataset.coords = JSON.stringify(coords); // Wildcard! (done clientside because of laziness) let letter = piece.dataset.letter; if (letter === '_') { // TODO: this would be a pretty good function for elsewhere.. const tilesetincludes = (l) => { for (const range of TileSet) if (range.letters.includes(l)) return true; return false; }; letter = prompt('You placed a wildcard! what would you like the letter to be?').toUpperCase(); if (letter === null || !tilesetincludes(letter)) { DrawerSounds[Math.floor(Math.random() * 3)].play(); piece.classList.remove('staged-piece'); piece.classList.remove('small-piece'); piece.classList.add('unplayed-piece'); delete piece.dataset.coords; setupPieces(); return; } piece.dataset.letter = letter; // no way to work this out here let score = -1; for (const range in TileSet) if (TileSet[range].letters.includes(letter)) score = TileSet[range].points; piece.dataset.score = score; piece.innerHTML = `${piece.dataset.letter}${piece.dataset.score}`; } setupPieces(); } else { DrawerSounds[Math.floor(Math.random() * 3)].play(); piece.classList.remove('staged-piece'); piece.classList.remove('small-piece'); piece.classList.add('unplayed-piece'); delete piece.dataset.coords; setupPieces(); } isHoldingPiece = false; return true; } function setupPieces() // also resets pieces { // TODO: this caused some weird html scaling bugs where the // flexboxes wouldn't update, fix this vvv // if the window has enough vertical height to fit the peices, // have them at the bottom of the board, else, have them to the right // needs to happen after resize updateBoardCoords(); let index = 0; for (const piece of document.querySelectorAll('piece, nopiece')) { if (piece.classList.contains('played-piece') || piece.classList.contains('staged-piece')) continue; // i feel dirty hardcoding this much const dx = (BOARD_X) + (index * (PIECE_WIDTH + 5)) + 5; const dy = (BOARD_Y + BOARD_H) + 10; piece.style.left = `${dx}px`; piece.style.top = `${dy}px`; index++; } for (const piece of document.querySelectorAll('.played-piece, .staged-piece')) { // cheating lol if (!piece.dataset.coords) continue; let coords = JSON.parse(piece.dataset.coords); placePieceOnBoard(piece, coords.x, coords.y); } } setupPieces();