Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
JessicaMulein committed Oct 27, 2024
1 parent fef949e commit 3ae976e
Show file tree
Hide file tree
Showing 28 changed files with 465 additions and 300 deletions.
14 changes: 8 additions & 6 deletions src/__fixtures__/dominion-lib-fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { IMatsEnabled } from '@/game/interfaces/mats-enabled';
import { IExpansionsEnabled } from '@/game/interfaces/expansions-enabled';
import { CurrentStep } from '@/game/enumerations/current-step';
import { ILogEntry } from '@/game/interfaces/log-entry';
import { deepClone } from '@/game/utils';
import { IVictoryDetails } from '@/game/interfaces/victory-details';

export function createMockGame(playerCount: number, overrides?: Partial<IGame>): IGame {
const options: IGameOptions = {
Expand Down Expand Up @@ -67,12 +69,12 @@ export function createMockPlayer(victory?: Partial<IPlayer['victory']>, index?:
DefaultPlayerColors[
index ?? faker.number.int({ min: 0, max: DefaultPlayerColors.length - 1 })
],
mats: { ...EmptyMatDetails },
turn: { ...DefaultTurnDetails },
newTurn: { ...DefaultTurnDetails },
mats: EmptyMatDetails(),
turn: DefaultTurnDetails(),
newTurn: DefaultTurnDetails(),
victory: {
...EmptyVictoryDetails,
...victory,
...EmptyVictoryDetails(),
...(victory ? deepClone<Partial<IVictoryDetails>>(victory) : {}),
},
} as IPlayer;
}
Expand All @@ -89,6 +91,6 @@ export function createMockLog(log?: Partial<ILogEntry>): ILogEntry {
correction: false,
linkedActionId: faker.string.uuid(),
prevPlayerIndex: faker.number.int({ min: 0, max: 3 }),
...log,
...(log ? deepClone<Partial<ILogEntry>>(log) : {}),
};
}
34 changes: 19 additions & 15 deletions src/components/AddPlayerNames.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import SuperCapsText from '@/components/SuperCapsText';
import CenteredContainer from '@/components/CenteredContainer';
import TabTitle from '@/components/TabTitle';
import { IGame } from '@/game/interfaces/game';
import { deepClone } from '@/game/utils';

interface AddPlayerNamesProps {
nextStep: () => void;
Expand All @@ -37,28 +38,31 @@ const AddPlayerNames: React.FC<AddPlayerNamesProps> = ({ nextStep }) => {
const [currentPlayerIndex, setCurrentPlayerIndex] = useState<number>(-1);

useEffect(() => {
setGameState((prevState: IGame) => ({
...prevState,
numSets: prevState.players.length > 4 ? 2 : 1,
}));
setGameState((prevState: IGame) => {
const newGame = deepClone<IGame>(prevState);
newGame.setsRequired = prevState.players.length > 4 ? 2 : 1;
return newGame;
});
}, [setGameState, gameState.players.length]);

const addPlayer = () => {
if (playerName.trim()) {
const nextPlayerIndex = gameState.players.length; // +1, -1
setGameState((prevState: IGame) => ({
...prevState,
players: [...prevState.players, newPlayer(playerName, nextPlayerIndex)],
}));
setGameState((prevState: IGame) => {
const newGame = deepClone<IGame>(prevState);
newGame.players = [...newGame.players, newPlayer(playerName, nextPlayerIndex)];

Check failure on line 53 in src/components/AddPlayerNames.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/AddPlayerNames.tsx#L53

Unsafe call of an `error` type typed value.
return newGame;
});
setPlayerName('');
}
};

const removePlayer = (index: number) => {
setGameState((prevState: IGame) => ({
...prevState,
players: prevState.players.filter((_, i) => i !== index),
}));
setGameState((prevState: IGame) => {
const newGame = deepClone<IGame>(prevState);
newGame.players = newGame.players.filter((_, i) => i !== index);
return newGame;
});
};

const handleColorClick = (event: React.MouseEvent<HTMLElement>, playerIndex: number) => {
Expand All @@ -69,9 +73,9 @@ const AddPlayerNames: React.FC<AddPlayerNamesProps> = ({ nextStep }) => {
const handleColorChange = (color: ColorResult) => {
if (currentPlayerIndex !== -1) {
setGameState((prevState: IGame) => {
const players = [...prevState.players];
players[currentPlayerIndex].color = color.hex;
return { ...prevState, players };
const newGame = deepClone<IGame>(prevState);
newGame.players[currentPlayerIndex].color = color.hex;
return newGame;
});
}
};
Expand Down
43 changes: 22 additions & 21 deletions src/components/DominionAssistant.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { addLogEntry } from '@/game/dominion-lib-log';
import { useAlert } from '@/components/AlertContext';
import { Location, NavigateFunction } from 'react-router-dom';
import { IGame } from '@/game/interfaces/game';
import { deepClone } from '@/game/utils';

interface DominionAssistantProps {
route: Location;
Expand Down Expand Up @@ -48,55 +49,55 @@ const DominionAssistant: React.FC<DominionAssistantProps> = ({ route, navigation
};

const nextStep = () => {
setGameState((prevState: IGame) => ({
...prevState,
currentStep: StepTransitions[prevState.currentStep] || prevState.currentStep,
}));
setGameState((prevState: IGame) => {

Check failure on line 52 in src/components/DominionAssistant.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/DominionAssistant.tsx#L52

Unsafe call of an `error` type typed value.
const newGame = deepClone<IGame>(prevState);
newGame.currentStep = StepTransitions[prevState.currentStep] || prevState.currentStep;

Check failure on line 54 in src/components/DominionAssistant.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/DominionAssistant.tsx#L54

Unsafe member access .currentStep on an `error` typed value.
return newGame;
});
};

/**
* Start the game with the selected players and options.
*/
const startGame = () => {
// The game initialization is now handled in SetGameOptions
setGameState((prevState: IGame) => ({
...prevState,
currentStep: CurrentStep.GameScreen,
}));
setGameState((prevState: IGame) => {
const newGame = deepClone<IGame>(prevState);
newGame.currentStep = CurrentStep.GameScreen;

Check failure on line 66 in src/components/DominionAssistant.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/DominionAssistant.tsx#L66

Unsafe member access .currentStep on an `error` typed value.
return newGame;
});
};

const nextTurn = () => {
setGameState((prevGame: IGame) => {
const nextPlayerIndex = getNextPlayerIndex(prevGame);
addLogEntry(prevGame, nextPlayerIndex, GameLogAction.NEXT_TURN, {
const newGame = deepClone(prevGame);

Check failure on line 73 in src/components/DominionAssistant.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/DominionAssistant.tsx#L73

Unsafe assignment of an error typed value.
const nextPlayerIndex = getNextPlayerIndex(newGame);

Check failure on line 74 in src/components/DominionAssistant.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/DominionAssistant.tsx#L74

Unsafe call of an `error` type typed value.
addLogEntry(newGame, nextPlayerIndex, GameLogAction.NEXT_TURN, {

Check failure on line 75 in src/components/DominionAssistant.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/DominionAssistant.tsx#L75

Unsafe member access .NEXT_TURN on an `error` typed value.
currentPlayerIndex: nextPlayerIndex,
playerTurnDetails: gameState.players.map((player) => player.turn),
prevPlayerIndex: gameState.currentPlayerIndex,
turn: prevGame.currentTurn + 1,
});
const updatedGame = incrementTurnCountersAndPlayerIndices(prevGame);
return resetPlayerTurnCounters(updatedGame);
return resetPlayerTurnCounters(incrementTurnCountersAndPlayerIndices(newGame));
});
};

const endGame = () => {
setGameState((prevState: IGame) => {
addLogEntry(prevState, NO_PLAYER, GameLogAction.END_GAME, {
const newGame = deepClone<IGame>(prevState);
addLogEntry(newGame, NO_PLAYER, GameLogAction.END_GAME, {

Check failure on line 88 in src/components/DominionAssistant.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/DominionAssistant.tsx#L88

Unsafe call of an `error` type typed value.

Check failure on line 88 in src/components/DominionAssistant.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/DominionAssistant.tsx#L88

Unsafe member access .END_GAME on an `error` typed value.
prevPlayerIndex: gameState.currentPlayerIndex,
});

return {
...prevState,
currentStep: CurrentStep.EndGame,
currentPlayerIndex: NO_PLAYER,
selectedPlayerIndex: NO_PLAYER,
};
newGame.currentStep = CurrentStep.EndGame;
newGame.currentPlayerIndex = NO_PLAYER;
newGame.selectedPlayerIndex = NO_PLAYER;
return newGame;
});
};

const resetGame = () => {
setGameState({
...EmptyGameState,
...EmptyGameState(),
currentStep: CurrentStep.AddPlayerNames,
});
};
Expand Down
4 changes: 3 additions & 1 deletion src/components/GameContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { saveGame } from '@/game/dominion-lib-load-save';
import { IGame } from '@/game/interfaces/game';
import React, { createContext, useContext, useState, ReactNode, useMemo, useEffect } from 'react';
import { LocalStorageService } from '@/game/local-storage-service';
import { deepClone } from '@/game/utils';

// Define the shape of the context
interface GameContextProps {
Expand Down Expand Up @@ -33,7 +34,8 @@ export const GameProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
const storageService = new LocalStorageService();
const saveId = 'autosave';
// the saved game branches from the active game and has the save game entry at the top of the log
const newState = { ...gameState };
// saveGame adds a new entry to the log
const newState = deepClone<IGame>(gameState);

Check failure on line 38 in src/components/GameContext.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/GameContext.tsx#L38

Unsafe assignment of an error typed value.

Check failure on line 38 in src/components/GameContext.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/GameContext.tsx#L38

Unsafe call of an `error` type typed value.
saveGame(newState, 'AutoSave', storageService, saveId);
}, [gameState]);

Expand Down
6 changes: 4 additions & 2 deletions src/components/GameScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { CurrentStep } from '@/game/enumerations/current-step';
import { addLogEntry } from '@/game/dominion-lib-log';
import { NO_PLAYER } from '@/game/constants';
import { GameLogAction } from '@/game/enumerations/game-log-action';
import { IGame } from '@/game/interfaces/game';
import { deepClone } from '@/game/utils';

interface GameScreenProps {
nextTurn: () => void;
Expand Down Expand Up @@ -110,14 +112,14 @@ const GameScreen: React.FC<GameScreenProps> = ({ nextTurn, endGame, undoLastActi
if (lastActionIsPause) {
// Unpause the game
setGameState((prevState) => {
const newState = { ...prevState };
const newState = deepClone<IGame>(prevState);
addLogEntry(newState, NO_PLAYER, GameLogAction.UNPAUSE);
return newState;
});
} else {
// Pause the game
setGameState((prevState) => {
const newState = { ...prevState };
const newState = deepClone<IGame>(prevState);
addLogEntry(newState, NO_PLAYER, GameLogAction.PAUSE);
return newState;
});
Expand Down
9 changes: 5 additions & 4 deletions src/components/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { PlayerFieldMap } from '@/game/types';
import { useAlert } from '@/components/AlertContext';
import '@/styles.scss';
import { IGame } from '@/game/interfaces/game';
import { deepClone } from '@/game/utils';

const StyledPaper = styled(Paper)(({ theme }) => ({
padding: theme.spacing(2),
Expand Down Expand Up @@ -88,7 +89,7 @@ const Player: React.FC = () => {
linkedActionId?: string,
victoryTrash?: boolean
): void => {
const prevGame = { ...gameState };
const prevGame = deepClone<IGame>(gameState);
try {
const updatedGame = updatePlayerField(
prevGame,
Expand Down Expand Up @@ -124,7 +125,7 @@ const Player: React.FC = () => {
incrementSubfield: PlayerFieldMap[T],
increment: number
): void => {
const prevGame = { ...gameState };
const prevGame = deepClone<IGame>(gameState);
try {
// Perform the decrement action
const tempGame = updatePlayerField(
Expand Down Expand Up @@ -195,7 +196,7 @@ const Player: React.FC = () => {
const handleProphecyIncrease = () => {
setGameState((prevState: IGame) => {
if (prevState.risingSun && prevState.options.expansions.risingSun) {
const newGameState = { ...prevState };
const newGameState = deepClone<IGame>(prevState);
// prophecy is always triggered by the selected player, not the current player in case there is an off-turn action triggered by a defense, etc
addLogEntry(newGameState, newGameState.selectedPlayerIndex, GameLogAction.ADD_PROPHECY, {
count: 1,
Expand All @@ -213,7 +214,7 @@ const Player: React.FC = () => {
if (prevState.risingSun.prophecy.suns - 1 < 0) {
return prevState;
}
const newGameState = { ...prevState };
const newGameState = deepClone<IGame>(prevState);
addLogEntry(newGameState, newGameState.selectedPlayerIndex, GameLogAction.REMOVE_PROPHECY, {
count: 1,
});
Expand Down
7 changes: 5 additions & 2 deletions src/components/Scoreboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { useGameContext } from '@/components/GameContext';
import { addLogEntry } from '@/game/dominion-lib-log';
import { GameLogAction } from '@/game/enumerations/game-log-action';
import { IGame } from '@/game/interfaces/game';
import { deepClone } from '@/game/utils';

const TableText = styled(Typography)(() => ({
fontFamily: 'TrajanProBold',
Expand All @@ -45,10 +46,12 @@ const Scoreboard: React.FC = () => {
if (prevState.selectedPlayerIndex === index) {
return prevState;
}
addLogEntry(prevState, index, GameLogAction.SELECT_PLAYER, {
const newGame = deepClone<IGame>(prevState);

Check failure on line 49 in src/components/Scoreboard.tsx

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/components/Scoreboard.tsx#L49

Unsafe assignment of an error typed value.
addLogEntry(newGame, index, GameLogAction.SELECT_PLAYER, {
prevPlayerIndex: prevState.selectedPlayerIndex,
});
return { ...prevState, selectedPlayerIndex: index };
newGame.selectedPlayerIndex = index;
return newGame;
});
};

Expand Down
27 changes: 15 additions & 12 deletions src/components/SelectFirstPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import CenteredContainer from '@/components/CenteredContainer';
import TabTitle from '@/components/TabTitle';
import SuperCapsText from '@/components/SuperCapsText';
import { IGame } from '@/game/interfaces/game';
import { deepClone } from '@/game/utils';

interface SelectFirstPlayerProps {
nextStep: () => void;
Expand All @@ -28,12 +29,13 @@ const SelectFirstPlayer: React.FC<SelectFirstPlayerProps> = ({ nextStep }) => {
const selectRandomFirstPlayer = useCallback(() => {
if (gameState.players.length > 0) {
const randomIndex = Math.floor(Math.random() * gameState.players.length);
setGameState((prevState: IGame) => ({
...prevState,
currentPlayerIndex: randomIndex,
firstPlayerIndex: randomIndex,
selectedPlayerIndex: randomIndex,
}));
setGameState((prevState: IGame) => {
const newGame = deepClone<IGame>(prevState);
newGame.currentPlayerIndex = randomIndex;
newGame.firstPlayerIndex = randomIndex;
newGame.selectedPlayerIndex = randomIndex;
return newGame;
});
}
}, [gameState.players.length, setGameState]);

Expand All @@ -51,12 +53,13 @@ const SelectFirstPlayer: React.FC<SelectFirstPlayerProps> = ({ nextStep }) => {
key={player.name}
selected={gameState.selectedPlayerIndex === index}
onClick={() => {
setGameState((prevState: IGame) => ({
...prevState,
selectedPlayerIndex: index,
currentPlayerIndex: index,
firstPlayerIndex: index,
}));
setGameState((prevState: IGame) => {
const newGame = deepClone<IGame>(prevState);
newGame.selectedPlayerIndex = index;
newGame.currentPlayerIndex = index;
newGame.firstPlayerIndex = index;
return newGame;
});
}}
>
<ListItemIcon>
Expand Down
Loading

0 comments on commit 3ae976e

Please sign in to comment.