Ajuste le mode Time et met en valeur les chronos
This commit is contained in:
148
app.js
148
app.js
@@ -13,17 +13,17 @@ const PRESETS = {
|
||||
fast: {
|
||||
label: "FAST",
|
||||
quota: 6,
|
||||
description: "6 coups par joueur et par partie.",
|
||||
description: "6 coups par joueur.",
|
||||
},
|
||||
freeze: {
|
||||
label: "FREEZE",
|
||||
quota: 8,
|
||||
description: "8 coups par joueur et par partie.",
|
||||
description: "8 coups par joueur.",
|
||||
},
|
||||
masters: {
|
||||
label: "MASTERS",
|
||||
quota: 10,
|
||||
description: "10 coups par joueur et par partie.",
|
||||
description: "10 coups par joueur.",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -114,6 +114,8 @@ function initSetupPage() {
|
||||
const summary = document.querySelector("#setupSummary");
|
||||
const loadDemoButton = document.querySelector("#loadDemoButton");
|
||||
const resumeCard = document.querySelector("#resumeCard");
|
||||
const moveSecondsField = document.querySelector("#moveSecondsField");
|
||||
const moveSecondsInput = form?.querySelector('[name="moveSeconds"]');
|
||||
|
||||
if (!form || !summary || !loadDemoButton || !resumeCard) {
|
||||
return;
|
||||
@@ -125,17 +127,34 @@ function initSetupPage() {
|
||||
const quota = PRESETS[preset].quota;
|
||||
const blockDurationMs = getDurationInputMs(form, "blockSeconds", DEFAULT_BLOCK_DURATION_MS);
|
||||
const moveLimitMs = getDurationInputMs(form, "moveSeconds", DEFAULT_MOVE_LIMIT_MS);
|
||||
const moveLimitActive = usesMoveLimit(mode);
|
||||
const timeImpact =
|
||||
mode === "time"
|
||||
? "Chronos cumules de 10 minutes, ajustes apres chaque phase cube avec plafond de 120 s pris en compte."
|
||||
? "Chronos cumules de 10 minutes par joueur, ajustes apres chaque phase cube avec plafond de 120 s pris en compte. Aucun temps par coup en mode Time."
|
||||
: "Le gagnant du cube commence la partie suivante, avec double coup V2 possible.";
|
||||
const timingText = moveLimitActive
|
||||
? `Temps configures : partie ${formatClock(blockDurationMs)}, coup ${formatClock(moveLimitMs)}.`
|
||||
: `Temps configure : Block ${formatClock(blockDurationMs)}.`;
|
||||
const quotaText = moveLimitActive
|
||||
? `Quota actif : ${quota} coups par joueur.`
|
||||
: `Quota actif : ${quota} coups par joueur et par Block.`;
|
||||
|
||||
if (moveSecondsField instanceof HTMLElement) {
|
||||
moveSecondsField.hidden = !moveLimitActive;
|
||||
}
|
||||
|
||||
if (moveSecondsInput instanceof HTMLInputElement) {
|
||||
moveSecondsInput.disabled = !moveLimitActive;
|
||||
}
|
||||
|
||||
document.body.classList.toggle("time-setup-mode", !moveLimitActive);
|
||||
|
||||
summary.innerHTML = `
|
||||
<strong>${MODES[mode].label}</strong>
|
||||
<span>${PRESETS[preset].description}</span>
|
||||
<span>Temps configures : partie ${formatClock(blockDurationMs)}, coup ${formatClock(moveLimitMs)}.</span>
|
||||
<span>${timingText}</span>
|
||||
<span>${timeImpact}</span>
|
||||
<span>Quota actif : ${quota} coups par joueur.</span>
|
||||
<span>${quotaText}</span>
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -228,7 +247,9 @@ function initChronoPage() {
|
||||
title: document.querySelector("#chronoTitle"),
|
||||
subtitle: document.querySelector("#chronoSubtitle"),
|
||||
blockTimer: document.querySelector("#blockTimer"),
|
||||
blockTimerLabel: document.querySelector("#blockTimerLabel"),
|
||||
moveTimer: document.querySelector("#moveTimer"),
|
||||
moveTimerCard: document.querySelector("#moveTimerCard"),
|
||||
centerLabel: document.querySelector("#chronoCenterLabel"),
|
||||
centerValue: document.querySelector("#chronoCenterValue"),
|
||||
spineLabel: document.querySelector("#spineLabel"),
|
||||
@@ -299,7 +320,7 @@ function initChronoPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
requestBlockClosure(match, "Cloture manuelle de la partie demandee par l'arbitre.");
|
||||
requestBlockClosure(match, `Cloture manuelle ${getBlockGenitivePhrase(match)} demandee par l'arbitre.`);
|
||||
dirty = true;
|
||||
if (!match.result && match.phase === "cube") {
|
||||
goToCubePage();
|
||||
@@ -310,7 +331,7 @@ function initChronoPage() {
|
||||
|
||||
refs.arbiterTimeoutButton?.addEventListener("click", () => {
|
||||
syncRunningState(match);
|
||||
if (match.result || match.phase !== "block") {
|
||||
if (match.result || match.phase !== "block" || !usesMoveLimit(match)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -326,7 +347,9 @@ function initChronoPage() {
|
||||
}
|
||||
|
||||
match.currentTurn = opponentOf(match.currentTurn);
|
||||
match.moveRemainingMs = getMoveLimitMs(match);
|
||||
if (usesMoveLimit(match)) {
|
||||
match.moveRemainingMs = getMoveLimitMs(match);
|
||||
}
|
||||
logEvent(match, "Trait corrige manuellement par l'arbitre.");
|
||||
dirty = true;
|
||||
render();
|
||||
@@ -416,17 +439,20 @@ function initChronoPage() {
|
||||
const clock = isWhite ? refs.whiteClock : refs.blackClock;
|
||||
const hint = isWhite ? refs.whiteHint : refs.blackHint;
|
||||
const zone = isWhite ? refs.whiteZone : refs.blackZone;
|
||||
const actorName = playerName(match, color);
|
||||
const active = match.currentTurn === color;
|
||||
const unitLabel = getBlockLabel(match);
|
||||
const unitPhrase = getBlockPhrase(match);
|
||||
|
||||
name.textContent = actorName;
|
||||
name.textContent = playerName(match, color);
|
||||
moves.textContent = `${match.moves[color]} / ${match.quota}`;
|
||||
clock.textContent = match.clocks
|
||||
? `Chrono ${formatSignedClock(match.clocks[color])}`
|
||||
: `Dernier cube ${renderLastCube(match, color)}`;
|
||||
clock.textContent = match.clocks ? formatSignedClock(match.clocks[color]) : `Dernier cube ${renderLastCube(match, color)}`;
|
||||
|
||||
button.classList.toggle("active-turn", active && !match.result);
|
||||
zone.classList.toggle("active-zone", active && !match.result);
|
||||
zone.classList.toggle("has-player-clock", Boolean(match.clocks));
|
||||
clock.classList.toggle("player-clock", Boolean(match.clocks));
|
||||
clock.classList.toggle("negative-clock", Boolean(match.clocks) && match.clocks[color] < 0);
|
||||
clock.classList.toggle("active-clock", Boolean(match.clocks) && active && !match.result);
|
||||
|
||||
if (match.result) {
|
||||
button.textContent = resultText(match);
|
||||
@@ -436,10 +462,10 @@ function initChronoPage() {
|
||||
}
|
||||
|
||||
if (!match.running) {
|
||||
button.textContent = "Partie en pause";
|
||||
button.textContent = `${unitLabel} en pause`;
|
||||
button.disabled = true;
|
||||
hint.textContent = active
|
||||
? "La partie n'a pas encore demarre ou a ete mise en pause."
|
||||
? `${unitPhrase} n'a pas encore demarre ou a ete mis en pause.`
|
||||
: `${playerName(match, match.currentTurn)} reprendra au demarrage.`;
|
||||
return;
|
||||
}
|
||||
@@ -480,11 +506,21 @@ function initChronoPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeMode = isTimeMode(match);
|
||||
const blockHeading = formatBlockHeading(match, match.blockNumber);
|
||||
|
||||
document.body.classList.toggle("time-mode", timeMode);
|
||||
refs.title.textContent = match.config.matchLabel;
|
||||
refs.subtitle.textContent = `Partie ${match.blockNumber} - ${MODES[match.config.mode].label} - ${renderModeContext(match)}`;
|
||||
refs.subtitle.textContent = `${blockHeading} - ${MODES[match.config.mode].label} - ${renderModeContext(match)}`;
|
||||
refs.blockTimerLabel.textContent = timeMode ? "Temps Block" : "Temps partie";
|
||||
refs.blockTimer.textContent = formatClock(match.blockRemainingMs);
|
||||
refs.moveTimer.textContent = formatClock(match.moveRemainingMs);
|
||||
refs.arbiterTimeoutButton.textContent = `Depassement ${formatClock(getMoveLimitMs(match))}`;
|
||||
refs.moveTimer.textContent = usesMoveLimit(match) ? formatClock(match.moveRemainingMs) : "--:--";
|
||||
refs.moveTimerCard.hidden = timeMode;
|
||||
refs.arbiterTimeoutButton.hidden = timeMode;
|
||||
refs.arbiterTimeoutButton.disabled = timeMode;
|
||||
if (usesMoveLimit(match)) {
|
||||
refs.arbiterTimeoutButton.textContent = `Depassement ${formatClock(getMoveLimitMs(match))}`;
|
||||
}
|
||||
|
||||
if (match.result) {
|
||||
refs.centerLabel.textContent = "Resultat";
|
||||
@@ -498,20 +534,20 @@ function initChronoPage() {
|
||||
refs.centerLabel.textContent = "Trait";
|
||||
refs.centerValue.textContent = playerName(match, match.currentTurn);
|
||||
refs.spineLabel.textContent = "Chrono en cours";
|
||||
refs.spineHeadline.textContent = `Partie ${match.blockNumber} active`;
|
||||
refs.spineHeadline.textContent = `${blockHeading} actif`;
|
||||
refs.spineText.textContent =
|
||||
"Chaque joueur tape sur sa grande zone quand son coup est termine. La page cube s'ouvrira automatiquement a la fin de la phase chess.";
|
||||
refs.primaryButton.textContent = "Pause arbitre";
|
||||
refs.arbiterStatus.textContent = `Partie en cours. Joueur au trait : ${playerName(match, match.currentTurn)}.`;
|
||||
refs.arbiterStatus.textContent = `${blockHeading} en cours. Joueur au trait : ${playerName(match, match.currentTurn)}.`;
|
||||
} else {
|
||||
refs.centerLabel.textContent = "Trait";
|
||||
refs.centerValue.textContent = playerName(match, match.currentTurn);
|
||||
refs.spineLabel.textContent = "Pret";
|
||||
refs.spineHeadline.textContent = `Partie ${match.blockNumber}`;
|
||||
refs.spineLabel.textContent = timeMode ? "Etat du Block" : "Pret";
|
||||
refs.spineHeadline.textContent = blockHeading;
|
||||
refs.spineText.textContent =
|
||||
"Demarrez la partie, puis laissez uniquement les deux grandes zones aux joueurs. La page cube prendra automatiquement le relais.";
|
||||
refs.primaryButton.textContent = "Demarrer la partie";
|
||||
refs.arbiterStatus.textContent = `Partie prete. ${playerName(match, match.currentTurn)} commencera.`;
|
||||
refs.primaryButton.textContent = timeMode ? "Demarrer le Block" : "Demarrer la partie";
|
||||
refs.arbiterStatus.textContent = `${blockHeading} pret. ${playerName(match, match.currentTurn)} commencera.`;
|
||||
}
|
||||
|
||||
refs.arbiterCloseBlockButton.textContent = "Passer au cube";
|
||||
@@ -555,6 +591,7 @@ function initCubePage() {
|
||||
const refs = {
|
||||
title: document.querySelector("#cubeTitle"),
|
||||
subtitle: document.querySelector("#cubeSubtitle"),
|
||||
blockLabelText: document.querySelector("#cubeBlockLabelText"),
|
||||
blockLabel: document.querySelector("#cubeBlockLabel"),
|
||||
elapsed: document.querySelector("#cubeElapsed"),
|
||||
centerLabel: document.querySelector("#cubeCenterLabel"),
|
||||
@@ -892,8 +929,11 @@ function initCubePage() {
|
||||
}
|
||||
|
||||
function render() {
|
||||
const blockHeading = formatBlockHeading(match, match.blockNumber);
|
||||
|
||||
refs.title.textContent = match.cube.number ? `Cube n${match.cube.number}` : "Phase cube";
|
||||
refs.subtitle.textContent = `Partie ${match.blockNumber} - ${MODES[match.config.mode].label} - ${renderModeContext(match)}`;
|
||||
refs.subtitle.textContent = `${blockHeading} - ${MODES[match.config.mode].label} - ${renderModeContext(match)}`;
|
||||
refs.blockLabelText.textContent = getBlockLabel(match);
|
||||
refs.blockLabel.textContent = `${match.blockNumber}`;
|
||||
refs.elapsed.textContent = renderCubeElapsed(match);
|
||||
|
||||
@@ -923,7 +963,9 @@ function initCubePage() {
|
||||
refs.centerValue.textContent = "Phase cube complete";
|
||||
refs.spineLabel.textContent = "Suite";
|
||||
refs.spineHeadline.textContent = "Ouvrir la page chrono";
|
||||
refs.spineText.textContent = "Appliquer le resultat du cube pour preparer la partie suivante.";
|
||||
refs.spineText.textContent = isTimeMode(match)
|
||||
? "Appliquer le resultat du cube pour preparer le Block suivant."
|
||||
: "Appliquer le resultat du cube pour preparer la partie suivante.";
|
||||
refs.primaryButton.textContent = "Appliquer et ouvrir la page chrono";
|
||||
refs.helpStatus.textContent = refs.spineText.textContent;
|
||||
} else if (match.cube.running) {
|
||||
@@ -1033,9 +1075,11 @@ function createMatch(config) {
|
||||
|
||||
logEvent(
|
||||
newMatch,
|
||||
`Match cree en mode ${MODES[config.mode].label}, cadence ${PRESETS[config.preset].label}, partie ${formatClock(config.blockDurationMs)} et coup ${formatClock(config.moveLimitMs)}.`,
|
||||
usesMoveLimit(config.mode)
|
||||
? `Match cree en mode ${MODES[config.mode].label}, cadence ${PRESETS[config.preset].label}, partie ${formatClock(config.blockDurationMs)} et coup ${formatClock(config.moveLimitMs)}.`
|
||||
: `Match cree en mode ${MODES[config.mode].label}, cadence ${PRESETS[config.preset].label}, Block ${formatClock(config.blockDurationMs)} sans temps par coup.`,
|
||||
);
|
||||
logEvent(newMatch, "Les Blancs commencent la partie 1.");
|
||||
logEvent(newMatch, `Les Blancs commencent ${formatBlockHeading(config, 1)}.`);
|
||||
return newMatch;
|
||||
}
|
||||
|
||||
@@ -1163,7 +1207,9 @@ function syncRunningState(storedMatch) {
|
||||
|
||||
storedMatch.lastTickAt = now;
|
||||
storedMatch.blockRemainingMs = Math.max(0, storedMatch.blockRemainingMs - delta);
|
||||
storedMatch.moveRemainingMs = Math.max(0, storedMatch.moveRemainingMs - delta);
|
||||
if (usesMoveLimit(storedMatch)) {
|
||||
storedMatch.moveRemainingMs = Math.max(0, storedMatch.moveRemainingMs - delta);
|
||||
}
|
||||
|
||||
if (storedMatch.clocks) {
|
||||
storedMatch.clocks[storedMatch.currentTurn] -= delta;
|
||||
@@ -1172,9 +1218,9 @@ function syncRunningState(storedMatch) {
|
||||
if (storedMatch.blockRemainingMs === 0) {
|
||||
requestBlockClosure(
|
||||
storedMatch,
|
||||
`Le temps de partie ${formatClock(getBlockDurationMs(storedMatch))} est ecoule.`,
|
||||
`Le temps ${getBlockGenitivePhrase(storedMatch)} ${formatClock(getBlockDurationMs(storedMatch))} est ecoule.`,
|
||||
);
|
||||
} else if (storedMatch.moveRemainingMs === 0) {
|
||||
} else if (usesMoveLimit(storedMatch) && storedMatch.moveRemainingMs === 0) {
|
||||
registerMoveTimeout(storedMatch, true);
|
||||
}
|
||||
|
||||
@@ -1193,8 +1239,8 @@ function startBlock(storedMatch) {
|
||||
logEvent(
|
||||
storedMatch,
|
||||
storedMatch.blockNumber === 1 && storedMatch.moves.white === 0 && storedMatch.moves.black === 0
|
||||
? "Partie 1 demarre."
|
||||
: `Partie ${storedMatch.blockNumber} relance.`,
|
||||
? `${formatBlockHeading(storedMatch, 1)} demarre.`
|
||||
: `${formatBlockHeading(storedMatch, storedMatch.blockNumber)} relance.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1205,7 +1251,7 @@ function pauseBlock(storedMatch) {
|
||||
|
||||
storedMatch.running = false;
|
||||
storedMatch.lastTickAt = null;
|
||||
logEvent(storedMatch, `Partie ${storedMatch.blockNumber} mise en pause.`);
|
||||
logEvent(storedMatch, `${formatBlockHeading(storedMatch, storedMatch.blockNumber)} passe en pause.`);
|
||||
}
|
||||
|
||||
function requestBlockClosure(storedMatch, reason) {
|
||||
@@ -1388,7 +1434,7 @@ function prepareNextTimeBlock(storedMatch) {
|
||||
storedMatch.cube.number = null;
|
||||
logEvent(
|
||||
storedMatch,
|
||||
`Partie ${storedMatch.blockNumber} prete. Le trait est conserve : ${playerName(
|
||||
`${formatBlockHeading(storedMatch, storedMatch.blockNumber)} pret. Le trait est conserve : ${playerName(
|
||||
storedMatch,
|
||||
storedMatch.currentTurn,
|
||||
)} reprend.`,
|
||||
@@ -1489,7 +1535,7 @@ function registerFreeDoubleMove(storedMatch) {
|
||||
}
|
||||
|
||||
function registerMoveTimeout(storedMatch, automatic) {
|
||||
if (!storedMatch || storedMatch.phase !== "block") {
|
||||
if (!storedMatch || storedMatch.phase !== "block" || !usesMoveLimit(storedMatch)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1718,6 +1764,34 @@ function getDurationInputMs(form, name, fallbackMs) {
|
||||
return seconds * 1000;
|
||||
}
|
||||
|
||||
function isTimeMode(matchOrConfig) {
|
||||
const mode =
|
||||
typeof matchOrConfig === "string"
|
||||
? matchOrConfig
|
||||
: matchOrConfig?.config?.mode ?? matchOrConfig?.mode;
|
||||
return mode === "time";
|
||||
}
|
||||
|
||||
function usesMoveLimit(matchOrConfig) {
|
||||
return !isTimeMode(matchOrConfig);
|
||||
}
|
||||
|
||||
function getBlockLabel(matchOrConfig) {
|
||||
return isTimeMode(matchOrConfig) ? "Block" : "Partie";
|
||||
}
|
||||
|
||||
function getBlockPhrase(matchOrConfig) {
|
||||
return isTimeMode(matchOrConfig) ? "Le Block" : "La partie";
|
||||
}
|
||||
|
||||
function getBlockGenitivePhrase(matchOrConfig) {
|
||||
return isTimeMode(matchOrConfig) ? "du Block" : "de la partie";
|
||||
}
|
||||
|
||||
function formatBlockHeading(matchOrConfig, blockNumber) {
|
||||
return `${getBlockLabel(matchOrConfig)} ${blockNumber}`;
|
||||
}
|
||||
|
||||
function playerName(storedMatch, color) {
|
||||
return color === "white" ? storedMatch.config.whiteName : storedMatch.config.blackName;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user