|
|
|
@ -1,4 +1,12 @@ |
|
|
|
|
import { ErrorType, EventResult, IncomingEvent, IncomingEventType, OutgoingEventType } from './gameEvent' |
|
|
|
|
import { |
|
|
|
|
ErrorType, |
|
|
|
|
EventResult, |
|
|
|
|
EventResultClass, |
|
|
|
|
IncomingEvent, |
|
|
|
|
IncomingEventType, |
|
|
|
|
OutgoingEvent, |
|
|
|
|
OutgoingEventType, |
|
|
|
|
} from './gameEvent' |
|
|
|
|
import { GamePhase, GameState, oppositePlayer, PlayerSide, PlayerState, RoundStarter } from './gameState' |
|
|
|
|
import { |
|
|
|
|
DieFace, |
|
|
|
@ -41,7 +49,7 @@ export function handleEvent(state: GameState, event: IncomingEvent): EventResult |
|
|
|
|
return handleAbortEvent<GameState>(state, event) |
|
|
|
|
default: |
|
|
|
|
return { |
|
|
|
|
newState: state, |
|
|
|
|
type: EventResultClass.FAILURE, |
|
|
|
|
error: { |
|
|
|
|
type: ErrorType.UnexpectedError, |
|
|
|
|
message: 'Event type not yet implemented', |
|
|
|
@ -50,7 +58,7 @@ export function handleEvent(state: GameState, event: IncomingEvent): EventResult |
|
|
|
|
} |
|
|
|
|
} catch (e) { |
|
|
|
|
return { |
|
|
|
|
newState: state, |
|
|
|
|
type: EventResultClass.FAILURE, |
|
|
|
|
error: { |
|
|
|
|
type: ErrorType.UnexpectedError, |
|
|
|
|
message: `Failed handling event: ${e}`, |
|
|
|
@ -73,23 +81,24 @@ export function handleSelectActionEvent<T extends SelectActionState<unknown>>( |
|
|
|
|
): EventResult<T> { |
|
|
|
|
if (state.gamePhase !== GamePhase.ROUND_START) { |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.FAILURE, |
|
|
|
|
error: { |
|
|
|
|
type: ErrorType.NotValidRightNow, |
|
|
|
|
message: `You can only change actions when the turn has not started yet.`, |
|
|
|
|
}, |
|
|
|
|
newState: state, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (index < 0 || index >= state.theme.actions.length || index !== Math.floor(index)) { |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.FAILURE, |
|
|
|
|
error: { |
|
|
|
|
type: ErrorType.InvalidIndex, |
|
|
|
|
message: `Select an integer action index between 0 (inclusive) and ${state.theme.actions.length} (exclusive)`, |
|
|
|
|
}, |
|
|
|
|
newState: state, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.SUCCESS, |
|
|
|
|
newState: { |
|
|
|
|
...state, |
|
|
|
|
action: state.theme.actions[index], |
|
|
|
@ -109,16 +118,16 @@ export function handleToggleSelectIndexEvent<D extends { readonly state: DieStat |
|
|
|
|
): EventResult<T> { |
|
|
|
|
if (state.gamePhase !== GamePhase.TURN_ROLLED) { |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.FAILURE, |
|
|
|
|
error: { |
|
|
|
|
type: ErrorType.NotValidRightNow, |
|
|
|
|
message: `You can only toggle the selected state of a die when dice have been rolled.`, |
|
|
|
|
}, |
|
|
|
|
newState: state, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!isValidIndex(index, state.lastRoll.length)) { |
|
|
|
|
return { |
|
|
|
|
newState: state, |
|
|
|
|
type: EventResultClass.FAILURE, |
|
|
|
|
error: { |
|
|
|
|
type: ErrorType.InvalidIndex, |
|
|
|
|
message: `Select an integer action index between 0 (inclusive) and ${state.lastRoll.length} (exclusive)`, |
|
|
|
@ -126,6 +135,7 @@ export function handleToggleSelectIndexEvent<D extends { readonly state: DieStat |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.SUCCESS, |
|
|
|
|
newState: { |
|
|
|
|
...state, |
|
|
|
|
lastRoll: [ |
|
|
|
@ -147,14 +157,15 @@ function handleSelectAllEvent<D extends { readonly state: DieState }, T extends |
|
|
|
|
): EventResult<T> { |
|
|
|
|
if (state.gamePhase !== GamePhase.TURN_ROLLED) { |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.FAILURE, |
|
|
|
|
error: { |
|
|
|
|
type: ErrorType.NotValidRightNow, |
|
|
|
|
message: `You can only change the selected state of the dice when dice have been rolled.`, |
|
|
|
|
}, |
|
|
|
|
newState: state, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.SUCCESS, |
|
|
|
|
newState: { |
|
|
|
|
...state, |
|
|
|
|
lastRoll: state.lastRoll.map<D>((x) => ({ |
|
|
|
@ -172,14 +183,15 @@ function handleHoldDiceEvent<D extends { readonly state: DieState }, T extends D |
|
|
|
|
): EventResult<T> { |
|
|
|
|
if (state.gamePhase !== GamePhase.TURN_ROLLED) { |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.FAILURE, |
|
|
|
|
error: { |
|
|
|
|
type: ErrorType.NotValidRightNow, |
|
|
|
|
message: `You can only toggle the hold state of dice when dice have been rolled.`, |
|
|
|
|
}, |
|
|
|
|
newState: state, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.SUCCESS, |
|
|
|
|
newState: { |
|
|
|
|
...state, |
|
|
|
|
lastRoll: state.lastRoll.map<D>((v) => { |
|
|
|
@ -249,11 +261,11 @@ export interface EndTurnState<P extends EndTurnPlayer> { |
|
|
|
|
function handleEndTurnEvent<P extends EndTurnPlayer, T extends EndTurnState<P>>(state: T): EventResult<T> { |
|
|
|
|
if (state.gamePhase !== GamePhase.TURN_ROLLED && state.gamePhase !== GamePhase.TURN_FAILED) { |
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.FAILURE, |
|
|
|
|
error: { |
|
|
|
|
type: ErrorType.NotValidRightNow, |
|
|
|
|
message: `You can only end your turn when it's in progress.`, |
|
|
|
|
}, |
|
|
|
|
newState: state, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
const failed = state.gamePhase === GamePhase.TURN_FAILED || !state.currentDiceEndTurn |
|
|
|
@ -262,6 +274,7 @@ function handleEndTurnEvent<P extends EndTurnPlayer, T extends EndTurnState<P>>( |
|
|
|
|
// The winner of this round has not yet been decided; this is better than the last turn this round.
|
|
|
|
|
// Moving on to the next turn...
|
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.SUCCESS, |
|
|
|
|
newState: { |
|
|
|
|
...state, |
|
|
|
|
lastTurnTotal: state.currentTurnTotal, |
|
|
|
@ -324,7 +337,12 @@ function handleEndTurnEvent<P extends EndTurnPlayer, T extends EndTurnState<P>>( |
|
|
|
|
newPhase === GamePhase.VICTORY |
|
|
|
|
? oppositePlayer(state.phaseOwner) |
|
|
|
|
: determineNextRoundStarter(state, state.difficulty) |
|
|
|
|
const events: OutgoingEvent[] = [] |
|
|
|
|
const endRoundEvent = |
|
|
|
|
state.gamePhase === GamePhase.TURN_FAILED ? OutgoingEventType.FailTurn : OutgoingEventType.AbandonTurn |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
type: EventResultClass.SUCCESS, |
|
|
|
|
newState: { |
|
|
|
|
...state, |
|
|
|
|
players, |
|
|
|
@ -338,7 +356,24 @@ function handleEndTurnEvent<P extends EndTurnPlayer, T extends EndTurnState<P>>( |
|
|
|
|
countedFails: 0, |
|
|
|
|
selectedDiceValue: 0, |
|
|
|
|
}, |
|
|
|
|
events: [], |
|
|
|
|
events: [ |
|
|
|
|
{ |
|
|
|
|
type: OutgoingEventType.PassTurn, |
|
|
|
|
target: state.phaseOwner, |
|
|
|
|
}, |
|
|
|
|
...(newPhase === GamePhase.VICTORY |
|
|
|
|
? [] |
|
|
|
|
: [ |
|
|
|
|
{ |
|
|
|
|
type: endRoundEvent, |
|
|
|
|
target: state.phaseOwner, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
type: OutgoingEventType.StartRound, |
|
|
|
|
target: newRoundOwner, |
|
|
|
|
}, |
|
|
|
|
]), |
|
|
|
|
], |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|