diff --git a/app.js b/app.js
index bb5db86..24c0157 100644
--- a/app.js
+++ b/app.js
@@ -596,13 +596,13 @@ function initCubePage() {
});
refs.whiteButton?.addEventListener("click", () => {
- captureCubeTime(match, "white");
+ handleCubeTap("white");
dirty = true;
render();
});
refs.blackButton?.addEventListener("click", () => {
- captureCubeTime(match, "black");
+ handleCubeTap("black");
dirty = true;
render();
});
@@ -618,17 +618,6 @@ function initCubePage() {
return;
}
- if (!match.cube.running && match.cube.times.white === null && match.cube.times.black === null) {
- startCubePhase(match);
- dirty = true;
- render();
- return;
- }
-
- if (match.cube.running) {
- return;
- }
-
if (match.cube.times.white !== null && match.cube.times.black !== null) {
if (match.config.mode === "twice" && match.cube.times.white === match.cube.times.black) {
replayCubePhase(match);
@@ -655,6 +644,23 @@ function initCubePage() {
replaceTo("index.html");
});
+ function handleCubeTap(color) {
+ if (match.result || match.phase !== "cube") {
+ return;
+ }
+
+ if (match.cube.times[color] !== null) {
+ return;
+ }
+
+ if (match.cube.playerState[color].running) {
+ captureCubeTime(match, color);
+ return;
+ }
+
+ startCubeTimer(match, color);
+ }
+
function renderCubeZone(color) {
const isWhite = color === "white";
const button = isWhite ? refs.whiteButton : refs.blackButton;
@@ -662,10 +668,11 @@ function initCubePage() {
const result = isWhite ? refs.whiteResult : refs.blackResult;
const cap = isWhite ? refs.whiteCap : refs.blackCap;
const hint = isWhite ? refs.whiteHint : refs.blackHint;
+ const playerState = match.cube.playerState[color];
const time = match.cube.times[color];
name.textContent = playerName(match, color);
- result.textContent = time === null ? "--" : formatStopwatch(time);
+ result.textContent = formatCubePlayerTime(match, color);
cap.textContent = renderCubeCap(match, time);
if (match.result) {
@@ -682,29 +689,23 @@ function initCubePage() {
return;
}
- if (!match.cube.running) {
- if (time !== null) {
- button.textContent = "Temps capture";
- button.disabled = true;
- hint.textContent = "Arret deja enregistre pour ce joueur.";
- } else {
- button.textContent = "Pret";
- button.disabled = true;
- hint.textContent = "Attente du demarrage de la phase cube.";
- }
- return;
- }
-
if (time !== null) {
- button.textContent = "Temps capture";
+ button.textContent = "Temps enregistre";
button.disabled = true;
- hint.textContent = "Le temps de ce joueur est deja enregistre.";
+ hint.textContent = "Ce joueur a deja termine son cube.";
return;
}
- button.textContent = "J'ai fini le cube";
+ if (playerState.running) {
+ button.textContent = "J'ai fini le cube";
+ button.disabled = false;
+ hint.textContent = "Tape au moment exact ou le cube est resolu.";
+ return;
+ }
+
+ button.textContent = "Demarrer mon chrono";
button.disabled = false;
- hint.textContent = "Tape au moment exact ou le cube est resolu.";
+ hint.textContent = "Chaque joueur lance son propre chrono quand il commence vraiment.";
}
function render() {
@@ -721,14 +722,6 @@ function initCubePage() {
refs.spineText.textContent = "Retournez a la configuration pour relancer une rencontre.";
refs.primaryButton.textContent = "Retour a l'accueil";
refs.helpStatus.textContent = "Le match est termine.";
- } else if (match.cube.running) {
- refs.centerLabel.textContent = "Etat";
- refs.centerValue.textContent = "Cube en cours";
- refs.spineLabel.textContent = "Arrets";
- refs.spineHeadline.textContent = "Attendre les deux fins";
- refs.spineText.textContent = "Chaque joueur tape sur sa grande zone des qu'il a resolu son cube.";
- refs.primaryButton.textContent = "Chrono cube en cours";
- refs.helpStatus.textContent = "Phase cube en cours. Les arrets sont saisis directement par les joueurs.";
} else if (
match.cube.times.white !== null &&
match.cube.times.black !== null &&
@@ -750,19 +743,40 @@ function initCubePage() {
refs.spineText.textContent = "Appliquer le resultat du cube pour preparer le block suivant.";
refs.primaryButton.textContent = "Appliquer et ouvrir la page chrono";
refs.helpStatus.textContent = refs.spineText.textContent;
+ } else if (match.cube.running) {
+ refs.centerLabel.textContent = "Etat";
+ refs.centerValue.textContent = "Chronos lances";
+ refs.spineLabel.textContent = "Arrets";
+ refs.spineHeadline.textContent = "Chaque joueur se chronometre";
+ refs.spineText.textContent = "Chaque joueur demarre quand il veut, puis retape sa zone une fois le cube termine.";
+ refs.primaryButton.textContent = "Attendre les deux temps";
+ refs.helpStatus.textContent = refs.spineText.textContent;
+ } else if (match.cube.times.white !== null || match.cube.times.black !== null) {
+ refs.centerLabel.textContent = "Etat";
+ refs.centerValue.textContent = "Un temps saisi";
+ refs.spineLabel.textContent = "Suite";
+ refs.spineHeadline.textContent = "Attendre l'autre joueur";
+ refs.spineText.textContent = "Le deuxieme joueur peut encore demarrer puis arreter son propre chrono quand il le souhaite.";
+ refs.primaryButton.textContent = "Attendre le deuxieme temps";
+ refs.helpStatus.textContent = refs.spineText.textContent;
} else {
refs.centerLabel.textContent = "Etat";
refs.centerValue.textContent = "Pret";
- refs.spineLabel.textContent = "Depart";
- refs.spineHeadline.textContent = "Lancer la phase cube";
- refs.spineText.textContent = "Demarrez le chrono commun, puis laissez chaque joueur utiliser uniquement sa grande zone.";
- refs.primaryButton.textContent = "Demarrer la phase cube";
- refs.helpStatus.textContent = "La phase cube n'a pas encore commence.";
+ refs.spineLabel.textContent = "Depart libre";
+ refs.spineHeadline.textContent = "Chaque joueur lance son chrono";
+ refs.spineText.textContent = "Au debut de sa resolution, chaque joueur tape sur sa grande zone pour demarrer son propre chrono.";
+ refs.primaryButton.textContent = "En attente des joueurs";
+ refs.helpStatus.textContent = refs.spineText.textContent;
}
renderCubeZone("black");
renderCubeZone("white");
- refs.primaryButton.disabled = match.result ? false : match.cube.running;
+ refs.primaryButton.disabled =
+ !match.result &&
+ !(
+ match.cube.times.white !== null &&
+ match.cube.times.black !== null
+ );
}
render();
@@ -819,6 +833,10 @@ function createMatch(config) {
white: null,
black: null,
},
+ playerState: {
+ white: createCubePlayerState(),
+ black: createCubePlayerState(),
+ },
round: 1,
history: [],
},
@@ -867,11 +885,26 @@ function normalizeRecoveredMatch(storedMatch) {
startedAt: null,
elapsedMs: 0,
times: { white: null, black: null },
+ playerState: {
+ white: createCubePlayerState(),
+ black: createCubePlayerState(),
+ },
round: 1,
history: [],
};
}
+ if (!storedMatch.cube.playerState) {
+ storedMatch.cube.playerState = {
+ white: createCubePlayerState(),
+ black: createCubePlayerState(),
+ };
+ }
+
+ storedMatch.cube.playerState.white = normalizeCubePlayerState(storedMatch.cube.playerState.white);
+ storedMatch.cube.playerState.black = normalizeCubePlayerState(storedMatch.cube.playerState.black);
+ storedMatch.cube.running = isAnyCubeTimerRunning(storedMatch);
+
if (!storedMatch.doubleCoup) {
storedMatch.doubleCoup = {
eligible: false,
@@ -968,11 +1001,15 @@ function openCubePhase(storedMatch) {
storedMatch.cube.startedAt = null;
storedMatch.cube.elapsedMs = 0;
storedMatch.cube.times = { white: null, black: null };
+ storedMatch.cube.playerState = {
+ white: createCubePlayerState(),
+ black: createCubePlayerState(),
+ };
storedMatch.cube.round = 1;
logEvent(storedMatch, `Page cube ouverte. Cube n${storedMatch.cube.number} designe.`);
}
-function startCubePhase(storedMatch) {
+function startCubeTimer(storedMatch, color) {
if (!storedMatch || storedMatch.phase !== "cube" || storedMatch.result) {
return;
}
@@ -981,25 +1018,41 @@ function startCubePhase(storedMatch) {
storedMatch.cube.number = pickCubeNumber();
}
+ if (storedMatch.cube.times[color] !== null || storedMatch.cube.playerState[color].running) {
+ return;
+ }
+
+ const playerState = storedMatch.cube.playerState[color];
+ playerState.running = true;
+ playerState.startedAt = Date.now();
storedMatch.cube.running = true;
- storedMatch.cube.startedAt = Date.now();
- storedMatch.cube.elapsedMs = 0;
- logEvent(storedMatch, `Phase cube demarree sur le cube n${storedMatch.cube.number}.`);
+ logEvent(
+ storedMatch,
+ `${playerName(storedMatch, color)} demarre son chrono cube sur le cube n${storedMatch.cube.number}.`,
+ );
}
function captureCubeTime(storedMatch, color) {
if (
!storedMatch ||
storedMatch.phase !== "cube" ||
- !storedMatch.cube.running ||
+ !storedMatch.cube.playerState[color].running ||
storedMatch.cube.times[color] !== null
) {
return;
}
- const elapsedMs = Date.now() - storedMatch.cube.startedAt;
+ const playerState = storedMatch.cube.playerState[color];
+ const elapsedMs = playerState.elapsedMs + (Date.now() - playerState.startedAt);
storedMatch.cube.times[color] = elapsedMs;
- storedMatch.cube.elapsedMs = Math.max(storedMatch.cube.elapsedMs, elapsedMs);
+ playerState.elapsedMs = elapsedMs;
+ playerState.startedAt = null;
+ playerState.running = false;
+ storedMatch.cube.elapsedMs = Math.max(
+ getCubePlayerElapsed(storedMatch, "white"),
+ getCubePlayerElapsed(storedMatch, "black"),
+ );
+ storedMatch.cube.running = isAnyCubeTimerRunning(storedMatch);
logEvent(storedMatch, `${playerName(storedMatch, color)} arrete le cube en ${formatStopwatch(elapsedMs)}.`);
if (
@@ -1059,6 +1112,10 @@ function prepareNextTwiceBlock(storedMatch, winner) {
storedMatch.cube.startedAt = null;
storedMatch.cube.elapsedMs = 0;
storedMatch.cube.times = { white: null, black: null };
+ storedMatch.cube.playerState = {
+ white: createCubePlayerState(),
+ black: createCubePlayerState(),
+ };
storedMatch.cube.number = null;
if (hadDouble) {
@@ -1085,6 +1142,10 @@ function prepareNextTimeBlock(storedMatch) {
storedMatch.cube.startedAt = null;
storedMatch.cube.elapsedMs = 0;
storedMatch.cube.times = { white: null, black: null };
+ storedMatch.cube.playerState = {
+ white: createCubePlayerState(),
+ black: createCubePlayerState(),
+ };
storedMatch.cube.number = null;
logEvent(
storedMatch,
@@ -1134,6 +1195,10 @@ function replayCubePhase(storedMatch) {
storedMatch.cube.startedAt = null;
storedMatch.cube.elapsedMs = 0;
storedMatch.cube.times = { white: null, black: null };
+ storedMatch.cube.playerState = {
+ white: createCubePlayerState(),
+ black: createCubePlayerState(),
+ };
storedMatch.cube.round += 1;
logEvent(storedMatch, `Phase cube relancee (tentative ${storedMatch.cube.round}).`);
}
@@ -1288,15 +1353,9 @@ function renderCubeElapsed(storedMatch) {
return "00:00.0";
}
- if (storedMatch.cube.running) {
- return formatStopwatch(Date.now() - storedMatch.cube.startedAt);
- }
-
- if (storedMatch.cube.elapsedMs > 0) {
- return formatStopwatch(storedMatch.cube.elapsedMs);
- }
-
- return "00:00.0";
+ return formatStopwatch(
+ Math.max(getCubePlayerElapsed(storedMatch, "white"), getCubePlayerElapsed(storedMatch, "black")),
+ );
}
function renderCubeCap(storedMatch, time) {
@@ -1502,3 +1561,52 @@ function readWindowNameState() {
return null;
}
}
+
+function createCubePlayerState() {
+ return {
+ running: false,
+ startedAt: null,
+ elapsedMs: 0,
+ };
+}
+
+function normalizeCubePlayerState(playerState) {
+ return {
+ running: Boolean(playerState?.running),
+ startedAt: typeof playerState?.startedAt === "number" ? playerState.startedAt : null,
+ elapsedMs: typeof playerState?.elapsedMs === "number" ? playerState.elapsedMs : 0,
+ };
+}
+
+function isAnyCubeTimerRunning(storedMatch) {
+ return storedMatch.cube.playerState.white.running || storedMatch.cube.playerState.black.running;
+}
+
+function getCubePlayerElapsed(storedMatch, color) {
+ const playerState = storedMatch.cube.playerState[color];
+
+ if (storedMatch.cube.times[color] !== null) {
+ return storedMatch.cube.times[color];
+ }
+
+ if (playerState.running && playerState.startedAt) {
+ return playerState.elapsedMs + (Date.now() - playerState.startedAt);
+ }
+
+ return playerState.elapsedMs;
+}
+
+function formatCubePlayerTime(storedMatch, color) {
+ const elapsed = getCubePlayerElapsed(storedMatch, color);
+ const playerState = storedMatch.cube.playerState[color];
+
+ if (playerState.running) {
+ return formatStopwatch(elapsed);
+ }
+
+ if (elapsed <= 0 && storedMatch.cube.times[color] === null) {
+ return "--";
+ }
+
+ return formatStopwatch(elapsed);
+}
diff --git a/cube.html b/cube.html
index c58b424..929461c 100644
--- a/cube.html
+++ b/cube.html
@@ -30,7 +30,7 @@
1