mirror of
https://github.com/AndrioCelos/TableturfBattleApp.git
synced 2026-08-28 13:53:59 -05:00
Flip board view for players 2 and 4
This commit is contained in:
@@ -85,7 +85,7 @@
|
||||
<input type="radio" id="stageRandomButton" name="stage" value="random" checked/> Random
|
||||
</label>
|
||||
</div>
|
||||
<p id="stageListLoadingSection"><div class="lds-ripple"><div></div><div></div></div> Loading stages...</p>
|
||||
<div id="stageListLoadingSection"><div class="lds-ripple"><div></div><div></div></div> Loading stages...</div>
|
||||
</form>
|
||||
</section>
|
||||
<div id="lobbyDeckSection" hidden>
|
||||
@@ -155,14 +155,16 @@
|
||||
<a id="resultLeaveButton" href="#">Leave game</a>
|
||||
</div>
|
||||
<div id="replayControls" hidden>
|
||||
<input type="checkbox" id="replayFlipBox" autocomplete="off"/>
|
||||
<label for="replayFlipBox">Flip board</label>
|
||||
<button id="replayPreviousButton">Previous turn</button>
|
||||
<button id="replayNextButton">Next turn</button>
|
||||
<a id="replayLeaveButton" href="#">Exit replay</a>
|
||||
</div>
|
||||
|
||||
<div class="playerBar" data-index="0">
|
||||
<div class="playerBar" data-index="2">
|
||||
<div class="result"></div>
|
||||
<div class="name">Player 1</div>
|
||||
<div class="name">Player 3</div>
|
||||
<div class="specialPoints"> </div>
|
||||
<div class="playerStats">
|
||||
<div class="statSpecialPoints">
|
||||
@@ -175,9 +177,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="playerBar" data-index="2">
|
||||
<div class="playerBar" data-index="0">
|
||||
<div class="result"></div>
|
||||
<div class="name">Player 3</div>
|
||||
<div class="name">Player 1</div>
|
||||
<div class="specialPoints"> </div>
|
||||
<div class="playerStats">
|
||||
<div class="statSpecialPoints">
|
||||
@@ -205,12 +207,10 @@
|
||||
<div id="turnNumberLabel">12</div>
|
||||
</div>
|
||||
<div id="scoreSection">
|
||||
<div id="pointsContainers">
|
||||
<div class="pointsContainer" data-index="2"><span class="points">69</span><span class="pointsToContainer">↪ <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
|
||||
<div class="pointsContainer" data-index="1"><span class="points">69</span><span class="pointsToContainer">↪ <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
|
||||
<div class="pointsContainer" data-index="0"><span class="points">69</span><span class="pointsToContainer">↪ <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
|
||||
<div class="pointsContainer" data-index="3"><span class="points">69</span><span class="pointsToContainer">↪ <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
|
||||
</div>
|
||||
<div class="pointsContainer" data-index="1"><span class="points">69</span><span class="pointsToContainer">↪ <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
|
||||
<div class="pointsContainer" data-index="3"><span class="points">69</span><span class="pointsToContainer">↪ <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
|
||||
<div class="pointsContainer" data-index="2"><span class="points">69</span><span class="pointsToContainer">↪ <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
|
||||
<div class="pointsContainer" data-index="0"><span class="points">69</span><span class="pointsToContainer">↪ <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
|
||||
</div>
|
||||
<div id="boardSection">
|
||||
<table id="gameBoard" tabindex="0"></table>
|
||||
@@ -231,8 +231,8 @@
|
||||
|
||||
<div class="playContainer" data-index="1"></div>
|
||||
<div class="playContainer" data-index="3"></div>
|
||||
<div class="playContainer" data-index="0"></div>
|
||||
<div class="playContainer" data-index="2"></div>
|
||||
<div class="playContainer" data-index="0"></div>
|
||||
</div>
|
||||
<div id="deckListPage" hidden>
|
||||
<section id="deckEditordeckListPage">
|
||||
|
||||
@@ -10,6 +10,7 @@ class Board {
|
||||
|
||||
autoHighlight = true;
|
||||
touchscreenMode = false;
|
||||
flip = false;
|
||||
|
||||
highlightX = NaN;
|
||||
highlightY = NaN;
|
||||
@@ -38,16 +39,16 @@ class Board {
|
||||
this.moveHighlight((x, y, r) => [x, y, r - 1], false);
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
this.moveHighlight((x, y, r) => [x, y - 1, r], true);
|
||||
this.moveHighlight((x, y, r) => [x, y + (this.flip ? 1 : -1), r], true);
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
this.moveHighlight((x, y, r) => [x, y + 1, r], true);
|
||||
this.moveHighlight((x, y, r) => [x, y + (this.flip ? -1 : 1), r], true);
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
this.moveHighlight((x, y, r) => [x - 1, y, r], true);
|
||||
this.moveHighlight((x, y, r) => [x + (this.flip ? 1 : -1), y, r], true);
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
this.moveHighlight((x, y, r) => [x + 1, y, r], true);
|
||||
this.moveHighlight((x, y, r) => [x + (this.flip ? -1 : 1), y, r], true);
|
||||
break;
|
||||
case 'Enter': case ' ':
|
||||
if (this.onclick)
|
||||
@@ -67,9 +68,9 @@ class Board {
|
||||
const touch = e.changedTouches[0];
|
||||
if (isNaN(this.highlightX) || isNaN(this.highlightY) || isNaN(this.cardRotation)) {
|
||||
const startSpace = this.startSpaces[this.playerIndex];
|
||||
this.highlightX = startSpace.x - 3;
|
||||
this.highlightY = startSpace.y - 3;
|
||||
this.cardRotation = 0;
|
||||
this.highlightX = startSpace.x - (this.flip ? 4 : 3);
|
||||
this.highlightY = startSpace.y - (this.flip ? 4 : 3);
|
||||
this.cardRotation = this.flip ? 2 : 0;
|
||||
this.refreshHighlight();
|
||||
}
|
||||
this.touch = [touch.identifier, touch.pageX, touch.pageY, this.highlightX, this.highlightY];
|
||||
@@ -105,7 +106,7 @@ class Board {
|
||||
if (this.playerIndex == null) return;
|
||||
if (this.highlightedCells.length == 0 || isNaN(this.highlightX) || isNaN(this.highlightY) || isNaN(this.cardRotation)) {
|
||||
const startSpace = this.startSpaces[this.playerIndex];
|
||||
[this.highlightX, this.highlightY, this.cardRotation] = [startSpace.x - 3, startSpace.y - 3, 0];
|
||||
[this.highlightX, this.highlightY, this.cardRotation] = [startSpace.x - (this.flip ? 4 : 3), startSpace.y - (this.flip ? 4 : 3), 0];
|
||||
} else {
|
||||
let [x, y, r] = move(this.highlightX, this.highlightY, this.cardRotation);
|
||||
let clampedPosition = clamp
|
||||
@@ -193,44 +194,33 @@ class Board {
|
||||
this.highlightedCells.splice(0);
|
||||
}
|
||||
|
||||
resize(grid: Space[][]) {
|
||||
if (grid.length == 0)
|
||||
throw new Error('Grid must not be empty.');
|
||||
|
||||
this.grid = grid || this.grid;
|
||||
resize(grid?: Space[][]) {
|
||||
if (grid) this.grid = grid;
|
||||
|
||||
clearChildren(this.table);
|
||||
this.cells.splice(0);
|
||||
this.highlightedCells.splice(0);
|
||||
|
||||
const boardWidth = grid.length;
|
||||
const boardHeight = grid[0].length;
|
||||
const boardWidth = this.grid.length;
|
||||
const boardHeight = this.grid[0].length;
|
||||
|
||||
this.table.style.setProperty('--board-width', boardWidth.toString());
|
||||
this.table.style.setProperty('--board-height', boardHeight.toString());
|
||||
|
||||
const trs: HTMLTableRowElement[] = [ ];
|
||||
for (let y = 0; y < boardHeight; y++) {
|
||||
const tr = document.createElement('tr');
|
||||
trs.push(tr);
|
||||
this.table.appendChild(tr);
|
||||
}
|
||||
|
||||
for (let x = 0; x < boardWidth; x++) {
|
||||
const col: HTMLTableCellElement[] = [ ];
|
||||
for (let y = 0; y < grid[x].length; y++) {
|
||||
for (let y = 0; y < this.grid[x].length; y++) {
|
||||
const td = document.createElement('td');
|
||||
td.dataset.x = x.toString();
|
||||
td.dataset.y = y.toString();
|
||||
trs[y].appendChild(td);
|
||||
col.push(td);
|
||||
td.addEventListener('mousemove', e => {
|
||||
if (e.buttons == 0)
|
||||
this.touchscreenMode = false;
|
||||
if (!this.touchscreenMode) {
|
||||
if (this.autoHighlight && this.cardPlaying != null) {
|
||||
const x = parseInt((e.target as HTMLTableCellElement).dataset.x!) - 3;
|
||||
const y = parseInt((e.target as HTMLTableCellElement).dataset.y!) - 3;
|
||||
const x = parseInt((e.target as HTMLTableCellElement).dataset.x!) - (this.flip ? 4 : 3);
|
||||
const y = parseInt((e.target as HTMLTableCellElement).dataset.y!) - (this.flip ? 4 : 3);
|
||||
if (x != this.highlightX || y != this.highlightY) {
|
||||
this.highlightX = x;
|
||||
this.highlightY = y;
|
||||
@@ -244,8 +234,8 @@ class Board {
|
||||
if (this.touchscreenMode) {
|
||||
this.onclick(this.highlightX, this.highlightY);
|
||||
} else {
|
||||
const x = parseInt((e.target as HTMLTableCellElement).dataset.x!) - 3;
|
||||
const y = parseInt((e.target as HTMLTableCellElement).dataset.y!) - 3;
|
||||
const x = parseInt((e.target as HTMLTableCellElement).dataset.x!) - (this.flip ? 4 : 3);
|
||||
const y = parseInt((e.target as HTMLTableCellElement).dataset.y!) - (this.flip ? 4 : 3);
|
||||
this.onclick(x, y);
|
||||
}
|
||||
}
|
||||
@@ -262,6 +252,26 @@ class Board {
|
||||
this.cells.push(col);
|
||||
}
|
||||
|
||||
const trs: HTMLTableRowElement[] = [ ];
|
||||
for (let y = 0; y < boardHeight; y++) {
|
||||
const tr = document.createElement('tr');
|
||||
trs.push(tr);
|
||||
this.table.appendChild(tr);
|
||||
}
|
||||
if (this.flip) trs.reverse();
|
||||
|
||||
for (let y = 0; y < boardHeight; y++) {
|
||||
if (this.flip) {
|
||||
for (let x = boardWidth - 1; x >= 0; x--) {
|
||||
trs[y].appendChild(this.cells[x][y]);
|
||||
}
|
||||
} else {
|
||||
for (let x = 0; x < boardWidth; x++) {
|
||||
trs[y].appendChild(this.cells[x][y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ const resultElement = document.getElementById('result')!;
|
||||
const replayControls = document.getElementById('replayControls')!;
|
||||
const replayNextButton = document.getElementById('replayNextButton')!;
|
||||
const replayPreviousButton = document.getElementById('replayPreviousButton')!;
|
||||
const replayFlipBox = document.getElementById('replayFlipBox') as HTMLInputElement;
|
||||
let replayAnimationAbortController: AbortController | null = null;
|
||||
|
||||
const shareReplayLinkButton = document.getElementById('shareReplayLinkButton') as HTMLButtonElement;
|
||||
@@ -185,6 +186,23 @@ replayPreviousButton.addEventListener('click', _ => {
|
||||
}
|
||||
});
|
||||
|
||||
replayFlipBox.addEventListener('input', _ => {
|
||||
if (currentGame == null || currentReplay == null) return;
|
||||
if (replayAnimationAbortController) {
|
||||
replayAnimationAbortController.abort();
|
||||
replayAnimationAbortController = null;
|
||||
clearPlayContainers();
|
||||
turnNumberLabel.setTurnNumber(currentGame.turnNumber);
|
||||
for (let i = 0; i < currentGame.players.length; i++) {
|
||||
updateStats(i);
|
||||
}
|
||||
}
|
||||
board.flip = replayFlipBox.checked;
|
||||
if (board.flip) gamePage.classList.add('boardFlipped');
|
||||
else gamePage.classList.remove('boardFlipped');
|
||||
board.resize();
|
||||
});
|
||||
|
||||
function loadPlayers(players: Player[]) {
|
||||
gamePage.dataset.players = players.length.toString();
|
||||
for (let i = 0; i < players.length; i++) {
|
||||
@@ -404,10 +422,10 @@ function updateHand(playerData: PlayerData) {
|
||||
} else {
|
||||
board.cardPlaying = card;
|
||||
if (isNaN(board.highlightX) || isNaN(board.highlightY)) {
|
||||
board.highlightX = board.startSpaces[board.playerIndex!].x - 3;
|
||||
board.highlightY = board.startSpaces[board.playerIndex!].y - 3;
|
||||
board.highlightX = board.startSpaces[board.playerIndex!].x - (board.flip ? 4 : 3);
|
||||
board.highlightY = board.startSpaces[board.playerIndex!].y - (board.flip ? 4 : 3);
|
||||
}
|
||||
board.cardRotation = 0;
|
||||
board.cardRotation = board.flip ? 2 : 0;
|
||||
board.refreshHighlight();
|
||||
board.table.focus();
|
||||
}
|
||||
|
||||
@@ -88,6 +88,9 @@ function onGameStateChange(game: any, playerData: PlayerData | null) {
|
||||
throw new Error('currentGame is null');
|
||||
clearPlayContainers();
|
||||
if (game.board) {
|
||||
board.flip = playerData != null && playerData.playerIndex % 2 != 0;
|
||||
if (board.flip) gamePage.classList.add('boardFlipped');
|
||||
else gamePage.classList.remove('boardFlipped');
|
||||
board.resize(game.board);
|
||||
board.startSpaces = game.startSpaces;
|
||||
board.refresh();
|
||||
|
||||
@@ -450,14 +450,21 @@ dialog::backdrop {
|
||||
grid-row: player-row-3;
|
||||
}
|
||||
|
||||
#gamePage.boardFlipped .playerBar[data-index="0"] { grid-row: player-row-1; }
|
||||
#gamePage.boardFlipped .playerBar[data-index="1"] { grid-row: player-row-0; }
|
||||
#gamePage.boardFlipped .playerBar[data-index="2"] { grid-row: player-row-3; }
|
||||
#gamePage.boardFlipped .playerBar[data-index="3"] { grid-row: player-row-2; }
|
||||
|
||||
.playerBar {
|
||||
grid-column: 1 / span 2;
|
||||
margin: 0 10px;
|
||||
border-left: 8px solid var(--colour);
|
||||
padding-left: 10px;
|
||||
}
|
||||
#gamePage:not([data-players="2"]) .playerBar:is([data-index="1"], [data-index="2"]) {
|
||||
#gamePage:not(.boardFlipped):not([data-players="2"]) .playerBar:is([data-index="1"], [data-index="2"]),
|
||||
#gamePage.boardFlipped:not([data-players="2"]) .playerBar:is([data-index="0"], [data-index="3"]) {
|
||||
text-align: right;
|
||||
border-left: none;
|
||||
border-right: 8px solid var(--colour);
|
||||
padding-right: 10px;
|
||||
}
|
||||
@@ -466,10 +473,17 @@ dialog::backdrop {
|
||||
grid-column: score-column;
|
||||
grid-row: 2 / -2;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 2em;
|
||||
}
|
||||
|
||||
#gamePage.boardFlipped .pointsContainer[data-index="2"] { order: 0; }
|
||||
#gamePage.boardFlipped .pointsContainer[data-index="0"] { order: 1; }
|
||||
#gamePage.boardFlipped .pointsContainer[data-index="3"] { order: 2; }
|
||||
#gamePage.boardFlipped .pointsContainer[data-index="1"] { order: 3; }
|
||||
|
||||
#playControls, #resultContainer, #replayControls {
|
||||
grid-column: 1 / span 2;
|
||||
grid-row: hand-row;
|
||||
@@ -557,11 +571,16 @@ dialog::backdrop {
|
||||
|
||||
.playContainer { text-align: center; }
|
||||
|
||||
.playContainer[data-index="0"] { grid-column: play-column-1; grid-row: 2 / -1; align-self: end; }
|
||||
.playContainer[data-index="1"] { grid-column: play-column-2; grid-row: 1 / 4; align-self: start; }
|
||||
.playContainer[data-index="2"] { grid-column: play-column-2; grid-row: 2 / -1; align-self: end; }
|
||||
.playContainer[data-index="1"] { grid-column: play-column-2; grid-row: 1 / 4; align-self: start; }
|
||||
.playContainer[data-index="0"] { grid-column: play-column-1; grid-row: 2 / -1; align-self: end; }
|
||||
.playContainer[data-index="3"] { grid-column: play-column-1; grid-row: 1 / 4; align-self: start; }
|
||||
|
||||
#gamePage.boardFlipped .playContainer[data-index="3"] { grid-column: play-column-2; grid-row: 2 / -1; align-self: end; }
|
||||
#gamePage.boardFlipped .playContainer[data-index="0"] { grid-column: play-column-2; grid-row: 1 / 4; align-self: start; }
|
||||
#gamePage.boardFlipped .playContainer[data-index="1"] { grid-column: play-column-1; grid-row: 2 / -1; align-self: end; }
|
||||
#gamePage.boardFlipped .playContainer[data-index="2"] { grid-column: play-column-1; grid-row: 1 / 4; align-self: start; }
|
||||
|
||||
.playContainer .card {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -734,7 +753,6 @@ dialog::backdrop {
|
||||
|
||||
.pointsContainer {
|
||||
color: var(--colour);
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
.pointsDelta {
|
||||
@@ -1040,6 +1058,11 @@ dialog::backdrop {
|
||||
.playerBar[data-index="2"] { grid-column: 1 / span 4; grid-row: 3; }
|
||||
.playerBar[data-index="3"] { grid-column: 1 / span 4; grid-row: 1; }
|
||||
|
||||
#gamePage.boardFlipped .playerBar[data-index="3"] { grid-column: 1 / span 4; grid-row: 3; }
|
||||
#gamePage.boardFlipped .playerBar[data-index="2"] { grid-column: 1 / span 4; grid-row: 1; }
|
||||
#gamePage.boardFlipped .playerBar[data-index="1"] { grid-column: 1 / span 4; grid-row: 3; }
|
||||
#gamePage.boardFlipped .playerBar[data-index="0"] { grid-column: 1 / span 4; grid-row: 1; }
|
||||
|
||||
#boardSection {
|
||||
grid-column: 2 / -1;
|
||||
grid-row: 2;
|
||||
@@ -1096,17 +1119,27 @@ dialog::backdrop {
|
||||
width: 30vw;
|
||||
}
|
||||
|
||||
.playContainer:is([data-index="0"], [data-index="1"], [data-index="2"], [data-index="3"]) {
|
||||
#gamePage:is(.boardFlipped, *) .playContainer:is([data-index="0"], [data-index="1"], [data-index="2"], [data-index="3"]) {
|
||||
font-size: x-small;
|
||||
grid-column: 1 / -1;
|
||||
left: auto;
|
||||
top: auto;
|
||||
z-index: -1;
|
||||
display: flex;
|
||||
}
|
||||
.playContainer[data-index="0"] { grid-row: 2 / span 2; justify-content: start; margin: 0 0 2em 1em; }
|
||||
.playContainer[data-index="1"] { grid-row: 1 / span 2; justify-content: end; margin: 2em 1em 0 0; }
|
||||
#gamePage[data-players="2"] .playContainer[data-index="0"],
|
||||
.playContainer[data-index="1"] { grid-row: 1 / span 2; justify-content: end; margin: 4em 1em 0 0; }
|
||||
.playContainer[data-index="2"] { grid-row: 2 / span 2; justify-content: end; margin: 0 1em 2em 0; }
|
||||
.playContainer[data-index="3"] { grid-row: 1 / span 2; justify-content: start; margin: 2em 0 0 1em; }
|
||||
.playContainer[data-index="3"] { grid-row: 1 / span 2; justify-content: start; margin: 4em 0 0 1em; }
|
||||
#gamePage[data-players="2"] .playContainer[data-index="0"] { justify-content: end; margin: 0 1em 0 0; }
|
||||
#gamePage[data-players="2"] .playContainer[data-index="1"] { justify-content: end; margin: 0 1em 0 0; }
|
||||
|
||||
#gamePage.boardFlipped .playContainer[data-index="1"] { grid-row: 2 / span 2; justify-content: start; margin: 0 0 2em 1em; }
|
||||
#gamePage.boardFlipped .playContainer[data-index="0"] { grid-row: 1 / span 2; justify-content: end; margin: 2em 1em 0 0; }
|
||||
#gamePage.boardFlipped .playContainer[data-index="3"] { grid-row: 2 / span 2; justify-content: end; margin: 0 1em 2em 0; }
|
||||
#gamePage.boardFlipped .playContainer[data-index="2"] { grid-row: 1 / span 2; justify-content: start; margin: 2em 0 0 1em; }
|
||||
#gamePage.boardFlipped[data-players="2"] .playContainer[data-index="0"] { justify-content: end; margin: 0 1em 0 0; }
|
||||
#gamePage.boardFlipped[data-players="2"] .playContainer[data-index="1"] { justify-content: end; margin: 0 1em 0 0; }
|
||||
|
||||
#gameButtonsContainer {
|
||||
grid-column: 1;
|
||||
|
||||
Reference in New Issue
Block a user