Browse Source

feat: Switch to a new major version of Discoteque

develop
Dale 1 year ago
parent
commit
cdda841cf4
Signed by: Deiru GPG Key ID: AA250C0277B927E1
  1. 4
      package.json
  2. BIN
      src/assets/antic-slab-regular.woff2
  3. 7
      src/components/Characters/index.tsx
  4. 22
      src/components/Menu/index.tsx
  5. 16
      src/components/Menu/styles.ts
  6. 221
      src/game.tsx
  7. 9
      src/index.html
  8. 19
      src/index.ts
  9. 32
      src/index.tsx
  10. 21
      src/lib/store.ts
  11. 2
      webpack.config.js
  12. 925
      yarn.lock
  13. 944
      yarn.nix

4
package.json

@ -12,8 +12,9 @@
"@emotion/core": "^10.0.35",
"@emotion/styled": "^10.0.27",
"classnames": "^2.2.6",
"discoteque": "^1.1.12",
"discoteque": "^2.0.4",
"emotion": "^10.0.27",
"luxon": "^1.25.0",
"ramda": "^0.27.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
@ -27,6 +28,7 @@
},
"devDependencies": {
"@types/classnames": "^2.2.10",
"@types/luxon": "^1.25.0",
"@types/ramda": "^0.27.19",
"@types/react": "^16.9.49",
"@types/react-dom": "^16.9.8",

BIN
src/assets/antic-slab-regular.woff2

7
src/components/Characters/index.tsx

@ -1,7 +1,8 @@
import React, { FC } from 'react';
import styled from '@emotion/styled';
import { IActor } from 'discoteque/lib/engine/types';
import { colors } from 'discoteque/lib/assets/style-vars';
import { Actor } from 'discoteque/lib/engine/types';
import { GameSkills } from '@/lib/skills';
import { IGameState } from '@/lib/store';
const CharacterListContainer = styled.div`
height: 100%;
@ -30,7 +31,7 @@ margin: 0;
type Props = {
actorDescriptions: Record<string, string>;
actors: Record<string, IActor>;
actors: Record<string, Actor<IGameState, GameSkills>>,
knownActors: string[];
}

22
src/components/Menu/index.tsx

@ -1,19 +1,18 @@
import React, { FC, useState } from 'react';
import React, { FC } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import SkillTree from 'discoteque/lib/components/SkillTree';
type Tabs = 'tasks' | 'characters' | 'skills';
import cn from 'classnames';
import * as styles from './styles';
import { setShowCustom } from 'discoteque/lib/engine/lib/store';
import TaskList from '../Tasks';
import taskInfo from '@/lib/tasks';
import styled from '@emotion/styled';
import Characters from '../Characters';
import { NodeMap, IActor } from 'discoteque/lib/engine/types';
import { stateSelector, setMenuTab, menuTabSelector } from '@/lib/store';
import { Helper } from '@/game';
import { setUI } from 'discoteque/lib/engine/store/actions';
import Skills from 'discoteque/lib/playback/components/Skills';
const TopMenuContainer = styled.div`
display: flex;
@ -23,28 +22,27 @@ height: 40px;
`
const actorDescriptions = {
char_helper: 'A very friendly fellow! Lover of helping others and very absurd guestions',
char_helper: 'A very friendly fellow! Lover of helping others and very absurd questions',
}
type TabMenuProps = {
nodeMap: NodeMap<any, any, any>;
}
const TabMenu: FC<TabMenuProps> = ({ nodeMap }) => {
const TabMenu: FC<TabMenuProps> = () => {
const dispatch = useDispatch();
const state = useSelector(stateSelector);
const openTab = useSelector(menuTabSelector);
const openTab = useSelector(menuTabSelector) as Tabs;
const setTab = (tabName: string) => () => dispatch(setMenuTab(tabName));
const openTasks = setTab('tasks');
const openSkills = setTab('skills');
const openChars = setTab('characters');
const closeMenu = () => dispatch(setShowCustom(false));
const closeMenu = () => dispatch(setUI({ game: true, custom: false }));
const actors = {
'char_helper': nodeMap['char_helper'] as IActor,
'char_helper': Helper,
}
return (
@ -58,7 +56,7 @@ const TabMenu: FC<TabMenuProps> = ({ nodeMap }) => {
</ul>
</TopMenuContainer>
{openTab === 'skills' && (
<SkillTree embeded />
<Skills />
)}
{openTab === 'tasks' && (
<TaskList taskList={state.db.tasks} taskInfo={taskInfo} />

16
src/components/Menu/styles.ts

@ -1,10 +1,7 @@
import { css } from 'emotion';
import { colors } from 'discoteque/lib/assets/style-vars';
import theme from 'discoteque/lib/playback/theme';
export const menuContainer = css`
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
display: flex;
@ -27,10 +24,11 @@ export const menuTabList = css`
padding: 5px 15px 5px 15px;
cursor: pointer;
transition: all 0.4s ease-out;
font-size: 1.5rem;
}
& > li.active {
background-color: ${colors.MainBgColorDark};
color: ${colors.MainBgColor};
background-color: ${theme.colors.backgroundStrong};
color: ${theme.colors.background};
transition: all 0.4s ease-in;
}
`;
@ -44,11 +42,11 @@ export const menuClose = css`
line-height: 40px;
font-size: 40px;
box-sizing: content-box;
border-right: 2px solid ${colors.MainBgColor};
border-right: 2px solid ${theme.colors.background};
text-align: center;
cursor: pointer;
color: ${colors.MainBgColor};
background-color: ${colors.MainBgColorDark};
color: ${theme.colors.background};
background-color: ${theme.colors.backgroundStrong};
`;
export const active = "active";

221
src/game.tsx

@ -1,23 +1,22 @@
import React from 'react';
import { IGameState, setState, reducer, addKnownCharacter, setTask } from '@/lib/store';
import { INode, IActor, EngineConfig, ILineOption, ILocation, RendererFN, ToolbarOptionsFN } from 'discoteque/lib/engine/types';
import { setShowCustom } from 'discoteque/lib/engine/lib/store';
import { Node, OptionObject, Actor, Location, EngineConfig } from 'discoteque/lib/engine/types';
import { setUI } from 'discoteque/lib/engine/store/actions';
import skills, { GameSkills } from './lib/skills';
import Menu from './components/Menu';
import { awardSkill } from 'discoteque/lib/engine/lib/utils';
import { lockSkills } from 'discoteque/lib/engine/lib/store';
import { awardSkill } from 'discoteque/lib/engine/util/skills';
import { DateTime } from 'luxon';
const nodes: INode<IGameState>[] = [
const nodes: Node<IGameState, GameSkills>[] = [
{
id: 'trying_out',
kind: 'node',
next: 'pre_choice',
lines: [
{ actorId: 'char_helper', text: "Hi!" } ,
(_, _g, dispatch) => {
dispatch(lockSkills());
(_, __, dispatch) => {
dispatch(addKnownCharacter('char_helper')(dispatch));
return { actorId: 'char_helper', text: 'I\'m Helper! I help people play this demo. (Not really...)' };
},
@ -31,8 +30,8 @@ const nodes: INode<IGameState>[] = [
{ actorId: 'char_helper', text: "Failing the check on the left will allow you to go again." },
{ actorId: 'char_helper', text: "Failing the check on the right will instantly end the game." },
{ actorId: 'char_helper', text: "You could also try going outside." },
({ skillPoints }, _, dispatch) => {
awardSkill(dispatch, skillPoints);
(_, __, dispatch) => {
awardSkill(dispatch);
dispatch(setTask("choice", { stages: [0] })(dispatch));
dispatch(setTask("outside", { stages: [0] })(dispatch));
return { actorId: 'char_helper', text: "By the way, here's a skill point just for you!" }
@ -58,9 +57,9 @@ const nodes: INode<IGameState>[] = [
next: 'exit',
lines: [
{ text: '[FAIL] You were so overhyped you couldn\'t even say what you wanted to say' },
{ actorId: 'char_helper', text: 'Well, this is the end.' },
(_, _gameState, dispatch) => {
dispatch(setState({ isOver: true }))
dispatch(setUI({ gameOver: true }))
return { actorId: 'char_helper', text: 'Well, this is the end.' };
},
],
},
@ -68,19 +67,20 @@ const nodes: INode<IGameState>[] = [
id: 'pre_choice',
kind: 'node',
lines: [
(_, gameState) => {
const counterRight = gameState.visitedRight;
const counterLeft = gameState.visitedLeft;
const combinedCounter = counterRight + counterLeft;
const showExit = combinedCounter >= 3;
return { actorId: 'char_helper', text: 'So, left, or right?', options: [
{ text: '"I want to go outside!"', value: 'pre_outside' },
{ text: '"Left!"', value: 'left_choice', skill: { name: 'tired', difficulty: 17, failTo: 'failed_choice_tired' } },
{ text: '"Right!"', value: 'right_choice', skill: { name: 'manic', difficulty: 9, failTo: 'failed_choice_manic' } },
showExit && { 'text': 'Let me out, please', value: 'exit' }
].filter(x => x) as ILineOption[] };
}
]
{ actorId: 'char_helper', text: 'So, left, or right?', },
],
options: (_, gameState) => {
const counterRight = gameState.visitedRight;
const counterLeft = gameState.visitedLeft;
const combinedCounter = counterRight + counterLeft;
const showExit = combinedCounter >= 3;
return [
{ text: '"I want to go outside!"', value: 'pre_outside' },
{ text: '"Left!"', value: 'left_choice', skill: { name: 'tired', difficulty: 17, failTo: 'failed_choice_tired' } },
{ text: '"Right!"', value: 'right_choice', skill: { name: 'manic', difficulty: 9, failTo: 'failed_choice_manic' } },
showExit && { 'text': 'Let me out, please', value: 'exit' }
].filter(x => x) as OptionObject<GameSkills>[]
},
},
{
id: 'pre_outside',
@ -107,13 +107,13 @@ const nodes: INode<IGameState>[] = [
{ actorId: 'char_helper', text: 'Huh. I think we\'ve been here before, no?' }
) : { actorId: 'char_helper', text: 'Good choice! As i\'ve said, picking left will lead you back.' };
},
({ skillPoints }, gameState, dispatch) => {
(_, gameState, dispatch) => {
if ((gameState.visitedLeft + 1) === 3) {
awardSkill(dispatch, skillPoints);
awardSkill(dispatch);
}
dispatch(setState({ visitedLeft: gameState.visitedLeft + 1 }));
return { actorId: 'char_helper', text: 'Pick the other choice next time, maybe?' };
},
{ actorId: 'char_helper', text: 'Pick the other choice next time, maybe?' },
]
},
{
@ -122,9 +122,9 @@ const nodes: INode<IGameState>[] = [
next: 'pre_choice',
lines: [
{ text: 'Without hesistation, you decided to go straight for the right option!' },
{ actorId: 'char_helper', text: 'Well, you passed this check. Try the other one now, and don\'t forget to fail this one.' },
(_, gameState, dispatch) => {
dispatch(setState({ visitedRight: gameState.visitedRight + 1 }));
return { actorId: 'char_helper', text: 'Well, you passed this check. Try the other one now, and don\'t forget to fail this one.' };
}
]
},
@ -136,6 +136,7 @@ const nodes: INode<IGameState>[] = [
{ actorId: 'char_helper', text: 'Thanks, but this is the end.' },
(_engineState, _gameState, dispatch) => {
dispatch(setState({ isOver: true }))
return { actorId: 'char_helper', text: 'Thanks, but this is the end.' };
},
]
},
@ -147,10 +148,10 @@ const nodes: INode<IGameState>[] = [
{ text: 'There\'s a letter inside.' },
{ text: 'You open it to take a look...' },
{ text: '"Welcome to Discoteque! An engine for games of adventure, danger, and low cunning!"' },
({ skillPoints }, gameState, dispatch) => {
(_, gameState, dispatch) => {
if (!gameState.readMailbox) {
dispatch(setState({ readMailbox: true }));
awardSkill(dispatch, skillPoints);
awardSkill(dispatch);
}
return { text: `"No browser should be without one!" ${!gameState.readMailbox ? "[+1 Skill Point]" : ""}`, time: 5 };
}
@ -190,18 +191,19 @@ const nodes: INode<IGameState>[] = [
{
'id': 'dialogue_helper', kind: 'node',
lines: [
(_, { talkedAboutTrapdoor }) => {
const trapdoorTalkSkill = talkedAboutTrapdoor ? 0 : 10;
return { text: 'What do you want to ask?', options: [
{ text: '"Tell me about that choice."', value: 'about_choice' },
{ text: '"Tell me about the trapdoor"', value: 'about_trapdoor', skill: {
name: 'tired', difficulty: trapdoorTalkSkill, failTo: 'about_trapdoor_fail'
} },
{ text: '"I\'m ready to pick"', value: 'pre_choice' },
{ text: '"Just came by to say hi!"', value: 'inside' },
] };
},
{ text: 'What do you want to ask?' },
],
options: (_, { talkedAboutTrapdoor }) => {
const trapdoorTalkSkill = talkedAboutTrapdoor ? 0 : 10;
return [
{ text: '"Tell me about that choice."', value: 'about_choice' },
{ text: '"Tell me about the trapdoor"', value: 'about_trapdoor', skill: {
name: 'tired', difficulty: trapdoorTalkSkill, failTo: 'about_trapdoor_fail'
} },
{ text: '"I\'m ready to pick"', value: 'pre_choice' },
{ text: '"Just came by to say hi!"', value: 'inside' },
]
}
},
{
'id': 'about_choice', kind: 'node', next: 'dialogue_helper',
@ -228,11 +230,11 @@ const nodes: INode<IGameState>[] = [
{ actorId: 'char_helper', text: 'What a *grue*some end, right?' },
{ text: 'Helper starts laughing and can\'t help themselves. You don\'t appreciate the joke though.' },
{ actorId: 'char_helper', text: 'Well, enought about gruesome things, let\'s get back to the topic of chosing' },
({ skillPoints }, gameState, dispatch) => {
(_, gameState, dispatch) => {
const { talkedAboutTrapdoor } = gameState;
if (!talkedAboutTrapdoor) {
dispatch(setState({ talkedAboutTrapdoor: true }));
awardSkill(dispatch, skillPoints);
awardSkill(dispatch);
dispatch(setTask('trapdoor', { stagesComplete: [0, 1] })(dispatch));
return { text: 'You feel like this will help you search for the trap door. [+1 Skill Point]' };
}
@ -246,13 +248,13 @@ const nodes: INode<IGameState>[] = [
{ text: 'But nothing comes up!' },
{ text: 'It\'s almost as if it\'s there but every time you look at it moves to another place.' },
{ text: 'Or perhaps it is always just right out of the corner of your eye...' },
({ skillPoints }, gameState, dispatch) => {
(_, gameState, dispatch) => {
const { lookedAtTrapdoor } = gameState;
if (lookedAtTrapdoor) {
return { text: 'Looks like you will have to search more thoroughly.' }
}
dispatch(setState({ lookedAtTrapdoor: true }));
awardSkill(dispatch, skillPoints)
awardSkill(dispatch)
return { text: 'You feel like you\'ll have an easier time looking for the trapdoor properly. [+1 Skill Point]' }
},
],
@ -260,23 +262,31 @@ const nodes: INode<IGameState>[] = [
]
// { actorId: 'char_helper', text: '' },
const actors: IActor<IGameState>[] = [
{ 'id': 'char_helper', kind: 'actor', name: 'Helper', image: require('@/assets/images/user.png').default, lines: [
export const Helper: Actor<IGameState, GameSkills> = {
'id': 'char_helper',
kind: 'actor',
name: 'Helper',
// image: require('@/assets/images/user.png').default,
lines: [
(_, { haveTalkedToHelper }, dispatch) => {
if (!haveTalkedToHelper) {
dispatch(setState({ haveTalkedToHelper: true }));
dispatch(setTask('outside', { stagesComplete: [0, 1, 2] })(dispatch));
dispatch(setTask('trapdoor', { stages: [0, 1, 2], stagesComplete: [0] })(dispatch));
}
return { actorId: 'char_helper', text: 'Back again, huh?' };
},
{ actorId: 'char_helper', text: 'Back again, huh?' },
{ actorId: 'char_helper', text: 'Then I guess you\'re ready to pick right from left now.', },
], next: 'dialogue_helper' },
],
next: 'dialogue_helper'
};
const actors: Actor<IGameState, GameSkills>[] = [
Helper,
{ 'id': 'char_you', kind: 'actor', name: 'You', lines: [] },
]
const locations: ILocation<IGameState>[] = [
const locations: Location<IGameState, GameSkills>[] = [
{ 'id': 'outside', kind: 'location', name: 'Great Outdoors', lines: [
(_, { beenOutside }, dispatch) => {
if (!beenOutside) {
@ -286,10 +296,10 @@ const locations: ILocation<IGameState>[] = [
return { text: 'You are standing in an open field, west of house.' };
},
{ text: 'The sea of green extends into all directions, as far as your eye can see.' },
{ text: 'What now?', options: [
{ text: 'Look inside mailbox', value: 'mailbox' },
{ text: 'Go inside the house', value: 'inside' },
] },
{ text: 'What now?', },
], options: [
{ text: 'Look inside mailbox', value: 'mailbox' },
{ text: 'Go inside the house', value: 'inside' },
] },
{ 'id': 'inside', kind: 'location', name: 'Inside House', lines: [
(_, { beenInside }, dispatch) => {
@ -298,82 +308,73 @@ const locations: ILocation<IGameState>[] = [
dispatch(setTask('outside', { stages: [0, 1, 2], stagesComplete: [0, 1] })(dispatch));
dispatch(setTask('trapdoor', { stages: [0, 2], stagesComplete: [0] })(dispatch));
}
return { text: 'You are standing inside a small wooden house. The setup feels familiar... ' };
},
{ text: 'You are standing inside a small wooden house. The setup feels familiar... ' },
{ text: 'You almost expect there to be a trapdoor to a great underground empire.' },
{ text: 'You can see Helper here as well. They are standing in the corner, gesturing you to come and talk to them.' },
(_, { lookedAtTrapdoor, talkedAboutTrapdoor }) => {
const searchDifficulties = [
lookedAtTrapdoor && 10,
talkedAboutTrapdoor && 5,
].filter(id => id) as Array<number>;
const searchDifficulty = searchDifficulties.reduce(
(acc, val) => acc - val,
25,
);
const searchEffects = [
lookedAtTrapdoor && '[+10 from scanning the room]',
talkedAboutTrapdoor && '[+5 from talking about trap door with Helper]',
].filter(id => id);
return { text: 'What will you do now?', options: [
{ text: 'Go back outside', value: 'outside' },
{ text: 'Talk to Helper', value: 'char_helper' },
{ text: 'Scan the room for the trapdoor', value: 'look_trapdoor' },
{
text: `Search thoroughly for the trapdoor ${searchEffects.join(' ')}`,
value: 'trapdoor_win',
skill: { name: 'manic', difficulty: searchDifficulty, failTo: 'trapdoor_end' }
},
] }
},
] },
{ text: 'What will you do now?' }
], options: (_, { lookedAtTrapdoor, talkedAboutTrapdoor }) => {
const searchDifficulties = [
lookedAtTrapdoor && 10,
talkedAboutTrapdoor && 5,
].filter(id => id) as Array<number>;
const searchDifficulty = searchDifficulties.reduce(
(acc, val) => acc - val,
25,
);
const searchEffects = [
lookedAtTrapdoor && '[+10 from scanning the room]',
talkedAboutTrapdoor && '[+5 from talking about trap door with Helper]',
].filter(id => id);
return [
{ text: 'Go back outside', value: 'outside' },
{ text: 'Talk to Helper', value: 'char_helper' },
{ text: 'Scan the room for the trapdoor', value: 'look_trapdoor' },
{
text: `Search thoroughly for the trapdoor ${searchEffects.join(' ')}`,
value: 'trapdoor_win',
skill: { name: 'manic', difficulty: searchDifficulty, failTo: 'trapdoor_end' }
},
];
} },
];
interface IGameConfig extends EngineConfig<IGameState, undefined, GameSkills> {
interface IGameConfig extends EngineConfig<IGameState, GameSkills> {
}
const renderFn: RendererFN<IGameState, undefined, GameSkills> = (engine) => {
const nodeMap = engine.config.nodes.reduce((acc, node) => ({ ...acc, [node.id]: node }), {});
const renderFn = () => {
return (
<Menu nodeMap={nodeMap} />
<Menu />
);
};
const optionsFn: ToolbarOptionsFN<IGameState, undefined, GameSkills> = (_engine, _engineConfig, _gameState, dispatch) => {
return [
{ label: 'Journal', onClick: () => dispatch(setShowCustom(true)) },
]
}
export const config: IGameConfig = {
menu: {
title: 'Discoteque Demo',
description: 'Interactive fiction system with light RPG elements',
},
reducer: reducer,
startNode: 'trying_out',
startAt: 'trying_out',
nodes: [
...nodes,
...actors,
...locations,
],
chrono: {
time: 1435,
date: "10 September",
},
onDayCycle: (time) => {
const day = time.date?.substr(0, 2) || "10";
const restOfDate = time.date?.substr(2) || " September";
const dayNum = Number(day) !== NaN ? Number(day) : 10;
return {
time: 0,
date: `${dayNum + 1}${restOfDate}`,
}
date: DateTime.local(),
},
skills,
skillPointsOnStart: 5,
customRenderer: renderFn,
customOptions: optionsFn,
skillDescriptoins: {
'manic': 'Out of this world at the highest pace',
'tired': 'Slow burning and contemplation',
}
skillPoints: 5,
customScreenFn: renderFn,
customDropdownFn: (_, __, dispatch) => {
return [
{ title: 'Journal', onClick: () => dispatch(setUI({ custom: true, game: false })) },
]
},
// skillDescriptoins: {
// 'manic': 'Out of this world at the highest pace',
// 'tired': 'Slow burning and contemplation',
// }
}
export default config;

9
src/index.html

@ -20,15 +20,8 @@
<div id="root"></div>
<section class="credits">
<p>
This is a demo for <a target="_blank" href="https://code.gensokyo.social/Gensokyo.social/discoteque">Discoteque v1.1.12</a>, a dialogue-based RPG / Interactive Book system
This is a demo for <a target="_blank" href="https://discoteque.pub">Discoteque v2.0.4</a>, an interactive fiction engine.
</p>
<div class="creditsSrc">
From <a href="https://deiru.tokyo" target="_blank">Dale</a> with <span class="heart"></span>
|&nbsp;<a herf="_blank" href="https://code.gensokyo.social/Gensokyo.social/discoteque-demo">Demo Source Code</a>
</div>
<div class="creditsSrc">
Back to <a href="/">root</a>
</div>
</section>
</body>
<style>

19
src/index.ts

@ -1,19 +0,0 @@
import makeApp from 'discoteque/lib';
import { injectGlobal } from 'emotion';
import 'react-toastify/dist/ReactToastify.css';
import font from "discoteque/src/assets/fonts/AnticSlab-Regular.woff2";
injectGlobal`
@font-face {
font-family: 'Antic Slab Regular';
src: url(${font}) format('woff2');
} body {
font-family: 'Antic Slab Regular';
}
`;
import config from '@/game';
makeApp(config);

32
src/index.tsx

@ -0,0 +1,32 @@
import React, { useMemo, FC } from 'react';
import { Provider } from 'react-redux';
import { render } from 'react-dom';
import { injectGlobal } from 'emotion';
import Engine from 'discoteque/lib/engine/Engine';
import Playback from 'discoteque/lib/playback';
import font from "./assets/fonts/AnticSlab-Regular.woff2";
import config from '@/game';
injectGlobal`
@font-face {
font-family: 'Antic Slab Regular';
src: url(${font}) format('woff2');
} body {
font-family: 'Antic Slab Regular';
}
`;
const App: FC = () => {
const engine = useMemo(() => new Engine<any, any>(config), [config]);
return (
<Provider store={engine.store}>
<Playback engine={engine} />
</Provider>
)
};
render(<App />, document.getElementById('root'));

21
src/lib/store.ts

@ -1,9 +1,8 @@
import * as R from 'ramda';
import { createStore, Action, Dispatch } from 'redux';
import { ILine } from 'discoteque/lib/engine/types';
import { Line } 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';
import { expandBacklog } from 'discoteque/lib/engine/store/actions';
export interface IGameState {
visitedLeft: number;
@ -20,7 +19,7 @@ export interface IGameState {
characters: string[],
tasks: Task[],
}
backlog: ILine<IGameState>[];
backlog: Line<IGameState>[];
}
export interface IGameStateAction extends Action {
@ -40,19 +39,13 @@ export const initState = (state: IGameState): IGameStateAction => ({ type: 'INIT
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));
} });
dispatch(expandBacklog({ text: 'Updated my journal' }))
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));
} });
dispatch(expandBacklog({ text: 'Updated my journal' }))
return {
type: 'ADD-KNOWN-CHARACTER', character,
};
@ -82,8 +75,8 @@ export const reducer = (state: IGameState = defaultState, action: IGameStateActi
return ({ ...state, ...action.state });
case 'INIT-GAME':
return action.state || state;
case 'INIT':
return (action as any).data.gameState || state;
case 'engine-restore' as any:
return (action as any).payload.gameState || state;
case 'RESET-GAME':
return defaultState;
case 'SET-TASK':

2
webpack.config.js

@ -4,7 +4,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'none',
entry: {
app: path.join(__dirname, 'src', 'index.ts')
app: path.join(__dirname, 'src', 'index.tsx')
},
target: 'web',
resolve: {

925
yarn.lock
File diff suppressed because it is too large
View File

944
yarn.nix
File diff suppressed because it is too large
View File

Loading…
Cancel
Save