692 lines
28 KiB
JavaScript
692 lines
28 KiB
JavaScript
|
|
|
|
import API from "../../api.js";
|
|
import TableBasePage from "../base_table.js";
|
|
import DOM from "../../dom.js";
|
|
import Events from "../../lib/events.js";
|
|
|
|
export default class PageMtgGame extends TableBasePage {
|
|
static hash = hashPageMtgGame;
|
|
static attrIdRowObject = attrGameId;
|
|
callSaveTableContent = API.saveGame;
|
|
|
|
constructor(router) {
|
|
super(router);
|
|
}
|
|
|
|
initialize() {
|
|
this.sharedInitialize();
|
|
this.hookupTcgGame();
|
|
}
|
|
hookupFilters() {
|
|
// this.sharedHookupFilters();
|
|
}
|
|
loadRowTable(rowJson) {
|
|
return;
|
|
}
|
|
getJsonRow(row) {
|
|
return;
|
|
}
|
|
initialiseRowNew(tbody, row) {
|
|
|
|
}
|
|
postInitialiseRowNewCallback(tbody) {
|
|
|
|
}
|
|
|
|
hookupTableMain() {
|
|
super.hookupTableMain();
|
|
}
|
|
hookupTcgGame() {
|
|
this.initGamePage();
|
|
let pageHeading = document.querySelector('.container.company-name .tcg-title.company-name');
|
|
pageHeading.innerText = `MTG Game #${gameId}`;
|
|
}
|
|
|
|
initGamePage() {
|
|
// Load existing game state from API or show setup
|
|
PageMtgGame.updatePlayerSetup();
|
|
if (typeof gameId !== 'undefined' && gameId) {
|
|
this.loadGameFromServer();
|
|
}
|
|
/*
|
|
else {
|
|
PageMtgGame.updatePlayerSetup();
|
|
}
|
|
*/
|
|
|
|
PageMtgGame.hookupResetButton();
|
|
PageMtgGame.hookupPlayerCountInput();
|
|
this.hookupStartGameButton();
|
|
/*
|
|
this.hookupCommanderDeathIncrementButtons();
|
|
this.hookupEliminateCommanderButtons();
|
|
this.hookupPlayerLifeIncrementButtons();
|
|
this.hookupCommanderDamageIncrementButtons();
|
|
*/
|
|
}
|
|
static hookupResetButton() {
|
|
const resetGameButton = document.querySelector('header.game-header .header-right .btn-tcg.btn-tcg-secondary');
|
|
if (resetGameButton) {
|
|
resetGameButton.addEventListener('click', PageMtgGame.resetGame);
|
|
}
|
|
}
|
|
static hookupPlayerCountInput() {
|
|
const playerCountInput = document.getElementById('playerCount');
|
|
if (playerCountInput) {
|
|
playerCountInput.addEventListener('change', PageMtgGame.updatePlayerSetup);
|
|
}
|
|
}
|
|
hookupStartGameButton() {
|
|
const startGameButton = document.querySelector('.setup-section .setup-actions .btn-tcg');
|
|
if (startGameButton) {
|
|
startGameButton.addEventListener('click', () => { this.startGame(); });
|
|
}
|
|
}
|
|
/*
|
|
hookupCommanderDeathIncrementButtons() {
|
|
const commanderDeathIncremementButtons = document.querySelectorAll('#players-grid .player-card .commander-deaths .death-btn');
|
|
if (commanderDeathIncremementButtons) {
|
|
commanderDeathIncremementButtons.forEach((button) => {
|
|
button.addEventListener('click', PageMtgGame.changeCommanderDeaths);
|
|
});
|
|
}
|
|
}
|
|
hookupEliminateCommanderButtons() {
|
|
const eliminateCommanderButtons = document.querySelector('#players-grid .player-card .eliminate-btn');
|
|
if (eliminateCommanderButtons) {
|
|
eliminateCommanderButtons.forEach((button) => {
|
|
button.addEventListener('click', PageMtgGame.toggleEliminate);
|
|
});
|
|
}
|
|
}
|
|
hookupPlayerLifeIncrementButtons() {
|
|
const playerLifeIncrementButtons = document.querySelector('#players-grid .player-card .eliminate-btn');
|
|
if (playerLifeIncrementButtons) {
|
|
playerLifeIncrementButtons.forEach((button) => {
|
|
button.addEventListener('click', PageMtgGame.changeLife);
|
|
});
|
|
}
|
|
}
|
|
hookupCommanderDamageIncrementButtons() {
|
|
const commanderDamageIncrementButtons = document.querySelector('#players-grid .player-card .eliminate-btn');
|
|
if (commanderDamageIncrementButtons) {
|
|
commanderDamageIncrementButtons.forEach((button) => {
|
|
button.addEventListener('click', PageMtgGame.changeCommanderDamage);
|
|
});
|
|
}
|
|
}
|
|
*/
|
|
|
|
async loadGameFromServer() {
|
|
console.log("loading game from server");
|
|
try {
|
|
// Fetch players, rounds, and damage records from API
|
|
const [playersResponse, roundsResponse, damageResponse] = await Promise.all([
|
|
API.getGamePlayers(gameId)
|
|
, API.getGameRounds(gameId)
|
|
, API.getGameDamageRecords(gameId)
|
|
]);
|
|
console.log({ playersResponse, damageResponse });
|
|
|
|
let setupSection = document.getElementById('setupSection');
|
|
let gameSection = document.getElementById('gameSection');
|
|
setupSection.classList.remove('hidden');
|
|
gameSection.classList.add('hidden');
|
|
|
|
if (playersResponse.status !== 'success') {
|
|
console.error('Failed to load players:', playersResponse.message);
|
|
return;
|
|
}
|
|
|
|
const savedPlayers = playersResponse.data || [];
|
|
const savedRounds = roundsResponse.status === 'success' ? (roundsResponse.data || []) : [];
|
|
const savedDamageRecords = damageResponse.status === 'success' ? (damageResponse.data || []) : [];
|
|
|
|
players = savedPlayers;
|
|
rounds = savedRounds;
|
|
damageRecords = savedDamageRecords;
|
|
|
|
if (savedPlayers.length === 0) {
|
|
// No players yet, show setup section
|
|
return;
|
|
}
|
|
|
|
// Hide setup, show game
|
|
setupSection.classList.add('hidden');
|
|
gameSection.classList.remove('hidden');
|
|
|
|
console.log({ savedPlayers, damageRecords });
|
|
|
|
// Render players to DOM
|
|
this.renderPlayers();
|
|
|
|
} catch (error) {
|
|
console.error('Error loading game from server:', error);
|
|
}
|
|
}
|
|
|
|
renderPlayers() {
|
|
const grid = document.getElementById('playersGrid');
|
|
grid.innerHTML = '';
|
|
|
|
// Build a damage lookup: { playerId: { fromPlayerId: damageAmount } }
|
|
/*
|
|
const damageLookup = {};
|
|
damageRecords.forEach(damage => {
|
|
if (!damageLookup[damage.player_id]) {
|
|
damageLookup[damage.player_id] = {};
|
|
}
|
|
if (damage.received_from_commander_player_id) {
|
|
damageLookup[damage.player_id][damage.received_from_commander_player_id] = damage.health_change || 0;
|
|
}
|
|
});
|
|
*/
|
|
const latestRoundId = PageMtgGame.getLatestRoundId();
|
|
|
|
players.forEach((player, index) => {
|
|
// Build display name: prefer user_name + deck_name, fallback to player name
|
|
const playerId = player[attrPlayerId];
|
|
let displayName = PageMtgGame.makePlayerDisplayName(playerId, index);
|
|
let damagePlayerPairs = [...players, { [attrPlayerId]: null }];
|
|
let maxCommanderDamageReceived = 0;
|
|
damagePlayerPairs.forEach(damagePlayerPair => {
|
|
const sourceId = damagePlayerPair[attrPlayerId];
|
|
const filteredPlayerDamages = damageRecords.filter(damage => (
|
|
damage[attrRoundId] == latestRoundId
|
|
&& damage[attrPlayerId] == playerId
|
|
&& damage[attrReceivedFromCommanderPlayerId] == sourceId
|
|
)); //[playerId] || {};
|
|
if (filteredPlayerDamages.length == 0) {
|
|
damageRecords.push(PageMtgGame.makeDefaultGameRoundPlayerDamage(playerId, sourceId));
|
|
}
|
|
maxCommanderDamageReceived = Math.max(
|
|
maxCommanderDamageReceived
|
|
, damageRecords.filter(damage => (
|
|
damage[attrPlayerId] == playerId
|
|
&& damage[attrReceivedFromCommanderPlayerId] == sourceId
|
|
))
|
|
.map(damage => damage[flagHealthChange])
|
|
.reduce((acc, curr) => acc + curr, 0)
|
|
);
|
|
});
|
|
|
|
const totalDamage = damageRecords.filter(damage => ( damage[attrPlayerId] == playerId ))
|
|
.map(damage => damage[flagHealthChange])
|
|
.reduce((acc, curr) => acc + curr, 0);
|
|
let life = startingLife + totalDamage;
|
|
|
|
let isEliminatedByForce = damageRecords.filter(damage => ( damage[attrPlayerId] == playerId ))
|
|
.map(damage => damage[flagIsEliminated])
|
|
.some(Boolean);
|
|
const isEliminated = (
|
|
isEliminatedByForce
|
|
|| !player[flagActive]
|
|
|| life < 1
|
|
|| maxCommanderDamageReceived >= 21
|
|
);
|
|
|
|
const playerOwnDamage = damageRecords.filter(damage => (
|
|
damage[attrPlayerId] == playerId
|
|
&& damage[attrReceivedFromCommanderPlayerId] == null
|
|
&& damage[attrRoundId] == latestRoundId
|
|
))[0];
|
|
const card = document.createElement('div');
|
|
card.className = `player-card ${isEliminated ? 'eliminated' : ''}`;
|
|
card.style.animationDelay = `${index * 0.1}s`;
|
|
card.dataset.playerId = playerId;
|
|
card.dataset.userName = player.user_name || '';
|
|
card.dataset.deckName = player.deck_name || '';
|
|
|
|
card.innerHTML = `
|
|
<div class="player-header">
|
|
<div class="player-info">
|
|
<div class="player-name">${displayName}</div>
|
|
<div class="commander-deaths">
|
|
<span>Commander Deaths:</span>
|
|
<div class="death-counter">
|
|
<button class="death-btn death-minus" data-player-id="${playerId}">−</button>
|
|
<span class="death-display" data-player-id="${playerId}" ${attrValuePrevious}="${playerOwnDamage[flagCommanderDeaths]}">${playerOwnDamage[flagCommanderDeaths]}</span>
|
|
<button class="death-btn death-plus" data-player-id="${playerId}">+</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button class="eliminate-btn" data-player-id="${playerId}" ${attrValuePrevious}="${isEliminated}">
|
|
${isEliminated ? 'Revive' : 'Eliminate'}
|
|
</button>
|
|
</div>
|
|
|
|
<div class="life-total">
|
|
<input type="hidden" class="life-value" data-player-id="${playerId}" value="${life}">
|
|
<div class="life-display" data-player-id="${playerId}" ${attrValuePrevious}="${life}">${life}</div>
|
|
<div class="life-controls">
|
|
<button class="life-btn" data-player-id="${playerId}" data-amount="-5">-5</button>
|
|
<button class="life-btn" data-player-id="${playerId}" data-amount="-1">-1</button>
|
|
<button class="life-btn" data-player-id="${playerId}" data-amount="1">+1</button>
|
|
<button class="life-btn" data-player-id="${playerId}" data-amount="5">+5</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="commander-damage-section">
|
|
<div class="section-title">Commander Damage Taken</div>
|
|
<div class="damage-grid" data-player-id="${playerId}">
|
|
${PageMtgGame.renderCommanderDamageRows(
|
|
playerId // playerId
|
|
, player[attrDeckId] // deckId
|
|
)}
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
grid.appendChild(card);
|
|
});
|
|
|
|
// Hookup all event handlers
|
|
this.hookupPlayerCardEvents();
|
|
}
|
|
static makeDefaultGameRoundPlayerDamage(playerId, receivedFromCommanderPlayerId) {
|
|
let roundId = PageMtgGame.getLatestRoundId();
|
|
return {
|
|
[attrDamageId]: -1 - damageRecords.length
|
|
, [attrRoundId]: roundId
|
|
, [attrPlayerId]: playerId
|
|
, [attrReceivedFromCommanderPlayerId]: receivedFromCommanderPlayerId
|
|
, [flagHealthChange]: 0
|
|
, [flagCommanderDeaths]: 0
|
|
, [flagActive]: true
|
|
};
|
|
}
|
|
static getLatestRoundId() {
|
|
let roundId = -1;
|
|
if (rounds.length > 0) {
|
|
let highestRoundDisplayOrder = Math.max(rounds.map(round => { return round[flagDisplayOrder]; }));
|
|
roundId = rounds.filter(round => round[flagDisplayOrder] == highestRoundDisplayOrder)[0][attrRoundId];
|
|
console.log({ "method": "getLatestRoundId", highestRoundDisplayOrder, roundId });
|
|
}
|
|
return roundId;
|
|
}
|
|
static makePlayerDisplayName(playerId, index) {
|
|
if (playerId == null) {
|
|
return `Player ${index + 1}`;
|
|
}
|
|
const player = players.filter(player => player[attrPlayerId] == playerId)[0];
|
|
const deckId = player[attrDeckId];
|
|
const deck = (deckId == null) ? null : decks.filter(deck => deck[attrDeckId] == deckId)[0];
|
|
const user = (playerId == null) ? null : users[player[attrUserId]];
|
|
return player[flagName] || `${(user == null) ? 'Error' : user[flagName]} - ${(deck == null) ? 'Error' : deck[flagName]}`;
|
|
}
|
|
static renderCommanderDamageRows(playerId) {
|
|
// const roundId = PageMtgGame.getLatestRoundId();
|
|
return players
|
|
.filter(otherPlayer => otherPlayer[attrPlayerId] !== playerId)
|
|
.map(otherPlayer => {
|
|
const sourceId = otherPlayer[attrPlayerId];
|
|
let otherPlayerDisplayName = PageMtgGame.makePlayerDisplayName(sourceId);
|
|
const totalDamage = damageRecords.filter(damage => (
|
|
damage[attrPlayerId] == playerId
|
|
&& damage[attrReceivedFromCommanderPlayerId] == sourceId
|
|
))
|
|
.map(damage => -damage[flagHealthChange])
|
|
.reduce((acc, curr) => acc + curr, 0);
|
|
const isLethal = totalDamage >= 21;
|
|
|
|
return `
|
|
<div class="damage-row" data-player-id="${playerId}" data-source-id="${sourceId}">
|
|
<span class="damage-source">from ${otherPlayerDisplayName}</span>
|
|
<div class="damage-controls">
|
|
<button class="damage-btn damage-minus" data-player-id="${playerId}" data-source-id="${sourceId}">−</button>
|
|
<input type="hidden" class="damage-value" data-player-id="${playerId}" data-source-id="${sourceId}" value="${totalDamage}">
|
|
<span class="damage-display ${isLethal ? 'lethal' : ''}" data-player-id="${playerId}" data-source-id="${sourceId}" ${attrValuePrevious}="${totalDamage}">${totalDamage}</span>
|
|
<button class="damage-btn damage-plus" data-player-id="${playerId}" data-source-id="${sourceId}">+</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
})
|
|
.join('');
|
|
}
|
|
|
|
hookupPlayerCardEvents() {
|
|
// Life buttons
|
|
let lifeButtonSelector = '.life-btn';
|
|
Events.hookupEventHandler("click", lifeButtonSelector, (event, button) => {
|
|
const playerId = button.dataset.playerId;
|
|
const amount = parseInt(button.dataset.amount);
|
|
const latestRoundId = PageMtgGame.getLatestRoundId();
|
|
const damageIndex = damageRecords.findIndex(damage => (
|
|
damage[attrRoundId] == latestRoundId
|
|
&& damage[attrPlayerId] == playerId
|
|
&& damage[attrReceivedFromCommanderPlayerId] == null
|
|
));
|
|
this.changeLife(
|
|
playerId // playerId
|
|
, amount // amount
|
|
, true // updateDamage
|
|
, damageIndex // damageIndex
|
|
);
|
|
});
|
|
|
|
// Commander death buttons
|
|
let commanderDeathButtonSelector = '.death-btn';
|
|
Events.hookupEventHandler("click", commanderDeathButtonSelector, (event, button) => {
|
|
const playerId = button.dataset.playerId;
|
|
const isMinusButton = button.classList.contains('death-minus');
|
|
const amount = (isMinusButton) ? -1 : 1;
|
|
this.changeCommanderDeaths(playerId, amount);
|
|
});
|
|
|
|
// Commander damage buttons
|
|
let commmanderDamageButtonSelector = '.damage-btn';
|
|
Events.hookupEventHandler("click", commmanderDamageButtonSelector, (event, button) => {
|
|
const playerId = button.dataset.playerId;
|
|
const sourceId = button.dataset.sourceId;
|
|
const isMinusButton = button.classList.contains('damage-minus');
|
|
const amount = (isMinusButton) ? -1 : 1;
|
|
this.changeCommanderDamage(playerId, sourceId, amount);
|
|
});
|
|
|
|
// Eliminate buttons
|
|
let eliminatePlayerButtonSelector = '.eliminate-btn';
|
|
Events.hookupEventHandler("click", eliminatePlayerButtonSelector, (event, button) => {
|
|
const playerId = button.dataset.playerId;
|
|
this.toggleEliminate(playerId);
|
|
});
|
|
}
|
|
|
|
changeLife(playerId, amount, updateDamage = false, damageIndex = null) {
|
|
const card = document.querySelector(`.player-card[data-player-id="${playerId}"]`);
|
|
if (!card || card.classList.contains('eliminated')) return;
|
|
|
|
const lifeInput = card.querySelector(`.life-value[data-player-id="${playerId}"]`);
|
|
const lifeDisplay = card.querySelector(`.life-display[data-player-id="${playerId}"]`);
|
|
|
|
const currentLife = parseInt(lifeInput.value) || 0;
|
|
const newLife = Math.max(0, currentLife + amount);
|
|
DOM.setElementAttributeValueCurrent(lifeDisplay, newLife);
|
|
DOM.isElementDirty(lifeDisplay);
|
|
lifeInput.value = newLife;
|
|
lifeDisplay.textContent = newLife;
|
|
|
|
if (updateDamage) {
|
|
damageRecords[damageIndex][flagHealthChange] += amount;
|
|
}
|
|
|
|
// PageMtgGame.debouncedSave();
|
|
this.updateAndToggleShowButtonsSaveCancel();
|
|
}
|
|
|
|
changeCommanderDamage(playerId, sourceId, amount) {
|
|
const card = document.querySelector(`.player-card[data-player-id="${playerId}"]`);
|
|
if (!card || card.classList.contains('eliminated')) return;
|
|
|
|
const damageInput = card.querySelector(`.damage-value[data-player-id="${playerId}"][data-source-id="${sourceId}"]`);
|
|
const damageDisplay = card.querySelector(`.damage-display[data-player-id="${playerId}"][data-source-id="${sourceId}"]`);
|
|
|
|
const currentDamage = parseInt(damageInput.value) || 0;
|
|
const newDamage = Math.max(0, currentDamage + amount);
|
|
amount = newDamage - currentDamage;
|
|
DOM.setElementAttributeValueCurrent(damageDisplay, newDamage);
|
|
DOM.isElementDirty(damageDisplay);
|
|
damageInput.value = newDamage;
|
|
damageDisplay.textContent = newDamage;
|
|
|
|
// Update lethal class
|
|
if (newDamage >= 21) {
|
|
damageDisplay.classList.add('lethal');
|
|
} else {
|
|
damageDisplay.classList.remove('lethal');
|
|
}
|
|
|
|
const latestRoundId = PageMtgGame.getLatestRoundId();
|
|
const damageIndex = damageRecords.findIndex(damageRecord => (
|
|
damageRecord[attrRoundId] == latestRoundId
|
|
&& damageRecord[attrPlayerId] == playerId
|
|
&& damageRecord[attrReceivedFromCommanderPlayerId] == sourceId
|
|
));
|
|
damageRecords[damageIndex][flagHealthChange] -= amount;
|
|
|
|
this.changeLife(
|
|
playerId // playerId
|
|
, -amount // amount
|
|
, false // updateDamage
|
|
, damageIndex // damageIndex
|
|
);
|
|
// PageMtgGame.debouncedSave();
|
|
}
|
|
|
|
changeCommanderDeaths(playerId, amount) {
|
|
const card = document.querySelector(`.player-card[data-player-id="${playerId}"]`);
|
|
if (!card || card.classList.contains('eliminated')) return;
|
|
|
|
const deathDisplay = card.querySelector(`.death-display[data-player-id="${playerId}"]`);
|
|
const currentDeaths = parseInt(deathDisplay.textContent) || 0;
|
|
const newDeaths = Math.max(0, currentDeaths + amount);
|
|
|
|
deathDisplay.textContent = newDeaths;
|
|
DOM.setElementAttributeValueCurrent(deathDisplay, newDeaths);
|
|
DOM.isElementDirty(deathDisplay);
|
|
|
|
const latestRoundId = PageMtgGame.getLatestRoundId();
|
|
const damageIndex = damageRecords.findIndex(damage => (
|
|
damage[attrRoundId] == latestRoundId
|
|
&& damage[attrPlayerId] == playerId
|
|
&& damage[attrReceivedFromCommanderPlayerId] == null
|
|
));
|
|
damageRecords[damageIndex][flagCommanderDeaths] = newDeaths;
|
|
|
|
// PageMtgGame.debouncedSave();
|
|
this.updateAndToggleShowButtonsSaveCancel();
|
|
}
|
|
|
|
toggleEliminate(playerId) {
|
|
const card = document.querySelector(`.player-card[data-player-id="${playerId}"]`);
|
|
if (!card) return;
|
|
|
|
const eliminateBtn = card.querySelector(`.eliminate-btn[data-player-id="${playerId}"]`);
|
|
const wasEliminated = card.classList.contains('eliminated');
|
|
|
|
if (wasEliminated) {
|
|
card.classList.remove('eliminated');
|
|
eliminateBtn.textContent = 'Eliminate';
|
|
} else {
|
|
card.classList.add('eliminated');
|
|
eliminateBtn.textContent = 'Revive';
|
|
}
|
|
const isEliminated = card.classList.contains('eliminated');
|
|
|
|
const latestRoundId = PageMtgGame.getLatestRoundId();
|
|
const damageIndex = damageRecords.findIndex(damage => (
|
|
damage[attrRoundId] == latestRoundId
|
|
&& damage[attrPlayerId] == playerId
|
|
&& damage[attrReceivedFromCommanderPlayerId] == null
|
|
));
|
|
damageRecords[damageIndex][flagIsEliminated] = isEliminated;
|
|
|
|
DOM.setElementAttributeValueCurrent(eliminateBtn, isEliminated);
|
|
DOM.isElementDirty(eliminateBtn);
|
|
// PageMtgGame.debouncedSave();
|
|
this.updateAndToggleShowButtonsSaveCancel();
|
|
}
|
|
|
|
static updatePlayerSetup() {
|
|
const playerCountInput = document.getElementById('playerCount');
|
|
if (!playerCountInput) return;
|
|
|
|
const playerCount = parseInt(playerCountInput.value);
|
|
const grid = document.getElementById('playerSetupGrid');
|
|
if (!grid) return;
|
|
|
|
grid.innerHTML = '';
|
|
const wrapperTemplate = document.getElementById(playerSetupWrapperTemplateId);
|
|
let player, wrapper, wrapperHeading, userDdl, deckDdl, nameInput;
|
|
for (let i = 0; i < playerCount; i++) {
|
|
if (i < players.length) {
|
|
player = players[i];
|
|
}
|
|
else {
|
|
player = PageMtgGame.makeDefaultGamePlayer();
|
|
players.push(player);
|
|
}
|
|
wrapper = wrapperTemplate.cloneNode(true);
|
|
wrapper.removeAttribute("id");
|
|
wrapper.setAttribute(flagDisplayOrder, i + 1);
|
|
wrapper.classList.remove(flagIsCollapsed);
|
|
wrapperHeading = wrapper.querySelector('label');
|
|
wrapperHeading.innerText = 'Player ' + (i + 1);
|
|
userDdl = wrapper.querySelector('.playerUser select');
|
|
DOM.setElementValuesCurrentAndPrevious(userDdl, player[attrUserId]);
|
|
deckDdl = wrapper.querySelector('.playerDeck select');
|
|
DOM.setElementValuesCurrentAndPrevious(deckDdl, player[attrDeckId]);
|
|
nameInput = wrapper.querySelector('.playerName input');
|
|
DOM.setElementValuesCurrentAndPrevious(nameInput, player[flagName]);
|
|
console.log('player: ', player);
|
|
grid.appendChild(wrapper);
|
|
}
|
|
}
|
|
static makeDefaultGamePlayer() {
|
|
return {
|
|
[attrPlayerId]: -players.length
|
|
, [attrGameId]: gameId
|
|
, [attrUserId]: user[attrUserId]
|
|
, [attrDeckId]: 0
|
|
, [flagName]: ""
|
|
, [flagNotes]: null
|
|
, [flagDisplayOrder]: players.length
|
|
, [flagActive]: true
|
|
};
|
|
}
|
|
|
|
async startGame() {
|
|
const playerCountInput = document.getElementById('playerCount');
|
|
if (!playerCountInput) return;
|
|
|
|
const playerCount = parseInt(playerCountInput.value);
|
|
const playersToSave = [];
|
|
|
|
let playerSetupWrapper, playerId, player, userDdl, userId, deckDdl, deckId, nameInput, name;
|
|
for (let i = 0; i < playerCount; i++) {
|
|
playerSetupWrapper = document.querySelector('.player-name-input-wrapper[' + flagDisplayOrder + '="' + (i + 1) + '"]');
|
|
userDdl = playerSetupWrapper.querySelector('.playerUser select');
|
|
deckDdl = playerSetupWrapper.querySelector('.playerDeck select');
|
|
nameInput = playerSetupWrapper.querySelector('.playerName input');
|
|
|
|
userId = DOM.getElementValueCurrent(userDdl);
|
|
deckId = DOM.getElementValueCurrent(deckDdl);
|
|
name = nameInput ? nameInput.value.trim() || `Player ${i + 1}` : `Player ${i + 1}`;
|
|
|
|
playerId = playerSetupWrapper.getAttribute(attrPlayerId);
|
|
player = players.filter(p => p[attrPlayerId] == playerId)[0];
|
|
playersToSave.push({
|
|
...player
|
|
, [attrGameId]: gameId
|
|
, [attrUserId]: userId
|
|
, [attrDeckId]: deckId
|
|
, [flagName]: name
|
|
, [flagDisplayOrder]: i + 1
|
|
, [flagActive]: true
|
|
});
|
|
}
|
|
|
|
// Save players to server
|
|
const comment = 'Save players';
|
|
const self = this;
|
|
API.saveGamePlayers(playersToSave, null, comment)
|
|
.then(data => {
|
|
if (data[flagStatus] == flagSuccess) {
|
|
self.leave();
|
|
window.location.reload();
|
|
}
|
|
else {
|
|
console.error('Failed to save players:', data[flagMessage]);
|
|
PageMtgGame.showError('An error occurred while creating the game');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error creating game:', error);
|
|
PageMtgGame.showError('An error occurred while creating the game');
|
|
})
|
|
.finally(() => {
|
|
});
|
|
}
|
|
|
|
static resetGame() {
|
|
if (confirm('Are you sure you want to start a new game? Current game will be lost.')) {
|
|
localStorage.removeItem(`mtgGame_${gameId}`);
|
|
window.location.href = hashPageGames;
|
|
}
|
|
}
|
|
|
|
async saveGame() {
|
|
/*
|
|
const gameState = {
|
|
[flagPlayer]: players
|
|
, [flagRound]: rounds
|
|
, [flagDamage]: damageRecords
|
|
};
|
|
if (gameState[flagPlayer].length > 0) {
|
|
localStorage.setItem(`mtgGame_${gameId}`, JSON.stringify(gameState));
|
|
PageMtgGame.showSaveIndicator();
|
|
}
|
|
*/
|
|
const comment = 'Save player damage';
|
|
const self = this;
|
|
API.saveGameRoundPlayerDamages(rounds, damageRecords, null, comment)
|
|
.then(data => {
|
|
if (data[flagStatus] == flagSuccess) {
|
|
self.leave();
|
|
window.location.reload();
|
|
}
|
|
else {
|
|
console.error('Failed to save players:', data[flagMessage]);
|
|
PageMtgGame.showError('An error occurred while creating the game');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error creating game:', error);
|
|
PageMtgGame.showError('An error occurred while creating the game');
|
|
})
|
|
.finally(() => {
|
|
});
|
|
}
|
|
/*
|
|
static debouncedSave() {
|
|
clearTimeout(PageMtgGame._saveTimeout);
|
|
PageMtgGame._saveTimeout = setTimeout(() => PageMtgGame.saveGame(), 500);
|
|
}
|
|
|
|
static showSaveIndicator() {
|
|
const indicator = document.getElementById('saveIndicator');
|
|
if (indicator) {
|
|
indicator.classList.add('show');
|
|
setTimeout(() => {
|
|
indicator.classList.remove('show');
|
|
}, 2000);
|
|
}
|
|
}
|
|
*/
|
|
saveRecordsTableDirty() {
|
|
this.saveGame();
|
|
}
|
|
static showError(message) {
|
|
// Check if there's an overlay error element
|
|
const errorOverlay = document.getElementById('overlayError');
|
|
if (errorOverlay) {
|
|
const errorLabel = errorOverlay.querySelector('.error-message, #labelError');
|
|
if (errorLabel) {
|
|
errorLabel.textContent = message;
|
|
}
|
|
errorOverlay.classList.remove('hidden');
|
|
errorOverlay.style.display = 'flex';
|
|
} else {
|
|
// Fallback to alert
|
|
alert(message);
|
|
}
|
|
}
|
|
|
|
leave() {
|
|
super.leave();
|
|
}
|
|
}
|
|
|
|
// Static timeout reference for debouncing
|
|
PageMtgGame._saveTimeout = null;
|