From b400e020ee786657fe7f7c4290da8ba4fa575e1e Mon Sep 17 00:00:00 2001 From: Jessica Mulein Date: Sun, 27 Oct 2024 23:03:28 +0000 Subject: [PATCH] 0.6.0: Added turn card gains count tracking --- README.md | 5 +++ src/components/Player.tsx | 28 ++++++++++++- ...n-lib-fieldSubfieldToGameLogAction.spec.ts | 8 ++++ ...-lib-getFieldAndSubfieldFromAction.spec.ts | 2 + .../dominion-lib-log-addLogEntry.spec.ts | 4 +- ...minion-lib-resetPlayerTurnCounters.spec.ts | 41 ++++++++++++++----- ...nion-lib-undo-reconstructGameState.spec.ts | 2 + .../dominion-lib-updatePlayerField.spec.ts | 4 +- src/game/constants.ts | 6 ++- src/game/dominion-lib-log.ts | 2 + src/game/dominion-lib.ts | 3 ++ src/game/enumerations/game-log-action.ts | 2 + .../interfaces/player-game-turn-details.ts | 1 + src/game/types.ts | 2 +- 14 files changed, 92 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 8719d02..6e7b1be 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,11 @@ Join our community of developers. ## Changelog +### Sun Oct 27 16:00:00 2024 + +- Version 0.6.0 + - Added turn card gains count tracking + ### Sun Oct 27 15:35:00 2024 - Version 0.5.0 diff --git a/src/components/Player.tsx b/src/components/Player.tsx index 3daae9c..539e784 100644 --- a/src/components/Player.tsx +++ b/src/components/Player.tsx @@ -46,8 +46,8 @@ const CenteredTitle = styled(Box)({ const CorrectionCheckboxContainer = styled(Box)({ position: 'absolute', - bottom: 10, - left: 30, + bottom: 0, + left: 10, display: 'flex', alignItems: 'center', }); @@ -302,6 +302,7 @@ const Player: React.FC = () => { handleFieldChange('turn', 'actions', 1)} onDecrement={() => { // greatLeaderProphecy gives unlimited actions when the prophecy is empty @@ -319,21 +320,31 @@ const Player: React.FC = () => { handleFieldChange('turn', 'buys', 1)} onDecrement={() => handleFieldChange('turn', 'buys', -1)} /> handleFieldChange('turn', 'coins', 1)} onDecrement={() => handleFieldChange('turn', 'coins', -1)} /> handleFieldChange('turn', 'cards', 1)} onDecrement={() => handleFieldChange('turn', 'cards', -1)} /> + handleFieldChange('turn', 'gains', 1)} + onDecrement={() => handleFieldChange('turn', 'gains', -1)} + /> {(showMats || showGlobalMats) && ( @@ -380,6 +391,7 @@ const Player: React.FC = () => { handleFieldChange('mats', 'debt', 1)} onDecrement={() => handleFieldChange('mats', 'debt', -1)} /> @@ -388,6 +400,7 @@ const Player: React.FC = () => { handleFieldChange('mats', 'favors', 1)} onDecrement={() => handleFieldChange('mats', 'favors', -1)} /> @@ -426,6 +439,7 @@ const Player: React.FC = () => { handleFieldChange('victory', 'curses', 1)} onDecrement={() => handleFieldChange('victory', 'curses', -1)} onTrash={() => handleFieldChange('victory', 'curses', -1, undefined, true)} @@ -434,6 +448,7 @@ const Player: React.FC = () => { handleFieldChange('victory', 'estates', 1)} onDecrement={() => handleFieldChange('victory', 'estates', -1)} onTrash={() => handleFieldChange('victory', 'estates', -1, undefined, true)} @@ -441,6 +456,7 @@ const Player: React.FC = () => { handleFieldChange('victory', 'duchies', 1)} onDecrement={() => handleFieldChange('victory', 'duchies', -1)} onTrash={() => handleFieldChange('victory', 'duchies', -1, undefined, true)} @@ -448,6 +464,7 @@ const Player: React.FC = () => { handleFieldChange('victory', 'provinces', 1)} onDecrement={() => handleFieldChange('victory', 'provinces', -1)} onTrash={() => handleFieldChange('victory', 'provinces', -1, undefined, true)} @@ -456,6 +473,7 @@ const Player: React.FC = () => { handleFieldChange('victory', 'colonies', 1)} onDecrement={() => handleFieldChange('victory', 'colonies', -1)} onTrash={() => handleFieldChange('victory', 'colonies', -1, undefined, true)} @@ -464,12 +482,14 @@ const Player: React.FC = () => { handleFieldChange('victory', 'tokens', 1)} onDecrement={() => handleFieldChange('victory', 'tokens', -1)} /> handleFieldChange('victory', 'other', 1)} onDecrement={() => handleFieldChange('victory', 'other', -1)} /> @@ -496,24 +516,28 @@ const Player: React.FC = () => { handleFieldChange('newTurn', 'actions', 1)} onDecrement={() => handleFieldChange('newTurn', 'actions', -1)} /> handleFieldChange('newTurn', 'buys', 1)} onDecrement={() => handleFieldChange('newTurn', 'buys', -1)} /> handleFieldChange('newTurn', 'coins', 1)} onDecrement={() => handleFieldChange('newTurn', 'coins', -1)} /> handleFieldChange('newTurn', 'cards', 1)} onDecrement={() => handleFieldChange('newTurn', 'cards', -1)} /> diff --git a/src/game/__tests__/dominion-lib-fieldSubfieldToGameLogAction.spec.ts b/src/game/__tests__/dominion-lib-fieldSubfieldToGameLogAction.spec.ts index ce16acf..43ea2a0 100644 --- a/src/game/__tests__/dominion-lib-fieldSubfieldToGameLogAction.spec.ts +++ b/src/game/__tests__/dominion-lib-fieldSubfieldToGameLogAction.spec.ts @@ -36,6 +36,14 @@ describe('victoryFieldToGameLogAction', () => { expect(fieldSubfieldToGameLogAction('turn', 'cards', -1)).toBe(GameLogAction.REMOVE_CARDS); }); + it('should return ADD_GAINS for turn gains increment', () => { + expect(fieldSubfieldToGameLogAction('turn', 'gains', 1)).toBe(GameLogAction.ADD_GAINS); + }); + + it('should return REMOVE_GAINS for turn gains decrement', () => { + expect(fieldSubfieldToGameLogAction('turn', 'gains', -1)).toBe(GameLogAction.REMOVE_GAINS); + }); + it('should return ADD_COFFERS for mats coffers increment', () => { expect(fieldSubfieldToGameLogAction('mats', 'coffers', 1)).toBe(GameLogAction.ADD_COFFERS); }); diff --git a/src/game/__tests__/dominion-lib-getFieldAndSubfieldFromAction.spec.ts b/src/game/__tests__/dominion-lib-getFieldAndSubfieldFromAction.spec.ts index bd9e2eb..d96b8dd 100644 --- a/src/game/__tests__/dominion-lib-getFieldAndSubfieldFromAction.spec.ts +++ b/src/game/__tests__/dominion-lib-getFieldAndSubfieldFromAction.spec.ts @@ -12,6 +12,8 @@ describe('getFieldAndSubfieldFromAction', () => { [GameLogAction.REMOVE_COINS, 'turn', 'coins'], [GameLogAction.ADD_CARDS, 'turn', 'cards'], [GameLogAction.REMOVE_CARDS, 'turn', 'cards'], + [GameLogAction.ADD_GAINS, 'turn', 'gains'], + [GameLogAction.REMOVE_GAINS, 'turn', 'gains'], ])( 'should return correct field and subfield for %s', (action, expectedField, expectedSubfield) => { diff --git a/src/game/__tests__/dominion-lib-log-addLogEntry.spec.ts b/src/game/__tests__/dominion-lib-log-addLogEntry.spec.ts index 4cabd23..79c438b 100644 --- a/src/game/__tests__/dominion-lib-log-addLogEntry.spec.ts +++ b/src/game/__tests__/dominion-lib-log-addLogEntry.spec.ts @@ -78,7 +78,9 @@ describe('addLogEntry', () => { }); it('should add a log entry with player turn details', () => { - const playerTurnDetails = [{ playerIndex: 0, actions: 1, buys: 1, coins: 1, cards: 5 }]; + const playerTurnDetails = [ + { playerIndex: 0, actions: 1, buys: 1, coins: 1, cards: 5, gains: 0 }, + ]; addLogEntry(mockGame, 0, GameLogAction.ADD_COINS, { count: 5, playerTurnDetails, diff --git a/src/game/__tests__/dominion-lib-resetPlayerTurnCounters.spec.ts b/src/game/__tests__/dominion-lib-resetPlayerTurnCounters.spec.ts index 769b366..643e804 100644 --- a/src/game/__tests__/dominion-lib-resetPlayerTurnCounters.spec.ts +++ b/src/game/__tests__/dominion-lib-resetPlayerTurnCounters.spec.ts @@ -55,20 +55,32 @@ describe('resetPlayerTurnCounters', () => { const initialGame = createMockGame([ createMockPlayer( 'Player 1', - { actions: 0, buys: 0, coins: 0, cards: 5 }, - { actions: 1, buys: 1, coins: 0, cards: 5 } + { actions: 0, buys: 0, coins: 0, cards: 5, gains: 0 }, + { actions: 1, buys: 1, coins: 0, cards: 5, gains: 0 } ), createMockPlayer( 'Player 2', - { actions: 2, buys: 1, coins: 3, cards: 5 }, - { actions: 1, buys: 1, coins: 0, cards: 5 } + { actions: 2, buys: 1, coins: 3, cards: 5, gains: 0 }, + { actions: 1, buys: 1, coins: 0, cards: 5, gains: 0 } ), ]); const updatedGame = resetPlayerTurnCounters(initialGame); - expect(updatedGame.players[0].turn).toEqual({ actions: 1, buys: 1, coins: 0, cards: 5 }); - expect(updatedGame.players[1].turn).toEqual({ actions: 1, buys: 1, coins: 0, cards: 5 }); + expect(updatedGame.players[0].turn).toEqual({ + actions: 1, + buys: 1, + coins: 0, + cards: 5, + gains: 0, + }); + expect(updatedGame.players[1].turn).toEqual({ + actions: 1, + buys: 1, + coins: 0, + cards: 5, + gains: 0, + }); }); it('should handle an empty player array', () => { @@ -83,8 +95,8 @@ describe('resetPlayerTurnCounters', () => { const initialGame = createMockGame([ createMockPlayer( 'Player 1', - { actions: 0, buys: 0, coins: 0, cards: 5 }, - { actions: 1, buys: 1, coins: 0, cards: 5 } + { actions: 0, buys: 0, coins: 0, cards: 5, gains: 0 }, + { actions: 1, buys: 1, coins: 0, cards: 5, gains: 0 } ), ]); initialGame.players[0].victory = { ...EmptyVictoryDetails(), estates: 3 }; @@ -111,6 +123,7 @@ describe('resetPlayerTurnCounters', () => { buys: 1, coins: 0, cards: 5, + gains: 0, }); }); @@ -118,8 +131,8 @@ describe('resetPlayerTurnCounters', () => { const initialGame = createMockGame([ createMockPlayer( 'Player 1', - { actions: 0, buys: 0, coins: 0, cards: 5 }, - { actions: 1, buys: 1, coins: 0, cards: 5 } + { actions: 0, buys: 0, coins: 0, cards: 5, gains: 0 }, + { actions: 1, buys: 1, coins: 0, cards: 5, gains: 0 } ), ]); @@ -129,6 +142,12 @@ describe('resetPlayerTurnCounters', () => { expect(updatedGame.players).not.toBe(initialGame.players); expect(updatedGame.players[0]).not.toBe(initialGame.players[0]); expect(updatedGame.players[0].turn).not.toBe(initialGame.players[0].turn); - expect(initialGame.players[0].turn).toEqual({ actions: 0, buys: 0, coins: 0, cards: 5 }); + expect(initialGame.players[0].turn).toEqual({ + actions: 0, + buys: 0, + coins: 0, + cards: 5, + gains: 0, + }); }); }); diff --git a/src/game/__tests__/dominion-lib-undo-reconstructGameState.spec.ts b/src/game/__tests__/dominion-lib-undo-reconstructGameState.spec.ts index 35c73f0..69ed07b 100644 --- a/src/game/__tests__/dominion-lib-undo-reconstructGameState.spec.ts +++ b/src/game/__tests__/dominion-lib-undo-reconstructGameState.spec.ts @@ -347,12 +347,14 @@ describe('reconstructGameState', () => { coins: 0, buys: 2, cards: 5, + gains: 0, }); expect(result.players[1].turn).toStrictEqual({ actions: 1, coins: 3, buys: 1, cards: 5, + gains: 0, }); }); }); diff --git a/src/game/__tests__/dominion-lib-updatePlayerField.spec.ts b/src/game/__tests__/dominion-lib-updatePlayerField.spec.ts index 23cae2e..adfaaed 100644 --- a/src/game/__tests__/dominion-lib-updatePlayerField.spec.ts +++ b/src/game/__tests__/dominion-lib-updatePlayerField.spec.ts @@ -17,8 +17,8 @@ describe('updatePlayerField', () => { name: 'Test Player', color: DefaultPlayerColors[0], mats: { coffers: 0, villagers: 0, debt: 0, favors: 0 }, - turn: { actions: 1, buys: 1, coins: 0, cards: 5 }, - newTurn: { actions: 1, buys: 1, coins: 0, cards: 5 }, + turn: { actions: 1, buys: 1, coins: 0, cards: 5, gains: 0 }, + newTurn: { actions: 1, buys: 1, coins: 0, cards: 5, gains: 0 }, victory: { estates: 3, duchies: 0, diff --git a/src/game/constants.ts b/src/game/constants.ts index 1f5fc0f..bc4e520 100644 --- a/src/game/constants.ts +++ b/src/game/constants.ts @@ -8,7 +8,7 @@ import { IMatsEnabled } from '@/game/interfaces/mats-enabled'; import { IGameOptions } from '@/game/interfaces/game-options'; import { deepClone } from '@/game/utils'; -export const VERSION_NUMBER = '0.5.0'; +export const VERSION_NUMBER = '0.6.0'; export const MIN_PLAYERS = 2; export const MAX_PLAYERS = 6; @@ -107,6 +107,7 @@ export function DefaultTurnDetails(): IPlayerGameTurnDetails { buys: 1, coins: 0, cards: 5, + gains: 0, }); } @@ -146,6 +147,8 @@ export const AdjustmentActions = [ GameLogAction.REMOVE_BUYS, GameLogAction.ADD_CARDS, GameLogAction.REMOVE_CARDS, + GameLogAction.ADD_GAINS, + GameLogAction.REMOVE_GAINS, // mats GameLogAction.ADD_COFFERS, GameLogAction.REMOVE_COFFERS, @@ -190,6 +193,7 @@ export const NegativeAdjustmentActions = [ GameLogAction.REMOVE_COINS, GameLogAction.REMOVE_BUYS, GameLogAction.REMOVE_CARDS, + GameLogAction.REMOVE_GAINS, // mats GameLogAction.REMOVE_COFFERS, GameLogAction.REMOVE_VILLAGERS, diff --git a/src/game/dominion-lib-log.ts b/src/game/dominion-lib-log.ts index 04df922..7c0facd 100644 --- a/src/game/dominion-lib-log.ts +++ b/src/game/dominion-lib-log.ts @@ -38,6 +38,8 @@ export function fieldSubfieldToGameLogAction( return increment > 0 ? GameLogAction.ADD_COINS : GameLogAction.REMOVE_COINS; case 'cards': return increment > 0 ? GameLogAction.ADD_CARDS : GameLogAction.REMOVE_CARDS; + case 'gains': + return increment > 0 ? GameLogAction.ADD_GAINS : GameLogAction.REMOVE_GAINS; default: throw new InvalidFieldError(field as string, subfield as string); } diff --git a/src/game/dominion-lib.ts b/src/game/dominion-lib.ts index 9e17350..42b7c0e 100644 --- a/src/game/dominion-lib.ts +++ b/src/game/dominion-lib.ts @@ -296,6 +296,9 @@ export function getFieldAndSubfieldFromAction(action: GameLogAction): { case GameLogAction.ADD_CARDS: case GameLogAction.REMOVE_CARDS: return { field: 'turn', subfield: 'cards' }; + case GameLogAction.ADD_GAINS: + case GameLogAction.REMOVE_GAINS: + return { field: 'turn', subfield: 'gains' }; case GameLogAction.ADD_COFFERS: case GameLogAction.REMOVE_COFFERS: return { field: 'mats', subfield: 'coffers' }; diff --git a/src/game/enumerations/game-log-action.ts b/src/game/enumerations/game-log-action.ts index ba6fecb..7604168 100644 --- a/src/game/enumerations/game-log-action.ts +++ b/src/game/enumerations/game-log-action.ts @@ -15,6 +15,8 @@ export enum GameLogAction { REMOVE_COINS = 'Removed {COUNT} Coins', ADD_CARDS = 'Added {COUNT} Cards', REMOVE_CARDS = 'Removed {COUNT} Cards', + ADD_GAINS = 'Added {COUNT} Gains', + REMOVE_GAINS = 'Removed {COUNT} Gains', ADD_COFFERS = 'Added {COUNT} Coffers', REMOVE_COFFERS = 'Removed {COUNT} Coffers', ADD_VILLAGERS = 'Added {COUNT} Villagers', diff --git a/src/game/interfaces/player-game-turn-details.ts b/src/game/interfaces/player-game-turn-details.ts index 3f41877..79a5178 100644 --- a/src/game/interfaces/player-game-turn-details.ts +++ b/src/game/interfaces/player-game-turn-details.ts @@ -3,4 +3,5 @@ export interface IPlayerGameTurnDetails { buys: number; coins: number; cards: number; + gains: number; } diff --git a/src/game/types.ts b/src/game/types.ts index aaf50d6..751a606 100644 --- a/src/game/types.ts +++ b/src/game/types.ts @@ -1,7 +1,7 @@ import { IGameOptions } from '@/game/interfaces/game-options'; import { IPlayer } from '@/game/interfaces/player'; -export type TurnField = 'actions' | 'buys' | 'coins' | 'cards'; +export type TurnField = 'actions' | 'buys' | 'coins' | 'cards' | 'gains'; export type VictoryField = | 'curses' | 'estates'