This commit is contained in:
Viktor Rådberg
2023-12-27 19:49:38 +01:00
parent 183fd9c079
commit 808c55109d
15 changed files with 687 additions and 630 deletions

View File

@@ -151,6 +151,7 @@ const Health = ({
const textContainer = textContainerRef.current;
const resizeObserver = new ResizeObserver(() => {
const calcFontSize = calculateFontSize(textContainer);
console.log(calcFontSize);
setFontSize(calcFontSize);
});
@@ -180,9 +181,9 @@ const Health = ({
const minRatio = Math.min(widthRatio, heightRatio);
const heightIsLarger = heightRatio > widthRatio;
const heightIs40PercentSmaller = heightRatio > widthRatio * 0.6;
const scaleFactor = heightIsLarger ? 0.8 : 1;
const scaleFactor = heightIs40PercentSmaller ? 0.8 : 1;
return minRatio * scaleFactor * 1;
};

View File

@@ -6,7 +6,7 @@ import { LoseGameButton } from '../Buttons/LoseButton';
import SettingsButton from '../Buttons/SettingsButton';
import CommanderDamageBar from '../Counters/CommanderDamageBar';
import ExtraCountersBar from '../Counters/ExtraCountersBar';
import PlayerMenu from '../PlayerMenu/PlayerMenu';
import PlayerMenu from '../Player/PlayerMenu';
import Health from './Health';
import { usePlayers } from '../../Hooks/usePlayers';
import { useGlobalSettings } from '../../Hooks/useGlobalSettings';

View File

@@ -1,8 +1,7 @@
import styled from 'styled-components';
import Play from './Views/Play';
import StartMenu from './Views/StartMenu/StartMenu';
import { useGlobalSettings } from '../Hooks/useGlobalSettings';
import Play2 from '../Components2/Views/Play2';
import StartMenu from './Views/StartMenu/StartMenu';
import { Play } from './Views/Play';
const StartWrapper = styled.div`
max-width: fit-content;
@@ -36,8 +35,7 @@ export const LifeTrinket = () => {
<>
{showPlay && initialGameSettings ? (
<PlayWrapper>
{/* <Play gridAreas={initialGameSettings?.gridAreas} /> */}
<Play2 />
<Play />
<EmergencyResetButton onClick={goToStart}>
<p>If you can see this, something is wrong.</p>
<p>Press screen to go to start.</p>

View File

@@ -1,22 +1,26 @@
import { Player } from '../../Types/Player';
import LifeCounter from '../../Components/LifeCounter/LifeCounter';
import { useGlobalSettings } from '../../Hooks/useGlobalSettings';
import LifeCounter from '../LifeCounter/LifeCounter';
import { Player as PlayerType } from '../../Types/Player';
export const FourPlayers = ({ players }: { players: Player[] }) => {
const { initialGameSettings } = useGlobalSettings();
let gridClasses: string;
switch (initialGameSettings?.orientation) {
case 'portrait':
gridClasses = 'grid-areas-fourPlayerPortrait';
break;
case 'side':
case 'landscape':
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:
gridClasses = 'grid-areas-fourPlayer';
break;
throw new Error('Invalid player index');
}
};
export const Player = (players: PlayerType[], gridClasses: string) => {
return (
<div className="w-full h-full bg-black">
<div className={`grid w-full h-full gap-1 box-border ${gridClasses} `}>
@@ -41,22 +45,3 @@ export const FourPlayers = ({ players }: { players: Player[] }) => {
</div>
);
};
export const getGridArea = (player: Player) => {
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');
}
};

View File

@@ -1,5 +1,8 @@
import styled from 'styled-components';
import Counters from '../Counters/Counters';
import { useGlobalSettings } from '../../Hooks/useGlobalSettings';
import { usePlayers } from '../../Hooks/usePlayers';
import { Orientation } from '../../Types/Settings';
import { Player } from '../Player/Player';
const MainWrapper = styled.div`
width: 100vmax;
@@ -9,16 +12,62 @@ const MainWrapper = styled.div`
overflow: hidden;
`;
type PlayProps = {
gridAreas: string;
};
export const Play = () => {
const { players } = usePlayers();
const { initialGameSettings } = useGlobalSettings();
const Play = ({ gridAreas }: PlayProps) => {
return (
<MainWrapper>
<Counters gridAreas={gridAreas} />
</MainWrapper>
);
};
let Layout: JSX.Element;
switch (players.length) {
case 1:
if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-onePlayerPortrait');
}
Layout = Player(players, 'grid-areas-onePlayerLandscape');
break;
case 2:
switch (initialGameSettings?.orientation) {
case Orientation.Portrait:
Layout = Player(players, 'grid-areas-twoPlayersOppositePortrait');
break;
default:
case Orientation.Landscape:
Layout = Player(players, 'grid-areas-twoPlayersSameSideLandscape');
break;
case Orientation.OppositeLandscape:
Layout = Player(players, 'grid-areas-twoPlayersOppositeLandscape');
break;
}
break;
case 3:
if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-threePlayersSide');
break;
}
Layout = Player(players, 'grid-areas-threePlayers');
break;
default:
case 4:
if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-fourPlayerPortrait');
break;
}
Layout = Player(players, 'grid-areas-fourPlayer');
break;
case 5:
if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-fivePlayersSide');
break;
}
Layout = Player(players, 'grid-areas-fivePlayers');
break;
case 6:
if (initialGameSettings?.orientation === Orientation.Portrait) {
Layout = Player(players, 'grid-areas-sixPlayersSide');
break;
}
Layout = Player(players, 'grid-areas-sixPlayers');
break;
}
export default Play;
return <MainWrapper>{Layout}</MainWrapper>;
};

View File

@@ -0,0 +1,397 @@
import { FormControlLabel, Radio, RadioGroup } from '@mui/material';
import React from 'react';
import styled from 'styled-components';
import { theme } from '../../../Data/theme';
import {
FivePlayers,
FourPlayers,
FourPlayersSide,
OnePlayerPortrait,
SixPlayers,
ThreePlayers,
ThreePlayersSide,
TwoPlayersOppositeLandscape,
TwoPlayersOppositePortrait,
TwoPlayersSameSide,
} from '../../../Icons/generated/Layouts';
import OnePlayerLandscape from '../../../Icons/generated/Layouts/OnePlayerLandscape';
import { Orientation } from '../../../Types/Settings';
const LayoutWrapper = styled.div`
flex-direction: row;
display: flex;
justify-content: space-evenly;
`;
type LayoutOptionsProps = {
numberOfPlayers: number;
selectedOrientation: Orientation;
onChange: (orientation: Orientation) => void;
};
const LayoutOptions2: React.FC<LayoutOptionsProps> = ({
numberOfPlayers,
selectedOrientation,
onChange,
}) => {
const iconHeight = '30vmin';
const iconWidth = '20vmin';
const renderLayoutOptions = () => {
switch (numberOfPlayers) {
case 1:
return (
<>
<FormControlLabel
value={Orientation.Landscape}
control={
<Radio
icon={
<OnePlayerLandscape
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<OnePlayerLandscape
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
<FormControlLabel
value={Orientation.Portrait}
control={
<Radio
icon={
<OnePlayerPortrait
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<OnePlayerPortrait
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
</>
);
case 2:
return (
<>
<FormControlLabel
value={Orientation.Landscape}
control={
<Radio
icon={
<TwoPlayersSameSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<TwoPlayersSameSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
<FormControlLabel
value={Orientation.Portrait}
control={
<Radio
icon={
<TwoPlayersOppositePortrait
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<TwoPlayersOppositePortrait
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
<FormControlLabel
value={Orientation.OppositeLandscape}
control={
<Radio
icon={
<TwoPlayersOppositeLandscape
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<TwoPlayersOppositeLandscape
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
</>
);
case 3:
return (
<>
<FormControlLabel
value={Orientation.Landscape}
control={
<Radio
icon={
<ThreePlayers
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<ThreePlayers
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
<FormControlLabel
value={Orientation.Portrait}
control={
<Radio
icon={
<ThreePlayersSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<ThreePlayersSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
</>
);
case 4:
return (
<>
<FormControlLabel
value={Orientation.Landscape}
control={
<Radio
icon={
<FourPlayers
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<FourPlayers
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
<FormControlLabel
value={Orientation.Portrait}
control={
<Radio
icon={
<FourPlayersSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<FourPlayersSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
</>
);
case 5:
return (
<>
<FormControlLabel
value={Orientation.Landscape}
control={
<Radio
icon={
<FivePlayers
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<FivePlayers
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
{/* <FormControlLabel
value={GridTemplateAreas.FivePlayersSide}
control={
<Radio
icon={
<FivePlayersSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<FivePlayersSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/> */}
</>
);
case 6:
return (
<>
<FormControlLabel
value={Orientation.Landscape}
control={
<Radio
icon={
<SixPlayers
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<SixPlayers
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/>
{/* <FormControlLabel
value={GridTemplateAreas.SixPlayersSide}
control={
<Radio
icon={
<SixPlayersSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.secondary.main}
/>
}
checkedIcon={
<SixPlayersSide
height={iconHeight}
width={iconWidth}
fill={theme.palette.primary.main}
/>
}
TouchRippleProps={{ style: { display: 'none' } }}
/>
}
label=""
/> */}
</>
);
default:
return null;
}
};
return (
<LayoutWrapper>
<RadioGroup
row
onChange={(_e, value) => {
onChange(value as Orientation);
}}
value={selectedOrientation}
style={{ justifyContent: 'center' }}
>
{renderLayoutOptions()}
</RadioGroup>
</LayoutWrapper>
);
};
export default LayoutOptions2;

View File

@@ -2,20 +2,19 @@ import { Button, FormControl, FormLabel, Switch } from '@mui/material';
import Slider from '@mui/material/Slider';
import { useEffect, useState } from 'react';
import styled from 'styled-components';
import { GridTemplateAreas } from '../../../Data/GridTemplateAreas';
import { createInitialPlayers } from '../../../Data/getInitialPlayers';
import { theme } from '../../../Data/theme';
import { useAnalytics } from '../../../Hooks/useAnalytics';
import { useGlobalSettings } from '../../../Hooks/useGlobalSettings';
import { usePlayers } from '../../../Hooks/usePlayers';
import { Cog, Info } from '../../../Icons/generated';
import { InitialGameSettings, Orientation } from '../../../Types/Settings';
import { InfoModal } from '../../Misc/InfoModal';
import { SettingsModal } from '../../Misc/SettingsModal';
import { Spacer } from '../../Misc/Spacer';
import { SupportMe } from '../../Misc/SupportMe';
import { H1, Paragraph } from '../../Misc/TextComponents';
import LayoutOptions from './LayoutOptions';
import { Spacer } from '../../Misc/Spacer';
import { usePlayers } from '../../../Hooks/usePlayers';
import { useGlobalSettings } from '../../../Hooks/useGlobalSettings';
import { InitialGameSettings } from '../../../Types/Settings';
import { SettingsModal } from '../../Misc/SettingsModal';
import LayoutOptions2 from './LayoutOptions2';
const MainWrapper = styled.div`
width: 100dvw;
@@ -118,8 +117,7 @@ const Start = () => {
numberOfPlayers: 4,
startingLifeTotal: 40,
useCommanderDamage: true,
gridAreas: GridTemplateAreas.FourPlayers,
orientation: 'portrait',
orientation: Orientation.Portrait,
gameFormat: 'commander',
}
);
@@ -158,32 +156,9 @@ const Start = () => {
return `${value}`;
};
const getDefaultLayout = (numberOfPlayers: number) => {
switch (numberOfPlayers) {
case 1:
return GridTemplateAreas.OnePlayerLandscape;
case 2:
return GridTemplateAreas.TwoPlayersSameSide;
case 3:
return GridTemplateAreas.ThreePlayers;
case 4:
return GridTemplateAreas.FourPlayers;
case 5:
return GridTemplateAreas.FivePlayers;
case 6:
return GridTemplateAreas.SixPlayers;
default:
return GridTemplateAreas.FourPlayers;
}
};
useEffect(() => {
const defaultLayout = getDefaultLayout(playerOptions.numberOfPlayers);
setPlayerOptions({
...playerOptions,
gridAreas: defaultLayout,
orientation: 'landscape',
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [playerOptions.numberOfPlayers]);
@@ -231,7 +206,7 @@ const Start = () => {
setPlayerOptions({
...playerOptions,
numberOfPlayers: value as number,
orientation: 'landscape',
orientation: Orientation.Landscape,
});
}}
/>
@@ -250,7 +225,7 @@ const Start = () => {
setPlayerOptions({
...playerOptions,
startingLifeTotal: value as number,
orientation: 'landscape',
orientation: Orientation.Landscape,
})
}
/>
@@ -272,7 +247,7 @@ const Start = () => {
useCommanderDamage: value,
numberOfPlayers: 4,
startingLifeTotal: 40,
orientation: 'landscape',
orientation: Orientation.Landscape,
});
return;
}
@@ -281,7 +256,7 @@ const Start = () => {
useCommanderDamage: value,
numberOfPlayers: 2,
startingLifeTotal: 20,
orientation: 'landscape',
orientation: Orientation.Landscape,
});
}}
/>
@@ -298,7 +273,7 @@ const Start = () => {
</ToggleButtonsWrapper>
<FormLabel>Layout</FormLabel>
<LayoutOptions
{/* <LayoutOptions
numberOfPlayers={playerOptions.numberOfPlayers}
gridAreas={playerOptions.gridAreas}
onChange={(gridAreas) =>
@@ -306,9 +281,20 @@ const Start = () => {
...playerOptions,
gridAreas,
//TODO fix the layout selection
orientation: 'portrait',
orientation: Orientation.Portrait,
})
}
/> */}
<LayoutOptions2
numberOfPlayers={playerOptions.numberOfPlayers}
selectedOrientation={playerOptions.orientation}
onChange={(orientation) => {
console.log('orientation', { orientation });
setPlayerOptions({
...playerOptions,
orientation,
});
}}
/>
</FormControl>

View File

@@ -1,59 +0,0 @@
import { Player, Rotation } from '../../Types/Player';
import styled from 'styled-components';
import { css } from 'styled-components';
import { CommanderDamage } from '../Buttons/CommanderDamage';
const CommanderDamageGrid = styled.div<{ $rotation: number }>`
display: flex;
flex-direction: row;
flex-grow: 1;
width: 100%;
${(props) => {
if (
props.$rotation === Rotation.SideFlipped ||
props.$rotation === Rotation.Side
) {
return css`
flex-direction: column;
height: 100%;
width: auto;
`;
}
}}
`;
type CommanderDamageBarProps = {
opponents: Player[];
player: Player;
handleLifeChange: (updatedLifeTotal: number) => void;
};
const CommanderDamageBar = ({
opponents,
player,
handleLifeChange,
}: CommanderDamageBarProps) => {
return (
<CommanderDamageGrid
$rotation={player.settings.rotation}
key={player.index}
>
{opponents.map((opponent) => {
if (!opponent.settings.useCommanderDamage) {
return null;
}
return (
<CommanderDamage
player={player}
opponent={opponent}
key={opponent.index}
handleLifeChange={handleLifeChange}
/>
);
})}
</CommanderDamageGrid>
);
};
export default CommanderDamageBar;

View File

@@ -1,196 +0,0 @@
import { CounterType, Player } from '../../Types/Player';
import ExtraCounter from '../Buttons/ExtraCounter';
import styled from 'styled-components';
import { css } from 'styled-components';
import { Rotation } from '../../Types/Player';
import {
CommanderTax,
Energy,
Experience,
PartnerTax,
Poison,
} from '../../Icons/generated';
import { usePlayers } from '../../Hooks/usePlayers';
const Container = styled.div<{ $rotation: Rotation }>`
width: 100%;
height: 20vmin;
display: flex;
${(props) => {
if (
props.$rotation === Rotation.SideFlipped ||
props.$rotation === Rotation.Side
) {
return css`
height: 100%;
width: 9.3vmax;
`;
}
}}
`;
export const ExtraCountersGrid = styled.div<{ $rotation: Rotation }>`
display: flex;
position: absolute;
width: 100%;
flex-direction: row;
flex-grow: 1;
bottom: 0;
pointer-events: none;
${(props) => {
if (
props.$rotation === Rotation.SideFlipped ||
props.$rotation === Rotation.Side
) {
return css`
flex-direction: column-reverse;
height: 100%;
width: auto;
bottom: auto;
right: -6px;
`;
}
}}
`;
type ExtraCountersBarProps = {
player: Player;
};
const ExtraCountersBar = ({ player }: ExtraCountersBarProps) => {
const { updatePlayer } = usePlayers();
const handleCounterChange = (
updatedCounterTotal: number,
type: CounterType
) => {
if (updatedCounterTotal < 0) {
return;
}
const existingCounter = player.extraCounters.find(
(counter) => counter.type === type
);
if (!existingCounter) {
const newCounter = {
type,
value: updatedCounterTotal,
};
const updatedExtraCounters = [...player.extraCounters, newCounter];
const updatedPlayer = { ...player, extraCounters: updatedExtraCounters };
updatePlayer(updatedPlayer);
return;
}
const updatedExtraCounters = player.extraCounters.map((counter) => {
if (counter.type === type) {
return { ...counter, value: updatedCounterTotal };
}
return counter;
});
const updatedPlayer = { ...player, extraCounters: updatedExtraCounters };
updatePlayer(updatedPlayer);
};
const iconSize =
player.settings.rotation === Rotation.SideFlipped ||
player.settings.rotation === Rotation.Side
? '5vmax'
: '10vmin';
const {
useCommanderDamage,
usePartner,
usePoison,
useEnergy,
useExperience,
} = player.settings;
const hasExtraCounters =
useCommanderDamage || usePartner || usePoison || useEnergy || useExperience;
if (!hasExtraCounters) {
return null;
}
return (
<Container $rotation={player.settings.rotation}>
<ExtraCountersGrid $rotation={player.settings.rotation}>
{useCommanderDamage && (
<ExtraCounter
rotation={player.settings.rotation}
Icon={<CommanderTax size={iconSize} opacity="0.5" color="black" />}
type={CounterType.CommanderTax}
counterTotal={
player.extraCounters?.find(
(counter) => counter.type === 'commanderTax'
)?.value
}
setCounterTotal={handleCounterChange}
playerIndex={player.index}
/>
)}
{Boolean(useCommanderDamage && usePartner) && (
<ExtraCounter
rotation={player.settings.rotation}
Icon={<PartnerTax size={iconSize} opacity="0.5" color="black" />}
type={CounterType.PartnerTax}
counterTotal={
player.extraCounters?.find(
(counter) => counter.type === 'partnerTax'
)?.value
}
setCounterTotal={handleCounterChange}
playerIndex={player.index}
/>
)}
{usePoison && (
<ExtraCounter
rotation={player.settings.rotation}
Icon={<Poison size={iconSize} opacity="0.5" color="black" />}
type={CounterType.Poison}
counterTotal={
player.extraCounters?.find((counter) => counter.type === 'poison')
?.value
}
setCounterTotal={handleCounterChange}
playerIndex={player.index}
/>
)}
{useEnergy && (
<ExtraCounter
rotation={player.settings.rotation}
Icon={<Energy size={iconSize} opacity="0.5" color="black" />}
type={CounterType.Energy}
counterTotal={
player.extraCounters?.find((counter) => counter.type === 'energy')
?.value
}
setCounterTotal={handleCounterChange}
playerIndex={player.index}
/>
)}
{useExperience && (
<ExtraCounter
rotation={player.settings.rotation}
Icon={<Experience size={iconSize} opacity="0.5" color="black" />}
type={CounterType.Experience}
counterTotal={
player.extraCounters?.find(
(counter) => counter.type === 'experience'
)?.value
}
setCounterTotal={handleCounterChange}
playerIndex={player.index}
/>
)}
</ExtraCountersGrid>
</Container>
);
};
export default ExtraCountersBar;

View File

@@ -1,46 +0,0 @@
import { Player } from '../../Types/Player';
import LifeCounter from '../../Components/LifeCounter/LifeCounter';
import { useGlobalSettings } from '../../Hooks/useGlobalSettings';
import { getGridArea } from './FourPlayers';
export const TwoPlayers = ({ players }: { players: Player[] }) => {
const { initialGameSettings } = useGlobalSettings();
let gridClasses: string;
switch (initialGameSettings?.orientation) {
case 'portrait':
gridClasses = 'grid-areas-twoPlayersOppositePortrait';
break;
default:
case 'side':
gridClasses = 'grid-areas-twoPlayersSameSideLandscape';
break;
case 'landscape':
gridClasses = 'grid-areas-twoPlayersOppositeLandscape';
break;
}
return (
<div className="w-full h-full bg-black">
<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>
</div>
);
};

View File

@@ -1,43 +0,0 @@
import styled from 'styled-components';
import { usePlayers } from '../../Hooks/usePlayers';
import { TwoPlayers } from '../Layouts/TwoPlayers';
import { FourPlayers } from '../Layouts/FourPlayers';
const MainWrapper = styled.div`
width: 100vmax;
height: 100vmin;
width: 100dvmax;
height: 100dvmin;
overflow: hidden;
`;
const Play2 = () => {
const { players } = usePlayers();
let Layout: JSX.Element;
switch (players.length) {
case 1:
Layout = <FourPlayers players={players} />;
break;
case 2:
Layout = <TwoPlayers players={players} />;
break;
case 3:
Layout = <FourPlayers players={players} />;
break;
default:
case 4:
Layout = <FourPlayers players={players} />;
break;
case 5:
Layout = <FourPlayers players={players} />;
break;
case 6:
Layout = <FourPlayers players={players} />;
break;
}
return <MainWrapper>{Layout}</MainWrapper>;
};
export default Play2;

View File

@@ -1,6 +1,5 @@
import { Player, Rotation } from '../Types/Player';
import { InitialGameSettings } from '../Types/Settings';
import { GridTemplateAreas } from './GridTemplateAreas';
import { InitialGameSettings, Orientation } from '../Types/Settings';
const presetColors = [
'#F06292', // Light Pink
@@ -13,184 +12,182 @@ const presetColors = [
'#FF8A80', // Coral
];
const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
if (gridAreas === GridTemplateAreas.OnePlayerLandscape && index === 0) {
return Rotation.Normal;
const getOrientationRotations = (
index: number,
numberOfPlayers: number,
orientation: Orientation
): Rotation => {
switch (numberOfPlayers) {
case 1:
switch (orientation) {
default:
case Orientation.Landscape:
return Rotation.Normal;
case Orientation.Portrait:
return Rotation.Side;
}
case 2:
switch (orientation) {
default:
case Orientation.Landscape:
return Rotation.Normal;
case Orientation.Portrait:
switch (index) {
case 0:
return Rotation.SideFlipped;
case 1:
return Rotation.Side;
default:
return Rotation.Normal;
}
case Orientation.OppositeLandscape:
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Normal;
default:
return Rotation.Normal;
}
}
case 3:
switch (orientation) {
default:
case Orientation.Landscape:
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Normal;
case 2:
return Rotation.Normal;
default:
return Rotation.Normal;
}
case Orientation.Portrait:
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Normal;
case 2:
return Rotation.Side;
default:
return Rotation.Normal;
}
}
case 4:
switch (orientation) {
default:
case Orientation.Landscape:
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Normal;
case 3:
return Rotation.Normal;
default:
return Rotation.Normal;
}
case Orientation.Portrait:
switch (index) {
case 0:
return Rotation.SideFlipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Normal;
case 3:
return Rotation.Side;
default:
return Rotation.Normal;
}
}
case 5:
switch (orientation) {
default:
case Orientation.Landscape:
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Normal;
case 3:
return Rotation.Normal;
case 4:
return Rotation.Normal;
default:
return Rotation.Normal;
}
case Orientation.Portrait:
switch (index) {
case 0:
return Rotation.Side;
case 1:
return Rotation.Side;
case 2:
return Rotation.SideFlipped;
case 3:
return Rotation.SideFlipped;
case 4:
return Rotation.SideFlipped;
default:
return Rotation.Normal;
}
}
case 6:
switch (orientation) {
default:
case Orientation.Landscape:
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Flipped;
case 3:
return Rotation.Normal;
case 4:
return Rotation.Normal;
case 5:
return Rotation.Normal;
default:
return Rotation.Normal;
}
case Orientation.Portrait:
switch (index) {
case 0:
return Rotation.Side;
case 1:
return Rotation.Side;
case 2:
return Rotation.Side;
case 3:
return Rotation.SideFlipped;
case 4:
return Rotation.SideFlipped;
case 5:
return Rotation.SideFlipped;
default:
return Rotation.Normal;
}
}
default:
return Rotation.Normal;
}
if (gridAreas === GridTemplateAreas.OnePlayerPortrait && index === 0) {
return Rotation.Side;
}
if (gridAreas === GridTemplateAreas.TwoPlayersOppositePortrait) {
switch (index) {
case 0:
return Rotation.SideFlipped;
case 1:
return Rotation.Side;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.TwoPlayersOppositeLandscape) {
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Normal;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.TwoPlayersSameSide) {
switch (index) {
case 0:
return Rotation.Normal;
case 1:
return Rotation.Normal;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.ThreePlayers) {
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Normal;
case 2:
return Rotation.Normal;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.ThreePlayersSide) {
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Normal;
case 2:
return Rotation.Side;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.FourPlayers) {
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Normal;
case 3:
return Rotation.Normal;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.FourPlayersSide) {
switch (index) {
case 0:
return Rotation.SideFlipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Normal;
case 3:
return Rotation.Side;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.FivePlayers) {
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Normal;
case 3:
return Rotation.Normal;
case 4:
return Rotation.Normal;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.FivePlayersSide) {
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Side;
case 3:
return Rotation.Normal;
case 4:
return Rotation.Normal;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.SixPlayers) {
switch (index) {
case 0:
return Rotation.Flipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Flipped;
case 3:
return Rotation.Normal;
case 4:
return Rotation.Normal;
case 5:
return Rotation.Normal;
default:
return Rotation.Normal;
}
}
if (gridAreas === GridTemplateAreas.SixPlayersSide) {
switch (index) {
case 0:
return Rotation.SideFlipped;
case 1:
return Rotation.Flipped;
case 2:
return Rotation.Flipped;
case 3:
return Rotation.Side;
case 4:
return Rotation.Normal;
case 5:
return Rotation.Normal;
default:
return Rotation.Normal;
}
}
return Rotation.Normal;
};
export const createInitialPlayers = ({
numberOfPlayers,
startingLifeTotal,
useCommanderDamage,
gridAreas,
orientation,
}: InitialGameSettings): Player[] => {
const players: Player[] = [];
const availableColors = [...presetColors]; // Create a copy of the colors array
@@ -213,7 +210,7 @@ export const createInitialPlayers = ({
});
}
const rotation = getRotation(i, gridAreas);
const rotation = getOrientationRotations(i, numberOfPlayers, orientation);
const player: Player = {
lifeTotal: startingLifeTotal,

View File

@@ -1,12 +1,11 @@
import { ReactNode, useEffect, useMemo, useState } from 'react';
import { useWakeLock } from 'react-screen-wake-lock';
import {
GlobalSettingsContext,
GlobalSettingsContextType,
} from '../Contexts/GlobalSettingsContext';
import { useWakeLock } from 'react-screen-wake-lock';
import { useAnalytics } from '../Hooks/useAnalytics';
import { InitialGameSettings, Settings } from '../Types/Settings';
import { GridTemplateAreas } from '../Data/GridTemplateAreas';
export const GlobalSettingsProvider = ({
children,
@@ -23,23 +22,11 @@ export const GlobalSettingsProvider = ({
savedShowPlay ? savedShowPlay === 'true' : false
);
const [initialGameSettings, setInitialSettings] =
const [initialGameSettings, setInitialGameSettings] =
useState<InitialGameSettings | null>(
savedGameSettings ? JSON.parse(savedGameSettings) : null
);
const setInitialGameSettings = (initialGameSettings: InitialGameSettings) => {
const defaultSettings: InitialGameSettings = {
numberOfPlayers: 4,
startingLifeTotal: 40,
useCommanderDamage: true,
gridAreas: GridTemplateAreas.FourPlayers,
orientation: 'portrait',
gameFormat: 'commander',
};
setInitialSettings({ ...defaultSettings, ...initialGameSettings });
};
const [settings, setSettings] = useState<Settings>(
savedSettings
? JSON.parse(savedSettings)

View File

@@ -1,6 +1,8 @@
import { GridTemplateAreas } from '../Data/GridTemplateAreas';
type Orientation = 'side' | 'landscape' | 'portrait';
export enum Orientation {
OppositeLandscape = 'opposite-landscape',
Landscape = 'landscape',
Portrait = 'portrait',
}
export type Settings = {
keepAwake: boolean;
@@ -13,8 +15,7 @@ export type InitialGameSettings = {
useCommanderDamage: boolean;
gameFormat?: GameFormat;
numberOfPlayers: number;
gridAreas: GridTemplateAreas;
orientation?: Orientation;
orientation: Orientation;
};
type GameFormat = 'commander' | 'standard' | 'two-headed-giant';