Implement the Show Deck button

This commit is contained in:
Andrio Celos
2022-10-28 14:42:55 +11:00
parent 71a68d39e2
commit 391b11a386
5 changed files with 188 additions and 71 deletions

View File

@@ -182,6 +182,15 @@
</div>
</div>
<div id="showDeckContainer" hidden>
<div id="showDeck">
<ul id="showDeckList"></ul>
<div>
<button type="button" id="showDeckCloseButton">Close</button>
</div>
</div>
</div>
<div id="turnNumberContainer" hidden>
<p>Turns left</p>
<div id="turnNumberLabel">12</div>

View File

@@ -22,6 +22,11 @@ const resultElement = document.getElementById('result')!;
const playerBars = Array.from(document.getElementsByClassName('playerBar'), el => new PlayerBar(el as HTMLDivElement));
playerBars.sort((a, b) => a.playerIndex - b.playerIndex);
const showDeckContainer = document.getElementById('showDeckContainer')!;
const showDeckListElement = document.getElementById('showDeckList')!;
const showDeckButtons: CardButton[] = [ ];
const showDeckCloseButton = document.getElementById('showDeckCloseButton') as HTMLButtonElement;
const playContainers = Array.from(document.getElementsByClassName('playContainer')) as HTMLDivElement[];
playContainers.sort((a, b) => parseInt(a.dataset.index || '0') - parseInt(b.dataset.index || '0'));
@@ -189,80 +194,106 @@ function showResult() {
}
}
function updateHand(cards: any[]) {
function clearShowDeck() {
showDeckContainer.hidden = true;
clearChildren(showDeckListElement);
showDeckButtons.splice(0);
}
function updateHand(playerData: PlayerData) {
for (const button of handButtons) {
handContainer.removeChild(button.element);
}
handButtons.splice(0);
if (!currentGame?.me) return;
currentGame.me.hand = cards.map(Card.fromJson);
if (cards) {
for (let i = 0; i < currentGame.me.hand.length; i++) {
const card = currentGame.me.hand[i];
const button = new CardButton('radio', card);
button.inputElement.name = 'handCard';
handButtons.push(button);
button.inputElement.addEventListener('input', e => {
if (button.checked) {
for (const button2 of handButtons) {
if (button2 != button)
button2.element.classList.remove('checked');
}
if (passButton.checked) {
if (canPlay) {
canPlay = false;
// Send the play to the server.
let req = new XMLHttpRequest();
req.open('POST', `${config.apiBaseUrl}/games/${currentGame!.id}/play`);
req.addEventListener('error', () => communicationError());
let data = new URLSearchParams();
data.append('clientToken', clientToken);
data.append('cardNumber', card.number.toString());
data.append('isPass', 'true');
req.send(data.toString());
if (showDeckButtons.length == 0) {
for (const card of playerData.deck!) {
const button = new CardButton('checkbox', card);
button.inputElement.hidden = true;
showDeckButtons.push(button);
board.autoHighlight = false;
}
} 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.cardRotation = 0;
board.refreshHighlight();
board.table.focus();
}
}
});
button.inputElement.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowUp':
if (i >= 2)
handButtons[i - 2].inputElement.focus();
e.preventDefault();
break;
case 'ArrowDown':
if (i < 2)
handButtons[i + 2].inputElement.focus();
e.preventDefault();
break;
case 'ArrowLeft':
if (i % 2 != 0)
handButtons[i - 1].inputElement.focus();
e.preventDefault();
break;
case 'ArrowRight':
if (i % 2 == 0)
handButtons[i + 1].inputElement.focus();
e.preventDefault();
break;
}
});
handContainer.appendChild(button.element);
const li = document.createElement('li');
li.appendChild(button.element);
showDeckListElement.appendChild(li);
}
}
for (const button of showDeckButtons) {
const li = button.element.parentElement!;
if (playerData.hand!.find(c => c.number == button.card.number))
li.className = 'inHand';
else if (playerData.cardsUsed.includes(button.card.number))
li.className = 'used';
else
li.className = 'unused';
}
if (!currentGame?.me) return;
currentGame.me.hand = playerData.hand!.map(Card.fromJson);
for (let i = 0; i < currentGame.me.hand.length; i++) {
const card = currentGame.me.hand[i];
const button = new CardButton('radio', card);
button.inputElement.name = 'handCard';
handButtons.push(button);
button.inputElement.addEventListener('input', e => {
if (button.checked) {
for (const button2 of handButtons) {
if (button2 != button)
button2.element.classList.remove('checked');
}
if (passButton.checked) {
if (canPlay) {
canPlay = false;
// Send the play to the server.
let req = new XMLHttpRequest();
req.open('POST', `${config.apiBaseUrl}/games/${currentGame!.id}/play`);
req.addEventListener('error', () => communicationError());
let data = new URLSearchParams();
data.append('clientToken', clientToken);
data.append('cardNumber', card.number.toString());
data.append('isPass', 'true');
req.send(data.toString());
board.autoHighlight = false;
}
} 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.cardRotation = 0;
board.refreshHighlight();
board.table.focus();
}
}
});
button.inputElement.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowUp':
if (i >= 2)
handButtons[i - 2].inputElement.focus();
e.preventDefault();
break;
case 'ArrowDown':
if (i < 2)
handButtons[i + 2].inputElement.focus();
e.preventDefault();
break;
case 'ArrowLeft':
if (i % 2 != 0)
handButtons[i - 1].inputElement.focus();
e.preventDefault();
break;
case 'ArrowRight':
if (i % 2 == 0)
handButtons[i + 1].inputElement.focus();
e.preventDefault();
break;
}
});
handContainer.appendChild(button.element);
}
}
(document.getElementById('redrawNoButton') as HTMLButtonElement).addEventListener('click', redrawButton_click);
@@ -385,6 +416,18 @@ function focusFirstEnabledHandCard() {
const firstEnabledButton = handButtons.find(b => b.enabled);
if (firstEnabledButton)
firstEnabledButton.inputElement.focus();
else
passButton.input.focus();
}
function toggleShowDeck() {
if (showDeckContainer.hidden) {
showDeckContainer.hidden = false;
showDeckCloseButton.focus();
} else {
showDeckContainer.hidden = true;
focusFirstEnabledHandCard();
}
}
rotateLeftButton.addEventListener('click', () => {
@@ -395,6 +438,8 @@ rotateRightButton.addEventListener('click', () => {
board.cardRotation++;
board.refreshHighlight();
});
gameDeckButton.addEventListener('click', toggleShowDeck);
showDeckCloseButton.addEventListener('click', () => showDeckContainer.hidden = true);
document.addEventListener('keydown', e => {
if (!pages.get('game')!.hidden) {
@@ -415,6 +460,10 @@ document.addEventListener('keydown', e => {
}
e.preventDefault();
break;
case 'd':
if (!gameButtonsContainer.hidden) toggleShowDeck();
e.preventDefault();
break;
}
}
});

View File

@@ -129,6 +129,8 @@ function getGameInfo(gameID: string, myPlayerIndex: number | null) {
board.playerIndex = myPlayerIndex;
initLobbyPage(window.location.toString());
showDeckButtons.splice(0);
clearShowDeck();
myPlayerIndex = setupWebSocket(gameID, myPlayerIndex);
}

View File

@@ -104,7 +104,7 @@ function onGameStateChange(game: any, playerData: any) {
case GameState.Ongoing:
case GameState.Ended:
if (playerData)
updateHand(playerData.hand);
updateHand(playerData);
board.autoHighlight = false;
redrawModal.hidden = true;
showPage('game');
@@ -294,11 +294,13 @@ function setupWebSocket(gameID: string, myPlayerIndex: number | null) {
(async () => {
await playInkAnimations(payload.data, anySpecialAttacks);
updateHand(payload.playerData.hand);
updateHand(payload.playerData);
turnNumberLabel.setTurnNumber(payload.data.game.turnNumber);
clearPlayContainers();
if (payload.event == 'gameEnd') {
gameButtonsContainer.hidden = true;
passButton.enabled = false;
specialButton.enabled = false;
gamePage.classList.add('gameEnded');
showResult();
} else {

View File

@@ -471,6 +471,56 @@ dialog::backdrop {
#playControls > label:is(:active, .checked) { background: var(--special-accent-colour-1); }
#playControls > label.disabled { background: grey; }
#showDeckContainer {
grid-column: 1 / span 3;
grid-row: 2 / -2;
background: black;
z-index: 2;
}
#showDeck {
display: flex;
flex-flow: column;
height: 100%;
text-align: center;
}
#showDeckList {
display: grid;
grid-template-columns: auto auto auto;
list-style-type: none;
font-size: smaller;
overflow-y: auto;
padding: 0;
margin: 0;
justify-items: center;
}
#showDeckList > li {
margin: 0.25em;
border-radius: 0.5em;
text-align: center;
}
#showDeckList > li.inHand {
outline: 0.25em solid;
}
#showDeckList > li.used {
opacity: 0.35;
}
#showDeckCloseButton {
border: none;
font-family: inherit;
color: inherit;
width: 40%;
grid-row: button-row;
margin: 1em;
padding: 0 0.5em;
text-align: center;
background: var(--primary-colour-1);
text-shadow: 0 0 4px black;
border-radius: 0.5em;
}
#showDeckCloseButton:hover { background: var(--special-colour-1); }
#showDeckCloseButton:focus-within { outline: 2px solid var(--special-accent-colour-2); }
#showDeckCloseButton:active { background: var(--special-accent-colour-1); }
.playContainer { text-align: center; }
.playContainer[data-index="0"] { grid-column: play-column-1; grid-row: 2 / -1; align-self: end; }
@@ -510,9 +560,6 @@ dialog::backdrop {
opacity: 1;
color: var(--primary-colour-1);
}
#gameDeckButton {
display: none;
}
#boardSection {
grid-column: board-column;
@@ -1007,6 +1054,14 @@ dialog::backdrop {
overflow: scroll visible;
}
#showDeckContainer {
grid-column: 1 / -1;
grid-row: 2 / -1;
}
#showDeckList .card {
width: 30vw;
}
.playContainer:is([data-index="0"], [data-index="1"], [data-index="2"], [data-index="3"]) {
font-size: x-small;
grid-column: 1 / -1;