Add events both incoming and outgoing

main
Mari 2 years ago
parent 05c4bae65d
commit fcf2b8a463
  1. 29
      .idea/workspace.xml
  2. 2
      src/state/gameData.spec.ts
  3. 27
      src/state/gameData.ts
  4. 168
      src/state/gameEvent.ts

@ -4,9 +4,11 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="84c57704-c34b-42d3-90dc-bc3746b4a30c" name="Changes" comment=""> <list default="true" id="84c57704-c34b-42d3-90dc-bc3746b4a30c" name="Changes" comment="Steppies project start">
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/state/gameEvent.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/state/gamestate.spec.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/state/gameData.spec.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/state/gamestate.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/state/gameData.ts" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -51,7 +53,7 @@
"nodejs_package_manager_path": "npm", "nodejs_package_manager_path": "npm",
"prettierjs.PrettierConfiguration.Package": "/home/reya/WebstormProjects/steppies/node_modules/prettier", "prettierjs.PrettierConfiguration.Package": "/home/reya/WebstormProjects/steppies/node_modules/prettier",
"settings.editor.selected.configurable": "configurable.group.appearance", "settings.editor.selected.configurable": "configurable.group.appearance",
"ts.external.directory.path": "/opt/WebStorm/plugins/JavaScriptLanguage/jsLanguageServicesImpl/external", "ts.external.directory.path": "/home/reya/WebstormProjects/steppies/node_modules/typescript/lib",
"vue.rearranger.settings.migration": "true" "vue.rearranger.settings.migration": "true"
} }
}]]></component> }]]></component>
@ -92,8 +94,23 @@
<option name="number" value="Default" /> <option name="number" value="Default" />
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1669828165304</updated> <updated>1669828165304</updated>
<workItem from="1669828166439" duration="20904000" /> <workItem from="1669828166439" duration="32122000" />
</task> </task>
<task id="LOCAL-00001" summary="Steppies project start">
<created>1669853979470</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1669853979470</updated>
</task>
<task id="LOCAL-00002" summary="Steppies project start">
<created>1669854047768</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1669854047768</updated>
</task>
<option name="localTasksCounter" value="3" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@ -110,6 +127,10 @@
</map> </map>
</option> </option>
</component> </component>
<component name="VcsManagerConfiguration">
<MESSAGE value="Steppies project start" />
<option name="LAST_COMMIT_MESSAGE" value="Steppies project start" />
</component>
<component name="com.intellij.coverage.CoverageDataManagerImpl"> <component name="com.intellij.coverage.CoverageDataManagerImpl">
<SUITE FILE_PATH="coverage/steppies$All_Tests.info" NAME="All Tests Coverage Results" MODIFIED="1669853649183" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="JestJavaScriptTestRunnerCoverage" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" /> <SUITE FILE_PATH="coverage/steppies$All_Tests.info" NAME="All Tests Coverage Results" MODIFIED="1669853649183" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="JestJavaScriptTestRunnerCoverage" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" />
</component> </component>

@ -1,5 +1,5 @@
import { describe, expect, test } from '@jest/globals' import { describe, expect, test } from '@jest/globals'
import { DieState, isHeldState, isSelectedState, setDeselected, setSelected, toggleSelected } from './gamestate' import { DieState, isHeldState, isSelectedState, setDeselected, setSelected, toggleSelected } from './gameData'
describe('isHeldState', () => { describe('isHeldState', () => {
test.each<[DieState, boolean]>([ test.each<[DieState, boolean]>([

@ -200,6 +200,7 @@ export interface GameTheme {
readonly difficulties: readonly Difficulty[] readonly difficulties: readonly Difficulty[]
readonly narratorName: string
readonly topText: PlayerText readonly topText: PlayerText
readonly bottomText: PlayerText readonly bottomText: PlayerText
} }
@ -296,9 +297,18 @@ export interface PlayerState {
readonly timesRecovered: number readonly timesRecovered: number
} }
export interface GameState { export enum GameState {
// The version of the serialization format this state was saved with. ONGOING = 'ongoing',
ABORTED = 'aborted',
TOP_WINS = 'top_wins',
BOTTOM_WINS = 'bottom_wins',
}
export interface GameData {
// The version of the serialization format this data was saved with.
readonly version: number readonly version: number
// Whether the game is still ongoing, or if not, who won (if anyone).
readonly gameState: GameState
// The state of the top player // The state of the top player
readonly top: PlayerState readonly top: PlayerState
@ -310,21 +320,18 @@ export interface GameState {
// The difficulty selected for this game. // The difficulty selected for this game.
readonly difficulty: Difficulty readonly difficulty: Difficulty
// Null if the top is a computer. // If true, the top chose/is choosing the action this round.
readonly topHumanId: string | null
// Null if the bottom is a computer.
readonly bottomHumanId: string | null
// If true, the top is choosing the action this round.
readonly isTopRound: boolean readonly isTopRound: boolean
// The action chosen for this round, or null if the current player is choosing an action // The action chosen for this round, or null if the current player has not chosen an action yet.
// The action is locked in if lastRoll is not null or lastTurnTotal is not 0.
readonly action: GameAction | null readonly action: GameAction | null
// If true, the top is rolling this turn. // If true, the top is rolling this turn.
readonly isTopTurn: boolean readonly isTopTurn: boolean
// The total for the previous turn, or 0 if the current player is taking the first turn // The total for the previous turn, or 0 if the current player is taking the first turn
// If the current player fails when the turn total is 0, they take the penalty and pass the initiative without taking damage. // If the current player fails when the turn total is 0, they take the penalty and pass the initiative without taking damage.
// This can still end the game if the current action is capable of ending the game for this player. // This can still end the game if the current action is capable of ending the game for this player and
// this player has more damage than their maximum.
readonly lastTurnTotal: number readonly lastTurnTotal: number
// The dice available for the current turn, or null if the current player has not rolled yet this turn. // The dice available for the current turn, or null if the current player has not rolled yet this turn.
readonly lastRoll: readonly DieResult[] | null readonly lastRoll: readonly DieResult[] | null

@ -0,0 +1,168 @@
import { DieResult, GameData } from './gameData'
export enum IncomingEventType {
// Chooses the action to be performed for this round but does not lock it in until the player rolls.
SelectAction = 'select_action',
// Dice buttons toggle the selection of that die
ToggleSelectDie = 'toggle_select_die',
// Button 1 is Select All/Deselect All
// Select All appears if no dice are selected
// Deselect All displays if at least one die is selected
SelectAllDice = 'select_all_dice',
DeselectAllDice = 'deselect_all_dice',
// Button 2 is Hold/Release selected dice
// If only held dice are selected, Release appears
// For selections with at least one unheld die, Hold appears
HoldSelectedDice = 'hold_selected_dice',
ReleaseSelectedDice = 'release_selected_dice',
// Button 3 is End Turn/Score Selected Dice
// End Turn appears if at least one Stop die is selected, but is only enabled if sufficient Stop dice are selected
// and no non-Stop dice are selected
// Score Selected Dice appears otherwise, but is only enabled if at least one scoreable die is selected and no
// non-scoreable dice are selected
EndTurn = 'end_turn',
ScoreSelectedDice = 'score_selected_dice',
// Button 4 is Roll Dice
// It's always visible, but is disabled if there are no unheld dice
RollDice = 'roll_dice',
}
export interface IncomingBaseEvent {
// The type of event to execute.
readonly type: IncomingEventType
}
export interface IncomingIndexedEvent extends IncomingBaseEvent {
readonly type: IncomingEventType.SelectAction | IncomingEventType.ToggleSelectDie
readonly index: number
}
export interface IncomingSimpleEvent extends IncomingBaseEvent {
readonly type:
| IncomingEventType.SelectAllDice
| IncomingEventType.HoldSelectedDice
| IncomingEventType.ReleaseSelectedDice
| IncomingEventType.ScoreSelectedDice
| IncomingEventType.EndTurn
| IncomingEventType.DeselectAllDice
| IncomingEventType.RollDice
}
export type IncomingEvent = IncomingIndexedEvent | IncomingSimpleEvent
export enum ErrorType {
NotValidRightNow = 'not_valid_right_now',
InvalidIndex = 'invalid_index',
InsufficientMatchingDice = 'insufficient_matching_dice',
DataLoadFailed = 'data_load_failed',
UnexpectedError = 'unexpected_error',
}
export interface GameError {
readonly type: ErrorType
readonly message: string
}
export enum OutgoingEventType {
Dialogue = 'dialogue',
Description = 'description',
DamageOrRecovery = 'damage',
ChangeStops = 'change_stops',
ChangeFails = 'change_fails',
ChangeDamageBonus = 'change_damage_bonus',
ScoreDice = 'score_dice',
GainFailures = 'gain_failures',
LoseRound = 'lose_round',
LoseGame = 'lose_game',
StartRoll = 'new_roll',
StartTurn = 'new_turn',
StartRound = 'new_round',
}
export enum EventTarget {
Top = 'top',
Bottom = 'bottom',
}
export enum TextSender {
Top = 'top',
Bottom = 'bottom',
Narrator = 'narrator',
}
export interface OutgoingBaseEvent {
readonly type: OutgoingEventType
}
export interface OutgoingTextEvent extends OutgoingBaseEvent {
readonly type: OutgoingEventType.Description | OutgoingEventType.Dialogue
readonly sender: TextSender
readonly text: string
}
export interface OutgoingBaseTargetedEvent extends OutgoingBaseEvent {
readonly type:
| OutgoingEventType.DamageOrRecovery
| OutgoingEventType.ChangeStops
| OutgoingEventType.ChangeFails
| OutgoingEventType.ChangeDamageBonus
| OutgoingEventType.LoseRound
| OutgoingEventType.LoseGame
| OutgoingEventType.ScoreDice
| OutgoingEventType.GainFailures
| OutgoingEventType.StartRoll
| OutgoingEventType.StartTurn
| OutgoingEventType.StartRound
readonly target: EventTarget
}
export interface OutgoingSimpleTargetedEvent extends OutgoingBaseTargetedEvent {
readonly type: OutgoingEventType.LoseGame | OutgoingEventType.StartTurn | OutgoingEventType.StartRound
}
export interface OutgoingDamageEvent extends OutgoingBaseTargetedEvent {
readonly type:
| OutgoingEventType.DamageOrRecovery
| OutgoingEventType.ChangeStops
| OutgoingEventType.ChangeFails
| OutgoingEventType.ChangeDamageBonus
| OutgoingEventType.LoseRound
| OutgoingEventType.GainFailures
readonly delta: number
}
export interface OutgoingStartRollEvent extends OutgoingBaseTargetedEvent {
readonly type: OutgoingEventType.StartRoll
readonly newDice: DieResult[]
}
export interface OutgoingScoreDiceEvent extends OutgoingBaseTargetedEvent {
readonly type: OutgoingEventType.ScoreDice
readonly scoredDice: DieResult[]
readonly scoreDelta: number
}
export type OutgoingEvent =
| OutgoingTextEvent
| OutgoingSimpleTargetedEvent
| OutgoingDamageEvent
| OutgoingStartRollEvent
| OutgoingScoreDiceEvent
export interface BaseEventResult {
readonly newState: GameData
}
export interface SuccessResult extends BaseEventResult {
readonly events: OutgoingEvent[]
}
export interface FailedResult extends BaseEventResult {
readonly error: GameError
}
export type EventResult = SuccessResult | FailedResult
Loading…
Cancel
Save