PWA fixed
added systemd service howto traefik nginix set_real_ip_from improved readme visuals fixed on mobile labels removed updated readme fixed visuals overlay for the hotkey disable screen lock clean up git precommit hooks clean up clean up update check for update feature added build-time information fixed date clean up added hook script fix fix fix hooks fixed webhook setup players stay in run all timers mode mqtt mqtt allways connected mqtt messages work capturing mqtt in edit player mqtt in Setup updated readme state of the mqtt Global Pass turn offline mode docs: update documentation to reflect current codebase and MQTT features - Update README.md with global MQTT commands - Enhance architecture.md with comprehensive data model and MQTT state - Update development.md with project structure and workflow - Remove redundant script listings - Fix formatting and organization rebase
This commit is contained in:
531
src/store/index.js
Normal file
531
src/store/index.js
Normal file
@@ -0,0 +1,531 @@
|
||||
import { createStore } from 'vuex';
|
||||
import { StorageService } from '../services/StorageService';
|
||||
import { parseTime, formatTime } from '../utils/timeFormatter';
|
||||
|
||||
const MAX_NEGATIVE_SECONDS = -(59 * 60 + 59); // -59:59
|
||||
const DEFAULT_AVATAR_MARKER = null; // Ensure this is defined
|
||||
|
||||
// Define predefined players
|
||||
const predefinedPlayers = [
|
||||
{
|
||||
id: 'predefined-1', // Unique ID for predefined player 1
|
||||
name: 'Player 1',
|
||||
avatar: DEFAULT_AVATAR_MARKER, // Or a specific avatar path if you have one
|
||||
initialTimerSec: 60 * 60, // 60:00
|
||||
currentTimerSec: 60 * 60,
|
||||
hotkey: '1', // Hotkey '1'
|
||||
isSkipped: false,
|
||||
isTimerRunning: false,
|
||||
},
|
||||
{
|
||||
id: 'predefined-2', // Unique ID for predefined player 2
|
||||
name: 'Player 2',
|
||||
avatar: DEFAULT_AVATAR_MARKER, // Or a specific avatar path
|
||||
initialTimerSec: 60 * 60, // 60:00
|
||||
currentTimerSec: 60 * 60,
|
||||
hotkey: '2', // Hotkey '2'
|
||||
isSkipped: false,
|
||||
isTimerRunning: false,
|
||||
}
|
||||
];
|
||||
|
||||
const initialState = {
|
||||
players: JSON.parse(JSON.stringify(predefinedPlayers)), // Start with predefined players (deep copy)
|
||||
globalHotkeyStopPause: null,
|
||||
globalHotkeyRunAll: null,
|
||||
globalHotkeyPassTurn: null,
|
||||
globalMqttStopPause: null,
|
||||
globalMqttRunAll: null,
|
||||
globalMqttPassTurn: null,
|
||||
mqttBrokerUrl: 'ws://localhost:9001',
|
||||
mqttConnectDesired: false,
|
||||
currentPlayerIndex: 0,
|
||||
gameMode: 'normal',
|
||||
isMuted: false,
|
||||
theme: 'dark',
|
||||
gameRunning: false,
|
||||
};
|
||||
|
||||
// Helper function to create a new player object
|
||||
const createPlayerObject = (playerData = {}) => ({
|
||||
id: playerData.id || Date.now().toString() + Math.random(),
|
||||
name: playerData.name || `Player ${store.state.players.length + 1}`, // Access store carefully here or pass length
|
||||
avatar: playerData.avatar === undefined ? DEFAULT_AVATAR_MARKER : playerData.avatar,
|
||||
initialTimerSec: playerData.initialTimerSec || 3600,
|
||||
currentTimerSec: playerData.currentTimerSec || playerData.initialTimerSec || 3600,
|
||||
hotkey: playerData.hotkey || null,
|
||||
mqttChar: playerData.mqttChar || null, // New
|
||||
isSkipped: playerData.isSkipped || false,
|
||||
isTimerRunning: playerData.isTimerRunning || false,
|
||||
});
|
||||
|
||||
export default createStore({
|
||||
state: () => {
|
||||
const persistedState = StorageService.getState();
|
||||
if (persistedState) {
|
||||
let playersToUse = persistedState.players;
|
||||
if (!playersToUse || (playersToUse.length === 0 && !persistedState.hasOwnProperty('players'))) {
|
||||
playersToUse = JSON.parse(JSON.stringify(predefinedPlayers.map(p => createPlayerObject(p))));
|
||||
} else if (persistedState.hasOwnProperty('players') && playersToUse.length === 0) {
|
||||
playersToUse = [];
|
||||
}
|
||||
|
||||
playersToUse = playersToUse.map(p_persisted => {
|
||||
const p_base = predefinedPlayers.find(p_def => p_def.id === p_persisted.id) || {};
|
||||
return createPlayerObject({ ...p_base, ...p_persisted, isTimerRunning: false });
|
||||
});
|
||||
|
||||
return {
|
||||
...initialState, // Start with all initial state defaults
|
||||
...persistedState, // Override with persisted values
|
||||
players: playersToUse, // Specifically set processed players
|
||||
globalHotkeyPassTurn: persistedState.globalHotkeyPassTurn || initialState.globalHotkeyPassTurn,
|
||||
globalMqttPassTurn: persistedState.globalMqttPassTurn || initialState.globalMqttPassTurn,
|
||||
globalHotkeyStopPause: persistedState.globalHotkeyStopPause || initialState.globalHotkeyStopPause,
|
||||
globalMqttStopPause: persistedState.globalMqttStopPause || initialState.globalMqttStopPause,
|
||||
globalHotkeyRunAll: persistedState.globalHotkeyRunAll || initialState.globalHotkeyRunAll,
|
||||
globalMqttRunAll: persistedState.globalMqttRunAll || initialState.globalMqttRunAll,
|
||||
mqttBrokerUrl: persistedState.mqttBrokerUrl || initialState.mqttBrokerUrl,
|
||||
mqttConnectDesired: persistedState.hasOwnProperty('mqttConnectDesired') ? persistedState.mqttConnectDesired : initialState.mqttConnectDesired,
|
||||
gameRunning: false, // Always start non-running
|
||||
currentPlayerIndex: persistedState.currentPlayerIndex !== undefined && persistedState.currentPlayerIndex < playersToUse.length ? persistedState.currentPlayerIndex : 0,
|
||||
};
|
||||
}
|
||||
// If no persisted state, deep copy initialState which includes new MQTT fields
|
||||
const newInitialState = JSON.parse(JSON.stringify(initialState));
|
||||
newInitialState.players = newInitialState.players.map(p => createPlayerObject(p));
|
||||
return newInitialState;
|
||||
},
|
||||
mutations: {
|
||||
ADD_PLAYER(state, playerConfig) {
|
||||
if (state.players.length < 99) {
|
||||
const newPlayer = createPlayerObject({
|
||||
name: playerConfig.name,
|
||||
avatar: playerConfig.avatar,
|
||||
initialTimerSec: playerConfig.initialTimerSec,
|
||||
currentTimerSec: playerConfig.currentTimerSec, // Set from form
|
||||
hotkey: playerConfig.hotkey,
|
||||
mqttChar: playerConfig.mqttChar // From form
|
||||
});
|
||||
state.players.push(newPlayer);
|
||||
} else {
|
||||
alert("Maximum player limit (99) reached.");
|
||||
}
|
||||
},
|
||||
UPDATE_PLAYER(state, updatedPlayer) {
|
||||
const index = state.players.findIndex(p => p.id === updatedPlayer.id);
|
||||
if (index !== -1) {
|
||||
state.players[index] = { ...state.players[index], ...updatedPlayer };
|
||||
}
|
||||
},
|
||||
SET_MQTT_BROKER_URL(state, url) {
|
||||
state.mqttBrokerUrl = url;
|
||||
state.mqttConnectDesired = true;
|
||||
},
|
||||
SET_MQTT_CONNECT_DESIRED(state, desired) {
|
||||
state.mqttConnectDesired = desired;
|
||||
},
|
||||
SET_GLOBAL_HOTKEY_STOP_PAUSE(state, key) {
|
||||
state.globalHotkeyStopPause = key;
|
||||
},
|
||||
SET_GLOBAL_HOTKEY_RUN_ALL(state, key) {
|
||||
state.globalHotkeyRunAll = key;
|
||||
},
|
||||
SET_GLOBAL_HOTKEY_PASS_TURN(state, key) {
|
||||
state.globalHotkeyPassTurn = key;
|
||||
},
|
||||
SET_GLOBAL_MQTT_PASS_TURN(state, char) {
|
||||
state.globalMqttPassTurn = char;
|
||||
},
|
||||
SET_GLOBAL_MQTT_STOP_PAUSE(state, char) {
|
||||
state.globalMqttStopPause = char;
|
||||
},
|
||||
SET_GLOBAL_MQTT_RUN_ALL(state, char) {
|
||||
state.globalMqttRunAll = char;
|
||||
},
|
||||
SET_PLAYERS(state, playersData) { // Used by fullResetApp and potentially reorder
|
||||
state.players = playersData.map(p => createPlayerObject(p));
|
||||
},
|
||||
SET_THEME(state, theme) { state.theme = theme; },
|
||||
DELETE_PLAYER(state, playerId) {
|
||||
state.players = state.players.filter(p => p.id !== playerId);
|
||||
if (state.currentPlayerIndex >= state.players.length && state.players.length > 0) {
|
||||
state.currentPlayerIndex = state.players.length - 1;
|
||||
} else if (state.players.length === 0) {
|
||||
state.currentPlayerIndex = 0;
|
||||
}
|
||||
},
|
||||
REORDER_PLAYERS(state, players) {
|
||||
state.players = players;
|
||||
},
|
||||
SHUFFLE_PLAYERS(state) {
|
||||
for (let i = state.players.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[state.players[i], state.players[j]] = [state.players[j], state.players[i]];
|
||||
}
|
||||
},
|
||||
REVERSE_PLAYERS(state) {
|
||||
state.players.reverse();
|
||||
},
|
||||
SET_CURRENT_PLAYER_INDEX(state, index) {
|
||||
state.currentPlayerIndex = index;
|
||||
},
|
||||
SET_GAME_MODE(state, mode) {
|
||||
state.gameMode = mode;
|
||||
},
|
||||
SET_IS_MUTED(state, muted) {
|
||||
state.isMuted = muted;
|
||||
},
|
||||
TOGGLE_THEME(state) {
|
||||
state.theme = state.theme === 'light' ? 'dark' : 'light';
|
||||
},
|
||||
SET_THEME(state, theme) {
|
||||
state.theme = theme;
|
||||
},
|
||||
DECREMENT_TIMER(state, { playerIndex }) {
|
||||
const player = state.players[playerIndex];
|
||||
if (player && player.isTimerRunning && !player.isSkipped) {
|
||||
player.currentTimerSec--;
|
||||
if (player.currentTimerSec < MAX_NEGATIVE_SECONDS) {
|
||||
player.currentTimerSec = MAX_NEGATIVE_SECONDS;
|
||||
player.isSkipped = true; // Auto-skip if max negative time reached
|
||||
player.isTimerRunning = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
RESET_PLAYER_TIMER(state, playerIndex) {
|
||||
if (state.players[playerIndex]) {
|
||||
state.players[playerIndex].currentTimerSec = state.players[playerIndex].initialTimerSec;
|
||||
state.players[playerIndex].isSkipped = false;
|
||||
state.players[playerIndex].isTimerRunning = false;
|
||||
}
|
||||
},
|
||||
RESET_ALL_TIMERS(state) {
|
||||
// When resetting, decide if you want to go back to *only* predefined players
|
||||
// or reset existing players' timers. The current spec "restores all timers to initial values"
|
||||
// implies resetting existing players. If it meant reverting to the initial player set,
|
||||
// this logic would need to change to:
|
||||
// state.players = JSON.parse(JSON.stringify(predefinedPlayers));
|
||||
// For now, sticking to resetting current players' timers:
|
||||
state.players.forEach(player => {
|
||||
player.currentTimerSec = player.initialTimerSec;
|
||||
player.isSkipped = false;
|
||||
player.isTimerRunning = false;
|
||||
});
|
||||
state.currentPlayerIndex = 0;
|
||||
state.gameMode = 'normal';
|
||||
state.gameRunning = false;
|
||||
},
|
||||
START_PLAYER_TIMER(state, playerIndex) {
|
||||
if(state.players[playerIndex] && !state.players[playerIndex].isSkipped) {
|
||||
state.players[playerIndex].isTimerRunning = true;
|
||||
state.gameRunning = true;
|
||||
}
|
||||
},
|
||||
PAUSE_PLAYER_TIMER(state, playerIndex) {
|
||||
if(state.players[playerIndex]) {
|
||||
state.players[playerIndex].isTimerRunning = false;
|
||||
}
|
||||
if (!state.players.some(p => p.isTimerRunning)) {
|
||||
state.gameRunning = false;
|
||||
}
|
||||
},
|
||||
PAUSE_ALL_TIMERS(state) {
|
||||
state.players.forEach(p => p.isTimerRunning = false);
|
||||
state.gameRunning = false;
|
||||
},
|
||||
SET_GAME_RUNNING(state, isRunning) {
|
||||
state.gameRunning = isRunning;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
loadState({ commit, state }) {
|
||||
// The state initializer already did the main loading from localStorage.
|
||||
// This action can be used for any *additional* setup after initial hydration
|
||||
// or to re-apply certain defaults if needed.
|
||||
// For now, it's mainly a confirmation that persisted state is used.
|
||||
|
||||
// Example: ensure theme is applied if it was loaded
|
||||
// This is already handled by App.vue's watcher, but could be centralized.
|
||||
// if (state.theme === 'dark') {
|
||||
// document.documentElement.classList.add('dark');
|
||||
// } else {
|
||||
// document.documentElement.classList.remove('dark');
|
||||
// }
|
||||
console.log("Store state loaded/initialized.");
|
||||
// It's good practice for actions to return a Promise if they are async
|
||||
// or if other parts of the app expect to chain .then()
|
||||
return Promise.resolve(); // Resolve immediately
|
||||
},
|
||||
saveState({ state }) {
|
||||
StorageService.saveState({
|
||||
players: state.players.map(p => ({ // Persist mqttChar for players
|
||||
id: p.id, name: p.name, avatar: p.avatar,
|
||||
initialTimerSec: p.initialTimerSec, currentTimerSec: p.currentTimerSec,
|
||||
hotkey: p.hotkey, mqttChar: p.mqttChar, // Save mqttChar
|
||||
isSkipped: p.isSkipped,
|
||||
})),
|
||||
globalHotkeyPassTurn: state.globalHotkeyPassTurn,
|
||||
globalMqttPassTurn: state.globalMqttPassTurn,
|
||||
globalHotkeyStopPause: state.globalHotkeyStopPause,
|
||||
globalHotkeyRunAll: state.globalHotkeyRunAll,
|
||||
globalMqttStopPause: state.globalMqttStopPause,
|
||||
globalMqttRunAll: state.globalMqttRunAll,
|
||||
mqttBrokerUrl: state.mqttBrokerUrl,
|
||||
mqttConnectDesired: state.mqttConnectDesired,
|
||||
currentPlayerIndex: state.currentPlayerIndex,
|
||||
gameMode: state.gameMode,
|
||||
isMuted: state.isMuted,
|
||||
theme: state.theme,
|
||||
});
|
||||
},
|
||||
addPlayer({ commit, dispatch }, player) {
|
||||
commit('ADD_PLAYER', player);
|
||||
dispatch('saveState');
|
||||
},
|
||||
setMqttBrokerUrl({ commit, dispatch }, url) {
|
||||
commit('SET_MQTT_BROKER_URL', url);
|
||||
dispatch('saveState');
|
||||
},
|
||||
setMqttConnectDesired({ commit, dispatch }, desired) {
|
||||
commit('SET_MQTT_CONNECT_DESIRED', desired);
|
||||
dispatch('saveState');
|
||||
},
|
||||
setGlobalMqttStopPause({ commit, dispatch }, char) {
|
||||
commit('SET_GLOBAL_MQTT_STOP_PAUSE', char);
|
||||
dispatch('saveState');
|
||||
},
|
||||
setGlobalMqttRunAll({ commit, dispatch }, char) {
|
||||
commit('SET_GLOBAL_MQTT_RUN_ALL', char);
|
||||
dispatch('saveState');
|
||||
},
|
||||
setGlobalHotkeyPassTurn({ commit, dispatch }, key) {
|
||||
commit('SET_GLOBAL_HOTKEY_PASS_TURN', key);
|
||||
dispatch('saveState');
|
||||
},
|
||||
setGlobalMqttPassTurn({ commit, dispatch }, char) {
|
||||
commit('SET_GLOBAL_MQTT_PASS_TURN', char);
|
||||
dispatch('saveState');
|
||||
},
|
||||
updatePlayer({ commit, dispatch }, player) {
|
||||
commit('UPDATE_PLAYER', player);
|
||||
dispatch('saveState');
|
||||
},
|
||||
deletePlayer({ commit, dispatch }, playerId) {
|
||||
commit('DELETE_PLAYER', playerId);
|
||||
dispatch('saveState');
|
||||
},
|
||||
reorderPlayers({commit, dispatch}, players) {
|
||||
commit('REORDER_PLAYERS', players);
|
||||
dispatch('saveState');
|
||||
},
|
||||
shufflePlayers({commit, dispatch}) {
|
||||
commit('SHUFFLE_PLAYERS');
|
||||
dispatch('saveState');
|
||||
},
|
||||
reversePlayers({commit, dispatch}) {
|
||||
commit('REVERSE_PLAYERS');
|
||||
dispatch('saveState');
|
||||
},
|
||||
toggleTheme({ commit, dispatch }) {
|
||||
commit('TOGGLE_THEME');
|
||||
dispatch('saveState');
|
||||
},
|
||||
setGlobalHotkey({ commit, dispatch }, key) {
|
||||
commit('SET_GLOBAL_HOTKEY_STOP_PAUSE', key);
|
||||
dispatch('saveState');
|
||||
},
|
||||
setMuted({ commit, dispatch }, muted) {
|
||||
commit('SET_IS_MUTED', muted);
|
||||
dispatch('saveState');
|
||||
},
|
||||
resetGame({ commit, dispatch }) {
|
||||
commit('RESET_ALL_TIMERS');
|
||||
dispatch('saveState');
|
||||
},
|
||||
setGlobalHotkeyStopPause({ commit, dispatch }, key) {
|
||||
commit('SET_GLOBAL_HOTKEY_STOP_PAUSE', key);
|
||||
dispatch('saveState');
|
||||
},
|
||||
setGlobalHotkeyRunAll({ commit, dispatch }, key) {
|
||||
commit('SET_GLOBAL_HOTKEY_RUN_ALL', key);
|
||||
dispatch('saveState');
|
||||
},
|
||||
fullResetApp({ commit, dispatch, state: currentGlobalState }) {
|
||||
StorageService.clearState();
|
||||
const freshInitialState = JSON.parse(JSON.stringify(initialState));
|
||||
freshInitialState.players = freshInitialState.players.map(p => createPlayerObject(p));
|
||||
|
||||
commit('SET_PLAYERS', freshInitialState.players);
|
||||
commit('SET_CURRENT_PLAYER_INDEX', freshInitialState.currentPlayerIndex);
|
||||
commit('SET_GAME_MODE', freshInitialState.gameMode);
|
||||
commit('SET_IS_MUTED', freshInitialState.isMuted);
|
||||
commit('SET_MQTT_BROKER_URL', freshInitialState.mqttBrokerUrl);
|
||||
commit('SET_MQTT_CONNECT_DESIRED', freshInitialState.mqttConnectDesired);
|
||||
commit('SET_GLOBAL_HOTKEY_STOP_PAUSE', freshInitialState.globalHotkeyStopPause);
|
||||
commit('SET_GLOBAL_MQTT_STOP_PAUSE', freshInitialState.globalMqttStopPause);
|
||||
commit('SET_GLOBAL_HOTKEY_RUN_ALL', freshInitialState.globalHotkeyRunAll);
|
||||
commit('SET_GLOBAL_MQTT_RUN_ALL', freshInitialState.globalMqttRunAll);
|
||||
commit('SET_GLOBAL_HOTKEY_PASS_TURN', freshInitialState.globalHotkeyPassTurn);
|
||||
commit('SET_GLOBAL_MQTT_PASS_TURN', freshInitialState.globalMqttPassTurn);
|
||||
|
||||
if (currentGlobalState.theme !== freshInitialState.theme) {
|
||||
commit('SET_THEME', freshInitialState.theme);
|
||||
}
|
||||
commit('SET_GAME_RUNNING', false);
|
||||
dispatch('saveState');
|
||||
},
|
||||
tick({ commit, state }) {
|
||||
if (state.gameMode === 'normal') {
|
||||
if (state.players[state.currentPlayerIndex]?.isTimerRunning) {
|
||||
commit('DECREMENT_TIMER', { playerIndex: state.currentPlayerIndex });
|
||||
}
|
||||
} else if (state.gameMode === 'allTimers') {
|
||||
state.players.forEach((player, index) => {
|
||||
if (player.isTimerRunning) {
|
||||
commit('DECREMENT_TIMER', { playerIndex: index });
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
passTurn({ commit, state, dispatch }) {
|
||||
const numPlayers = state.players.length;
|
||||
if (numPlayers === 0) return;
|
||||
|
||||
const currentIdx = state.currentPlayerIndex;
|
||||
const currentPlayerTimerWasRunning = state.players[currentIdx]?.isTimerRunning;
|
||||
|
||||
commit('PAUSE_PLAYER_TIMER', currentIdx);
|
||||
|
||||
let nextPlayerIndex = (currentIdx + 1) % numPlayers;
|
||||
let skippedCount = 0;
|
||||
while(state.players[nextPlayerIndex]?.isSkipped && skippedCount < numPlayers) {
|
||||
nextPlayerIndex = (nextPlayerIndex + 1) % numPlayers;
|
||||
skippedCount++;
|
||||
}
|
||||
|
||||
if (skippedCount === numPlayers) {
|
||||
commit('PAUSE_ALL_TIMERS');
|
||||
dispatch('saveState');
|
||||
return;
|
||||
}
|
||||
|
||||
commit('SET_CURRENT_PLAYER_INDEX', nextPlayerIndex);
|
||||
|
||||
if (currentPlayerTimerWasRunning && !state.players[nextPlayerIndex].isSkipped) {
|
||||
commit('START_PLAYER_TIMER', nextPlayerIndex);
|
||||
} else {
|
||||
if (state.players[nextPlayerIndex] && !state.players[nextPlayerIndex].isSkipped) {
|
||||
commit('PAUSE_PLAYER_TIMER', nextPlayerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
dispatch('saveState');
|
||||
},
|
||||
toggleCurrentPlayerTimerNormalMode({ commit, state, dispatch }) {
|
||||
const player = state.players[state.currentPlayerIndex];
|
||||
if (!player) return;
|
||||
|
||||
if (player.isTimerRunning) {
|
||||
commit('PAUSE_PLAYER_TIMER', state.currentPlayerIndex);
|
||||
} else if (!player.isSkipped) {
|
||||
commit('START_PLAYER_TIMER', state.currentPlayerIndex);
|
||||
}
|
||||
dispatch('saveState');
|
||||
},
|
||||
togglePlayerTimerAllTimersMode({ commit, state, dispatch }, playerIndex) {
|
||||
const player = state.players[playerIndex];
|
||||
if (!player) return;
|
||||
|
||||
if (player.isTimerRunning) {
|
||||
commit('PAUSE_PLAYER_TIMER', playerIndex);
|
||||
} else if (!player.isSkipped) {
|
||||
commit('START_PLAYER_TIMER', playerIndex);
|
||||
}
|
||||
|
||||
const anyTimerRunning = state.players.some(p => p.isTimerRunning && !p.isSkipped);
|
||||
if (!anyTimerRunning && state.players.length > 0 && state.gameMode === 'allTimers') {
|
||||
// This auto-revert logic is now in GameView.vue watcher for better control over timing
|
||||
}
|
||||
dispatch('saveState');
|
||||
},
|
||||
globalStopPauseAll({ commit, state, dispatch }) {
|
||||
if (state.gameMode === 'normal') {
|
||||
dispatch('toggleCurrentPlayerTimerNormalMode');
|
||||
} else {
|
||||
const anyTimerRunning = state.players.some(p => p.isTimerRunning && !p.isSkipped);
|
||||
if (anyTimerRunning) {
|
||||
commit('PAUSE_ALL_TIMERS');
|
||||
} else {
|
||||
state.players.forEach((player, index) => {
|
||||
if (!player.isSkipped) {
|
||||
commit('START_PLAYER_TIMER', index);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
dispatch('saveState');
|
||||
},
|
||||
switchToAllTimersMode({ commit, state, dispatch }) {
|
||||
commit('SET_GAME_MODE', 'allTimers');
|
||||
let anyStarted = false;
|
||||
state.players.forEach((player, index) => {
|
||||
if (!player.isSkipped) {
|
||||
commit('START_PLAYER_TIMER', index);
|
||||
anyStarted = true;
|
||||
}
|
||||
});
|
||||
if(anyStarted) commit('SET_GAME_RUNNING', true);
|
||||
else commit('SET_GAME_RUNNING', false);
|
||||
dispatch('saveState');
|
||||
},
|
||||
switchToNormalMode({commit, state, dispatch}) {
|
||||
commit('PAUSE_ALL_TIMERS');
|
||||
commit('SET_GAME_MODE', 'normal');
|
||||
// Determine current player for normal mode, respecting skips
|
||||
let currentIdx = state.currentPlayerIndex;
|
||||
let skippedCount = 0;
|
||||
while(state.players[currentIdx]?.isSkipped && skippedCount < state.players.length) {
|
||||
currentIdx = (currentIdx + 1) % state.players.length;
|
||||
skippedCount++;
|
||||
}
|
||||
if (skippedCount < state.players.length) {
|
||||
commit('SET_CURRENT_PLAYER_INDEX', currentIdx);
|
||||
// Timer for this player should remain paused as per PAUSE_ALL_TIMERS
|
||||
} else {
|
||||
// All players skipped, game is effectively paused.
|
||||
commit('SET_GAME_RUNNING', false);
|
||||
}
|
||||
dispatch('saveState');
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
players: state => state.players,
|
||||
currentPlayer: state => state.players[state.currentPlayerIndex],
|
||||
nextPlayer: state => {
|
||||
if (!state.players || state.players.length < 1) return null;
|
||||
let nextIndex = (state.currentPlayerIndex + 1) % state.players.length;
|
||||
let count = 0;
|
||||
while(state.players[nextIndex]?.isSkipped && count < state.players.length) {
|
||||
nextIndex = (nextIndex + 1) % state.players.length;
|
||||
count++;
|
||||
}
|
||||
return state.players[nextIndex];
|
||||
},
|
||||
getPlayerById: (state) => (id) => state.players.find(p => p.id === id),
|
||||
gameMode: state => state.gameMode,
|
||||
isMuted: state => state.isMuted,
|
||||
theme: state => state.theme,
|
||||
mqttBrokerUrl: state => state.mqttBrokerUrl,
|
||||
mqttConnectDesired: state => state.mqttConnectDesired,
|
||||
globalHotkeyStopPause: state => state.globalHotkeyStopPause,
|
||||
globalMqttStopPause: state => state.globalMqttStopPause,
|
||||
globalHotkeyRunAll: state => state.globalHotkeyRunAll,
|
||||
globalMqttRunAll: state => state.globalMqttRunAll,
|
||||
globalHotkeyPassTurn: state => state.globalHotkeyPassTurn,
|
||||
globalMqttPassTurn: state => state.globalMqttPassTurn,
|
||||
totalPlayers: state => state.players.length,
|
||||
gameRunning: state => state.gameRunning,
|
||||
maxNegativeTimeReached: () => MAX_NEGATIVE_SECONDS,
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user