Sample game made on Discoteque engine https://deiru.moe/disco/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

121 lines
3.9 KiB

import * as R from 'ramda';
import { createStore, Action, Dispatch } from 'redux';
import { ILine } from 'discoteque/lib/engine/types';
import { Task } from '@/components/Tasks';
import { toast } from 'discoteque/lib/engine/lib/utils';
import { setShowCustom } from 'discoteque/lib/engine/lib/store';
export interface IGameState {
visitedLeft: number;
askedAboutChoice: boolean;
visitedRight: number;
beenOutside: boolean;
beenInside: boolean;
haveTalkedToHelper: boolean;
lookedAtTrapdoor: boolean;
talkedAboutTrapdoor: boolean;
readMailbox: boolean;
ui: { menuTab: string }
db: {
characters: string[],
tasks: Task[],
}
backlog: ILine<IGameState>[];
}
export interface IGameStateAction extends Action {
type: 'INIT' | 'PATCH-GAME' | 'INIT-GAME' | 'RESET-GAME' | 'SET-TASK' | 'ADD-KNOWN-CHARACTER' | 'SET-MENU-TAB';
state?: IGameState;
tab?: string;
task?: {
id: string;
data: Partial<Task>;
}
character?: string;
}
export const setState = (state: object): IGameStateAction => ({ type: 'PATCH-GAME', state: (state as IGameState) });
export const initState = (state: IGameState): IGameStateAction => ({ type: 'INIT-GAME', state });
export const resetState = (): IGameStateAction => ({ type: 'RESET-GAME' })
export const setMenuTab = (tab: string): IGameStateAction => ({ type: 'SET-MENU-TAB', tab });
export const setTask = (id: string, data: Partial<Task>) => (dispatch: Dispatch): IGameStateAction => {
toast.info("Task list updated", { onClick: () => {
dispatch(setMenuTab('tasks'));
dispatch(setShowCustom(true));
} });
return {
type: 'SET-TASK', task: { id, data },
};
};
export const addKnownCharacter = (character: string) => (dispatch: Dispatch): IGameStateAction => {
toast.info("Character database updated", { onClick: () => {
dispatch(setMenuTab('characters'));
dispatch(setShowCustom(true));
} });
return {
type: 'ADD-KNOWN-CHARACTER', character,
};
};
const defaultState: IGameState = {
visitedLeft: 0,
visitedRight: 0,
askedAboutChoice: false,
beenOutside: false,
beenInside: false,
haveTalkedToHelper: false,
lookedAtTrapdoor: false,
talkedAboutTrapdoor: false,
readMailbox: false,
ui: { menuTab: 'skills' },
db: {
characters: [],
tasks: [{ id: 'trapdoor', stages: [0], stagesComplete: [] }],
},
backlog: [],
};
export const reducer = (state: IGameState = defaultState, action: IGameStateAction): IGameState => {
switch (action.type) {
case 'PATCH-GAME':
return ({ ...state, ...action.state });
case 'INIT-GAME':
return action.state || state;
case 'INIT':
return (action as any).data.gameState || state;
case 'RESET-GAME':
return defaultState;
case 'SET-TASK':
if (action.task) {
const newTasks = [
R.mergeDeepRight<Partial<Task>, Partial<Task>>(
state.db.tasks.find(task => task.id === action.task?.id) || { id: action.task.id },
action.task.data,
),
...state.db.tasks.filter(task => task.id !== action.task?.id),
] as Task[];
const statePatch: Partial<IGameState> = { db: { ...state.db, tasks: newTasks } };
return R.mergeDeepRight<IGameState, Partial<IGameState>>(
state,
statePatch,
) as IGameState;
}
case 'ADD-KNOWN-CHARACTER':
return R.mergeDeepRight(state, {
db: { characters: [ ...state.db.characters, action.character ].filter(R.identity) }
}) as IGameState;
case 'SET-MENU-TAB':
if (action.tab) {
return R.mergeDeepRight(state, {
ui: { menuTab: action.tab }
});
}
}
return state;
}
export const stateSelector: (state: object) => IGameState = R.propOr(defaultState, 'game');
export const menuTabSelector: (state: object) => string = R.pathOr(defaultState.ui.menuTab, ['game', 'ui', 'menuTab']);
export default createStore(reducer);