2024-05-11 22:38:07 +00:00
|
|
|
import { createContext } from 'react';
|
|
|
|
import { createStore, StateCreator } from 'zustand';
|
|
|
|
|
|
|
|
import { doesExist, Maybe } from '@apextoaster/js-utils';
|
|
|
|
import { PaletteMode } from '@mui/material';
|
|
|
|
import { ReadyState } from 'react-use-websocket';
|
|
|
|
import { Actor, GameEvent, Item, Room, World } from './models';
|
|
|
|
|
2024-05-19 00:46:56 +00:00
|
|
|
export type LayoutMode = 'horizontal' | 'vertical';
|
|
|
|
|
2024-05-11 22:38:07 +00:00
|
|
|
export interface ClientState {
|
|
|
|
autoScroll: boolean;
|
|
|
|
clientId: string;
|
|
|
|
clientName: string;
|
2024-05-12 20:47:18 +00:00
|
|
|
detailEntity: Maybe<Item | Actor | Room | World>;
|
2024-05-11 22:38:07 +00:00
|
|
|
eventHistory: Array<GameEvent>;
|
2024-05-19 00:46:56 +00:00
|
|
|
layoutMode: LayoutMode;
|
2024-05-11 22:38:07 +00:00
|
|
|
readyState: ReadyState;
|
|
|
|
themeMode: PaletteMode;
|
|
|
|
|
|
|
|
// setters
|
|
|
|
setAutoScroll: (autoScroll: boolean) => void;
|
|
|
|
setClientId: (clientId: string) => void;
|
|
|
|
setClientName: (name: string) => void;
|
2024-05-12 20:47:18 +00:00
|
|
|
setDetailEntity: (entity: Maybe<Item | Actor | Room | World>) => void;
|
2024-05-19 00:46:56 +00:00
|
|
|
setLayoutMode: (mode: LayoutMode) => void;
|
2024-05-11 22:38:07 +00:00
|
|
|
setReadyState: (state: ReadyState) => void;
|
|
|
|
setThemeMode: (mode: PaletteMode) => void;
|
|
|
|
|
|
|
|
// misc helpers
|
|
|
|
appendEvent: (event: GameEvent) => void;
|
|
|
|
clearDetailEntity: () => void;
|
|
|
|
clearEventHistory: () => void;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface WorldState {
|
|
|
|
players: Record<string, string>;
|
|
|
|
world: Maybe<World>;
|
|
|
|
|
|
|
|
// setters
|
|
|
|
setPlayers: (players: Record<string, string>) => void;
|
|
|
|
setWorld: (world: Maybe<World>) => void;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface PlayerState {
|
|
|
|
activeTurn: boolean;
|
|
|
|
character: Maybe<Actor>;
|
|
|
|
|
|
|
|
// setters
|
|
|
|
setActiveTurn: (activeTurn: boolean) => void;
|
|
|
|
setCharacter: (character: Maybe<Actor>) => void;
|
|
|
|
|
|
|
|
// misc helpers
|
|
|
|
isPlaying: () => boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
export type StoreState = ClientState & WorldState & PlayerState;
|
|
|
|
|
|
|
|
export function createClientStore(): StateCreator<ClientState> {
|
|
|
|
return (set) => ({
|
|
|
|
autoScroll: true,
|
|
|
|
clientId: '',
|
|
|
|
clientName: '',
|
|
|
|
detailEntity: undefined,
|
|
|
|
eventHistory: [],
|
2024-05-19 00:46:56 +00:00
|
|
|
layoutMode: 'horizontal',
|
2024-05-11 22:38:07 +00:00
|
|
|
readyState: ReadyState.UNINSTANTIATED,
|
|
|
|
themeMode: 'light',
|
|
|
|
setAutoScroll(autoScroll) {
|
|
|
|
set({ autoScroll });
|
|
|
|
},
|
|
|
|
setClientId(clientId) {
|
|
|
|
set({ clientId });
|
|
|
|
},
|
|
|
|
setClientName(clientName) {
|
|
|
|
set({ clientName });
|
|
|
|
},
|
|
|
|
setDetailEntity(detailEntity) {
|
|
|
|
set({ detailEntity });
|
|
|
|
},
|
2024-05-19 00:46:56 +00:00
|
|
|
setLayoutMode(mode) {
|
|
|
|
set({ layoutMode: mode });
|
|
|
|
},
|
2024-05-11 22:38:07 +00:00
|
|
|
setReadyState(state) {
|
|
|
|
set({ readyState: state });
|
|
|
|
},
|
|
|
|
setThemeMode(themeMode) {
|
|
|
|
set({ themeMode });
|
|
|
|
},
|
|
|
|
appendEvent(event) {
|
|
|
|
set((state) => {
|
|
|
|
const history = state.eventHistory.concat(event);
|
|
|
|
return { eventHistory: history };
|
|
|
|
});
|
|
|
|
},
|
|
|
|
clearDetailEntity() {
|
|
|
|
set({ detailEntity: undefined });
|
|
|
|
},
|
|
|
|
clearEventHistory() {
|
|
|
|
set({ eventHistory: [] });
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function createWorldStore(): StateCreator<WorldState> {
|
|
|
|
return (set) => ({
|
|
|
|
players: {},
|
|
|
|
world: undefined,
|
|
|
|
setPlayers: (players) => set({ players }),
|
|
|
|
setWorld: (world) => set({ world }),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function createPlayerStore(): StateCreator<PlayerState> {
|
|
|
|
return (set) => ({
|
|
|
|
activeTurn: false,
|
|
|
|
character: undefined,
|
|
|
|
setActiveTurn: (activeTurn: boolean) => set({ activeTurn }),
|
|
|
|
setCharacter: (character: Maybe<Actor>) => set({ character }),
|
|
|
|
isPlaying() {
|
|
|
|
return doesExist(this.character);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function createStateStore() {
|
|
|
|
return createStore<StoreState>((...args) => ({
|
|
|
|
...createClientStore()(...args),
|
|
|
|
...createWorldStore()(...args),
|
|
|
|
...createPlayerStore()(...args),
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: make this not global
|
|
|
|
export const store = createStateStore();
|
|
|
|
export const storeContext = createContext(store);
|