332 lines
8.5 KiB
JavaScript
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();
|
|
|