Files
scrabble-online/client/public/scrabble/pieces.js
2021-05-10 22:22:15 +01:00

332 lines
8.5 KiB
JavaScript

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 putPiecesBack()
{
for (const piece of document.querySelectorAll('.staged-piece'))
{
piece.classList.remove('staged-piece');
piece.classList.remove('small-piece');
delete piece.dataset.coords;
DrawerSounds[Math.floor(Math.random() * 3)].play();
}
setupPieces();
}
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}<score>${piece.dataset.score}</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();