Compare commits

...

8 Commits
0.6.7 ... 0.6.9

Author SHA1 Message Date
Viktor Rådberg
d6cd678e9f fix random interval wrapper showing if enabled but show player is disabled 2024-03-17 18:41:58 +01:00
Viktor Rådberg
334b46db6e bump 2024-03-16 22:29:25 +01:00
Viktor Rådberg
e03ecc6f51 Merge pull request #33 from Vikeo/random-player-interval
random player interval
2024-03-16 22:28:49 +01:00
Viktor Rådberg
d4dc44076d fix lint 2024-03-16 22:28:37 +01:00
Viktor Rådberg
a1b5cfd871 fix tsc 2024-03-16 22:26:06 +01:00
Viktor Rådberg
f11eea5e53 better styling 2024-03-16 22:23:03 +01:00
Viktor Rådberg
905912a7fd fix random interval 2024-03-16 21:59:24 +01:00
Viktor Rådberg
a90dd7c9ea wip 2024-03-16 14:40:18 +01:00
14 changed files with 304 additions and 118 deletions

View File

@@ -1,7 +1,7 @@
{ {
"name": "life-trinket", "name": "life-trinket",
"private": true, "private": true,
"version": "0.6.7", "version": "0.6.9",
"type": "commonjs", "type": "commonjs",
"engines": { "engines": {
"node": ">=18", "node": ">=18",

View File

@@ -13,7 +13,7 @@ import { LoseGameButton } from '../Buttons/LoseButton';
import CommanderDamageBar from '../Counters/CommanderDamageBar'; import CommanderDamageBar from '../Counters/CommanderDamageBar';
import ExtraCountersBar from '../Counters/ExtraCountersBar'; import ExtraCountersBar from '../Counters/ExtraCountersBar';
import { Paragraph } from '../Misc/TextComponents'; import { Paragraph } from '../Misc/TextComponents';
import PlayerMenu from '../Player/PlayerMenu'; import PlayerMenu from '../Players/PlayerMenu';
import Health from './Health'; import Health from './Health';
import { baseColors } from '../../../tailwind.config'; import { baseColors } from '../../../tailwind.config';
@@ -90,13 +90,15 @@ const playerCanLose = (player: Player) => {
type LifeCounterProps = { type LifeCounterProps = {
player: Player; player: Player;
opponents: Player[]; opponents: Player[];
isStartingPlayer?: boolean;
}; };
const RECENT_DIFFERENCE_TTL = 3_000; const RECENT_DIFFERENCE_TTL = 3_000;
const LifeCounter = ({ player, opponents }: LifeCounterProps) => { const LifeCounter = ({ player, opponents }: LifeCounterProps) => {
const { updatePlayer, updateLifeTotal } = usePlayers(); const { updatePlayer, updateLifeTotal } = usePlayers();
const { settings } = useGlobalSettings(); const { settings, playing, setPlaying, stopPlayerRandomization } =
useGlobalSettings();
const playingTimerRef = useRef<NodeJS.Timeout | undefined>(undefined); const playingTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);
const [showPlayerMenu, setShowPlayerMenu] = useState(false); const [showPlayerMenu, setShowPlayerMenu] = useState(false);
@@ -114,12 +116,10 @@ const LifeCounter = ({ player, opponents }: LifeCounterProps) => {
trackMouse: true, trackMouse: true,
onSwipedDown: (e) => { onSwipedDown: (e) => {
e.event.stopPropagation(); e.event.stopPropagation();
console.log(`User DOWN Swiped on player ${player.index}`);
setShowPlayerMenu(true); setShowPlayerMenu(true);
}, },
onSwipedUp: (e) => { onSwipedUp: (e) => {
e.event.stopPropagation(); e.event.stopPropagation();
console.log(`User UP Swiped on player ${player.index}`);
setShowPlayerMenu(false); setShowPlayerMenu(false);
}, },
@@ -151,12 +151,26 @@ const LifeCounter = ({ player, opponents }: LifeCounterProps) => {
}, [recentDifference, document.body.clientHeight, document.body.clientWidth]); }, [recentDifference, document.body.clientHeight, document.body.clientWidth]);
useEffect(() => { useEffect(() => {
playingTimerRef.current = setTimeout(() => { if (
localStorage.setItem('playing', 'true'); player.isStartingPlayer &&
}, 10_000); ((!playing &&
settings.useRandomStartingPlayerInterval &&
stopPlayerRandomization) ||
(!settings.useRandomStartingPlayerInterval && !playing))
) {
playingTimerRef.current = setTimeout(() => {
setPlaying(true);
}, 10_000);
}
return () => clearTimeout(playingTimerRef.current); return () => clearTimeout(playingTimerRef.current);
}, []); }, [
player.isStartingPlayer,
playing,
setPlaying,
settings.useRandomStartingPlayerInterval,
stopPlayerRandomization,
]);
player.settings.rotation === Rotation.SideFlipped || player.settings.rotation === Rotation.SideFlipped ||
player.settings.rotation === Rotation.Side; player.settings.rotation === Rotation.Side;
@@ -191,39 +205,53 @@ const LifeCounter = ({ player, opponents }: LifeCounterProps) => {
style={{ rotate: `${calcRotation}deg` }} style={{ rotate: `${calcRotation}deg` }}
{...handlers} {...handlers}
> >
{settings.showStartingPlayer && {!playing && settings.showStartingPlayer && player.isStartingPlayer && (
player.isStartingPlayer && <div
player.showStartingPlayer && ( className="z-20 flex absolute w-full h-full justify-center items-center select-none cursor-pointer webkit-user-select-none"
<div style={{
className="z-10 flex absolute w-full h-full justify-center items-center select-none cursor-pointer webkit-user-select-none" rotate: `${calcRotation}deg`,
backgroundImage:
stopPlayerRandomization ||
!settings.useRandomStartingPlayerInterval
? `radial-gradient(circle at center, ${player.color}, ${baseColors.primary.main})`
: 'none',
}}
onClick={() => {
clearTimeout(playingTimerRef.current);
setPlaying(true);
}}
>
<DynamicText
style={{ style={{
rotate: `${calcRotation}deg`, rotate: `${calcTextRotation}deg`,
backgroundImage: `radial-gradient(circle at center, ${player.color}, ${baseColors.primary.main})`,
}}
onClick={() => {
clearTimeout(playingTimerRef.current);
localStorage.setItem('playing', 'true');
player.showStartingPlayer = false;
updatePlayer(player);
}} }}
> >
<DynamicText <div className="flex flex-col justify-center items-center">
style={{ <Paragraph>👑</Paragraph>
rotate: `${calcTextRotation}deg`, {(stopPlayerRandomization ||
}} !settings.useRandomStartingPlayerInterval) && (
> <>
<div className="flex flex-col justify-center items-center"> <Paragraph>You start!</Paragraph>
<Paragraph>👑</Paragraph> <Paragraph className="text-xl">(Press to hide)</Paragraph>
<Paragraph>You start!</Paragraph> </>
<Paragraph className="text-xl">(Press to hide)</Paragraph> )}
</div> </div>
</DynamicText> </DynamicText>
</div> </div>
)} )}
{player.hasLost && ( {player.hasLost && (
<PlayerLostWrapper $rotation={player.settings.rotation} /> <PlayerLostWrapper $rotation={player.settings.rotation} />
)} )}
{settings.showStartingPlayer &&
settings.useRandomStartingPlayerInterval &&
!stopPlayerRandomization &&
!playing && (
<div
className="flex absolute w-full h-full justify-center items-center pointer-events-none select-none webkit-user-select-none z-10"
style={{ backgroundColor: player.color }}
/>
)}
<CommanderDamageBar <CommanderDamageBar
opponents={opponents} opponents={opponents}
player={player} player={player}

View File

@@ -121,6 +121,26 @@ export const SettingsModal = ({ isOpen, closeModal }: SettingsModalProps) => {
this is enabled. this is enabled.
</Description> </Description>
</SettingContainer> </SettingContainer>
<SettingContainer>
<ToggleContainer>
<FormLabel>Randomize starting player with interval</FormLabel>
<Switch
checked={settings.useRandomStartingPlayerInterval}
onChange={() => {
setSettings({
...settings,
useRandomStartingPlayerInterval:
!settings.useRandomStartingPlayerInterval,
});
}}
/>
</ToggleContainer>
<Description>
Will randomize between all players at when starting a game,
pressing the screen aborts the interval and chooses the player
that has the crown.
</Description>
</SettingContainer>
<SettingContainer> <SettingContainer>
<ToggleContainer> <ToggleContainer>
<FormLabel>Keep Awake</FormLabel> <FormLabel>Keep Awake</FormLabel>

View File

@@ -1,50 +0,0 @@
import LifeCounter from '../LifeCounter/LifeCounter';
import { Player as PlayerType } from '../../Types/Player';
import { twc } from 'react-twc';
const getGridArea = (player: PlayerType) => {
switch (player.index) {
case 0:
return 'grid-in-player0';
case 1:
return 'grid-in-player1';
case 2:
return 'grid-in-player2';
case 3:
return 'grid-in-player3';
case 4:
return 'grid-in-player4';
case 5:
return 'grid-in-player5';
default:
throw new Error('Invalid player index');
}
};
const PlayerWrapper = twc.div`w-full h-full bg-black`;
export const Player = (players: PlayerType[], gridClasses: string) => {
return (
<PlayerWrapper>
<div className={`grid w-full h-full gap-1 box-border ${gridClasses} `}>
{players.map((player) => {
const gridArea = getGridArea(player);
return (
<div
key={player.index}
className={`flex justify-center items-center align-middle ${gridArea}`}
>
<LifeCounter
player={player}
opponents={players.filter(
(opponent) => opponent.index !== player.index
)}
/>
</div>
);
})}
</div>
</PlayerWrapper>
);
};

View File

@@ -104,7 +104,14 @@ const PlayerMenu = ({
containerRef: settingsContainerRef, containerRef: settingsContainerRef,
}); });
const { fullscreen, wakeLock, goToStart, settings } = useGlobalSettings(); const {
fullscreen,
wakeLock,
goToStart,
settings,
setPlaying,
setStopPlayerRandomization,
} = useGlobalSettings();
const { updatePlayer, resetCurrentGame } = usePlayers(); const { updatePlayer, resetCurrentGame } = usePlayers();
const handleColorChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleColorChange = (event: React.ChangeEvent<HTMLInputElement>) => {
@@ -122,6 +129,13 @@ const PlayerMenu = ({
const handleResetGame = () => { const handleResetGame = () => {
resetCurrentGame(); resetCurrentGame();
setShowPlayerMenu(false); setShowPlayerMenu(false);
setPlaying(false);
setStopPlayerRandomization(false);
};
const handleGoToStart = () => {
goToStart();
setStopPlayerRandomization(false);
}; };
const toggleFullscreen = () => { const toggleFullscreen = () => {
@@ -291,7 +305,7 @@ const PlayerMenu = ({
cursor: 'pointer', cursor: 'pointer',
userSelect: 'none', userSelect: 'none',
}} }}
onClick={goToStart} onClick={handleGoToStart}
aria-label="Back to start" aria-label="Back to start"
> >
<Exit size={iconSize} style={{ rotate: '180deg' }} /> <Exit size={iconSize} style={{ rotate: '180deg' }} />

View File

@@ -0,0 +1,146 @@
import { useEffect, useRef } from 'react';
import { twc } from 'react-twc';
import { useGlobalSettings } from '../../Hooks/useGlobalSettings';
import { usePlayers } from '../../Hooks/usePlayers';
import { Player as PlayerType } from '../../Types/Player';
import LifeCounter from '../LifeCounter/LifeCounter';
const getGridArea = (player: PlayerType) => {
switch (player.index) {
case 0:
return 'grid-in-player0';
case 1:
return 'grid-in-player1';
case 2:
return 'grid-in-player2';
case 3:
return 'grid-in-player3';
case 4:
return 'grid-in-player4';
case 5:
return 'grid-in-player5';
default:
throw new Error('Invalid player index');
}
};
const PlayersWrapper = twc.div`w-full h-full bg-black`;
export const Players = (players: PlayerType[], gridClasses: string) => {
const randomIntervalRef = useRef<NodeJS.Timeout | null>(null);
const prevRandomIndexRef = useRef<number>(-1);
const {
settings,
stopPlayerRandomization,
setStopPlayerRandomization,
playing,
} = useGlobalSettings();
const { setPlayers } = usePlayers();
useEffect(() => {
if (
settings.showStartingPlayer &&
settings.useRandomStartingPlayerInterval &&
!stopPlayerRandomization &&
!playing
) {
randomIntervalRef.current = setInterval(() => {
let randomIndex: number;
do {
randomIndex = Math.floor(Math.random() * players.length);
} while (randomIndex === prevRandomIndexRef.current);
prevRandomIndexRef.current = randomIndex;
setPlayers(
players.map((p) =>
p.index === prevRandomIndexRef.current
? {
...p,
isStartingPlayer: true,
}
: {
...p,
isStartingPlayer: false,
}
)
);
}, 100);
}
if (!settings.useRandomStartingPlayerInterval) {
const randomPlayerIndex = Math.floor(Math.random() * players.length);
setPlayers(
players.map((p) =>
p.index === randomPlayerIndex
? {
...p,
isStartingPlayer: true,
}
: {
...p,
isStartingPlayer: false,
}
)
);
}
return () => {
if (randomIntervalRef.current) {
clearInterval(randomIntervalRef.current);
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
players.length,
playing,
setPlayers,
settings.useRandomStartingPlayerInterval,
stopPlayerRandomization,
]);
return (
<PlayersWrapper>
{settings.showStartingPlayer &&
settings.useRandomStartingPlayerInterval &&
!stopPlayerRandomization &&
!playing && (
<div
className="absolute flex justify-center items-center bg-black bg-opacity-40 h-screen w-screen portrait:h-[100vw] portrait:w-[100vh] z-50 cursor-pointer text-5xl"
onClick={() => {
if (randomIntervalRef.current) {
clearInterval(randomIntervalRef.current);
randomIntervalRef.current = null;
}
setStopPlayerRandomization(true);
}}
>
<div className="bg-primary-main px-8 py-2 rounded-2xl opacity-70 text-[5vmax]">
PRESS TO SELECT PLAYER
</div>
</div>
)}
<div className={`grid w-full h-full gap-1 box-border ${gridClasses} `}>
{players.map((player) => {
const gridArea = getGridArea(player);
return (
<div
key={player.index}
className={`flex justify-center items-center align-middle ${gridArea}`}
>
<LifeCounter
player={player}
opponents={players.filter(
(opponent) => opponent.index !== player.index
)}
/>
</div>
);
})}
</div>
</PlayersWrapper>
);
};

View File

@@ -1,7 +1,7 @@
import { useGlobalSettings } from '../../Hooks/useGlobalSettings'; import { useGlobalSettings } from '../../Hooks/useGlobalSettings';
import { usePlayers } from '../../Hooks/usePlayers'; import { usePlayers } from '../../Hooks/usePlayers';
import { Orientation } from '../../Types/Settings'; import { Orientation } from '../../Types/Settings';
import { Player } from '../Player/Player'; import { Players } from '../Players/Players';
import { twc } from 'react-twc'; import { twc } from 'react-twc';
const MainWrapper = twc.div`w-[100dvmax] h-[100dvmin] overflow-hidden`; const MainWrapper = twc.div`w-[100dvmax] h-[100dvmin] overflow-hidden`;
@@ -14,52 +14,52 @@ export const Play = () => {
switch (players.length) { switch (players.length) {
case 1: case 1:
if (initialGameSettings?.orientation === Orientation.Portrait) { if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-onePlayerPortrait'); Layout = Players(players, 'grid-areas-onePlayerPortrait');
} }
Layout = Player(players, 'grid-areas-onePlayerLandscape'); Layout = Players(players, 'grid-areas-onePlayerLandscape');
break; break;
case 2: case 2:
switch (initialGameSettings?.orientation) { switch (initialGameSettings?.orientation) {
case Orientation.Portrait: case Orientation.Portrait:
Layout = Player(players, 'grid-areas-twoPlayersOppositePortrait'); Layout = Players(players, 'grid-areas-twoPlayersOppositePortrait');
break; break;
default: default:
case Orientation.Landscape: case Orientation.Landscape:
Layout = Player(players, 'grid-areas-twoPlayersSameSideLandscape'); Layout = Players(players, 'grid-areas-twoPlayersSameSideLandscape');
break; break;
case Orientation.OppositeLandscape: case Orientation.OppositeLandscape:
Layout = Player(players, 'grid-areas-twoPlayersOppositeLandscape'); Layout = Players(players, 'grid-areas-twoPlayersOppositeLandscape');
break; break;
} }
break; break;
case 3: case 3:
if (initialGameSettings?.orientation === Orientation.Portrait) { if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-threePlayersSide'); Layout = Players(players, 'grid-areas-threePlayersSide');
break; break;
} }
Layout = Player(players, 'grid-areas-threePlayers'); Layout = Players(players, 'grid-areas-threePlayers');
break; break;
default: default:
case 4: case 4:
if (initialGameSettings?.orientation === Orientation.Portrait) { if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-fourPlayerPortrait'); Layout = Players(players, 'grid-areas-fourPlayerPortrait');
break; break;
} }
Layout = Player(players, 'grid-areas-fourPlayer'); Layout = Players(players, 'grid-areas-fourPlayer');
break; break;
case 5: case 5:
if (initialGameSettings?.orientation === Orientation.Portrait) { if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-fivePlayersSide'); Layout = Players(players, 'grid-areas-fivePlayersSide');
break; break;
} }
Layout = Player(players, 'grid-areas-fivePlayers'); Layout = Players(players, 'grid-areas-fivePlayers');
break; break;
case 6: case 6:
if (initialGameSettings?.orientation === Orientation.Portrait) { if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-sixPlayersSide'); Layout = Players(players, 'grid-areas-sixPlayersSide');
break; break;
} }
Layout = Player(players, 'grid-areas-sixPlayers'); Layout = Players(players, 'grid-areas-sixPlayers');
break; break;
} }

View File

@@ -22,6 +22,10 @@ export type GlobalSettingsContextType = {
setInitialGameSettings: (initialGameSettings: InitialGameSettings) => void; setInitialGameSettings: (initialGameSettings: InitialGameSettings) => void;
settings: Settings; settings: Settings;
setSettings: (settings: Settings) => void; setSettings: (settings: Settings) => void;
playing: boolean;
setPlaying: (playing: boolean) => void;
stopPlayerRandomization: boolean;
setStopPlayerRandomization: (stopRandom: boolean) => void;
isPWA: boolean; isPWA: boolean;
}; };

View File

@@ -7,6 +7,8 @@ export type PlayersContextType = {
updatePlayer: (updatedPlayer: Player) => void; updatePlayer: (updatedPlayer: Player) => void;
updateLifeTotal: (player: Player, updatedLifeTotal: number) => number; updateLifeTotal: (player: Player, updatedLifeTotal: number) => number;
resetCurrentGame: () => void; resetCurrentGame: () => void;
startingPlayerIndex: number;
setStartingPlayerIndex: (index: number) => void;
}; };
export const PlayersContext = createContext<PlayersContextType | null>(null); export const PlayersContext = createContext<PlayersContextType | null>(null);

View File

@@ -191,10 +191,8 @@ export const createInitialPlayers = ({
}: InitialGameSettings): Player[] => { }: InitialGameSettings): Player[] => {
const players: Player[] = []; const players: Player[] = [];
const availableColors = [...presetColors]; // Create a copy of the colors array const availableColors = [...presetColors]; // Create a copy of the colors array
const firstPlayerIndex = Math.floor(Math.random() * numberOfPlayers);
for (let i = 0; i <= numberOfPlayers - 1; i++) { for (let i = 0; i <= numberOfPlayers - 1; i++) {
const isStartingPlayer = i === firstPlayerIndex;
const colorIndex = Math.floor(Math.random() * availableColors.length); const colorIndex = Math.floor(Math.random() * availableColors.length);
const color = availableColors[colorIndex]; const color = availableColors[colorIndex];
@@ -224,11 +222,10 @@ export const createInitialPlayers = ({
usePoison: false, usePoison: false,
rotation, rotation,
}, },
isStartingPlayer,
showStartingPlayer: isStartingPlayer,
extraCounters: [], extraCounters: [],
commanderDamage, commanderDamage,
hasLost: false, hasLost: false,
isStartingPlayer: false,
isSide: rotation === Rotation.Side || rotation === Rotation.SideFlipped, isSide: rotation === Rotation.Side || rotation === Rotation.SideFlipped,
}; };

View File

@@ -21,11 +21,23 @@ export const GlobalSettingsProvider = ({
const savedShowPlay = localStorage.getItem('showPlay'); const savedShowPlay = localStorage.getItem('showPlay');
const savedGameSettings = localStorage.getItem('initialGameSettings'); const savedGameSettings = localStorage.getItem('initialGameSettings');
const savedSettings = localStorage.getItem('settings'); const savedSettings = localStorage.getItem('settings');
const savedPlaying = localStorage.getItem('playing');
const [playing, setPlaying] = useState<boolean>(
savedPlaying ? savedPlaying === 'true' : false
);
const setPlayingAndLocalStorage = (playing: boolean) => {
setPlaying(playing);
localStorage.setItem('playing', String(playing));
};
const [showPlay, setShowPlay] = useState<boolean>( const [showPlay, setShowPlay] = useState<boolean>(
savedShowPlay ? savedShowPlay === 'true' : false savedShowPlay ? savedShowPlay === 'true' : false
); );
const [stopPlayerRandomization, setStopPlayerRandomization] =
useState<boolean>(false);
const [initialGameSettings, setInitialGameSettings] = const [initialGameSettings, setInitialGameSettings] =
useState<InitialGameSettings | null>( useState<InitialGameSettings | null>(
savedGameSettings ? JSON.parse(savedGameSettings) : null savedGameSettings ? JSON.parse(savedGameSettings) : null
@@ -39,6 +51,7 @@ export const GlobalSettingsProvider = ({
keepAwake: true, keepAwake: true,
showStartingPlayer: true, showStartingPlayer: true,
showPlayerMenuCog: true, showPlayerMenuCog: true,
useRandomStartingPlayerInterval: false,
} }
); );
@@ -47,6 +60,8 @@ export const GlobalSettingsProvider = ({
localStorage.removeItem('players'); localStorage.removeItem('players');
localStorage.removeItem('playing'); localStorage.removeItem('playing');
localStorage.removeItem('showPlay'); localStorage.removeItem('showPlay');
setPlaying(false);
setShowPlay(false); setShowPlay(false);
}; };
@@ -153,10 +168,14 @@ export const GlobalSettingsProvider = ({
goToStart, goToStart,
showPlay, showPlay,
setShowPlay, setShowPlay,
playing,
setPlaying: setPlayingAndLocalStorage,
initialGameSettings, initialGameSettings,
setInitialGameSettings, setInitialGameSettings,
settings, settings,
setSettings, setSettings,
stopPlayerRandomization,
setStopPlayerRandomization,
isPWA: window?.matchMedia('(display-mode: standalone)').matches, isPWA: window?.matchMedia('(display-mode: standalone)').matches,
}; };
}, [ }, [
@@ -165,10 +184,12 @@ export const GlobalSettingsProvider = ({
initialGameSettings, initialGameSettings,
isFullscreen, isFullscreen,
isSupported, isSupported,
playing,
release, release,
request, request,
settings, settings,
showPlay, showPlay,
stopPlayerRandomization,
type, type,
]); ]);

View File

@@ -7,6 +7,17 @@ import { InitialGameSettings } from '../Types/Settings';
export const PlayersProvider = ({ children }: { children: ReactNode }) => { export const PlayersProvider = ({ children }: { children: ReactNode }) => {
const savedPlayers = localStorage.getItem('players'); const savedPlayers = localStorage.getItem('players');
const savedStartingPlayerIndex = localStorage.getItem('startingPlayerIndex');
const [startingPlayerIndex, setStartingPlayerIndex] = useState<number>(
savedStartingPlayerIndex ? parseInt(savedStartingPlayerIndex) : -1
);
const setStartingPlayerIndexAndLocalStorage = (index: number) => {
setStartingPlayerIndex(index);
localStorage.setItem('startingPlayerIndex', String(index));
};
const [players, setPlayers] = useState<Player[]>( const [players, setPlayers] = useState<Player[]>(
savedPlayers ? JSON.parse(savedPlayers) : [] savedPlayers ? JSON.parse(savedPlayers) : []
); );
@@ -50,9 +61,7 @@ export const PlayersProvider = ({ children }: { children: ReactNode }) => {
return; return;
} }
const startingPlayerIndex = Math.floor( const newStartingPlayerIndex = Math.floor(Math.random() * players.length);
Math.random() * initialGameSettings.numberOfPlayers
);
players.forEach((player: Player) => { players.forEach((player: Player) => {
player.commanderDamage.map((damage) => { player.commanderDamage.map((damage) => {
@@ -65,16 +74,9 @@ export const PlayersProvider = ({ children }: { children: ReactNode }) => {
}); });
player.lifeTotal = initialGameSettings.startingLifeTotal; player.lifeTotal = initialGameSettings.startingLifeTotal;
player.hasLost = false; player.hasLost = false;
const isStartingPlayer = player.index === startingPlayerIndex; player.isStartingPlayer = newStartingPlayerIndex === player.index;
player.isStartingPlayer = isStartingPlayer;
if (player.isStartingPlayer) {
player.showStartingPlayer = true;
}
updatePlayer(player); updatePlayer(player);
}); });
@@ -87,8 +89,10 @@ export const PlayersProvider = ({ children }: { children: ReactNode }) => {
updatePlayer, updatePlayer,
updateLifeTotal, updateLifeTotal,
resetCurrentGame, resetCurrentGame,
startingPlayerIndex,
setStartingPlayerIndex: setStartingPlayerIndexAndLocalStorage,
}; };
}, [players]); }, [players, startingPlayerIndex]);
return ( return (
<PlayersContext.Provider value={ctxValue}> <PlayersContext.Provider value={ctxValue}>

View File

@@ -6,7 +6,6 @@ export type Player = {
commanderDamage: CommanderDamage[]; commanderDamage: CommanderDamage[];
extraCounters: ExtraCounter[]; extraCounters: ExtraCounter[];
isStartingPlayer: boolean; isStartingPlayer: boolean;
showStartingPlayer: boolean;
hasLost: boolean; hasLost: boolean;
isSide: boolean; isSide: boolean;
}; };

View File

@@ -17,6 +17,7 @@ export type Settings = {
showStartingPlayer: boolean; showStartingPlayer: boolean;
showPlayerMenuCog: boolean; showPlayerMenuCog: boolean;
goFullscreenOnStart: boolean; goFullscreenOnStart: boolean;
useRandomStartingPlayerInterval: boolean;
}; };
export type InitialGameSettings = { export type InitialGameSettings = {