You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.2 KiB
JavaScript
149 lines
4.2 KiB
JavaScript
import React from 'react'
|
|
import useGameState from '../../hooks/useGameState'
|
|
import useLoadGame from '../../hooks/useLoadGame'
|
|
import useLocalStorage from '../../hooks/useLocalStorage'
|
|
import {DateTime} from 'luxon'
|
|
|
|
import styles from './Options.module.css'
|
|
import useSharedState from '../../hooks/useSharedState'
|
|
|
|
export default function () {
|
|
const [currentTab, setCurrentTab] = useSharedState('optionsTab', 'data')
|
|
const [, setCurrentMenu] = useSharedState('currentMenu')
|
|
|
|
const gameState = useGameState()
|
|
const saveFile1 = useLocalStorage('save1', null)
|
|
const saveFile2 = useLocalStorage('save2', null)
|
|
const saveFile3 = useLocalStorage('save3', null)
|
|
const loadGame = useLoadGame()
|
|
|
|
const [videoOptions, setVideoOptions] = useLocalStorage('video')
|
|
|
|
function OptionButton({name}) {
|
|
return (
|
|
<button
|
|
className={styles.optionMenuButton + (currentTab === name ? ' ' + styles.selected : '')}
|
|
onClick={ev => setCurrentTab(name)}
|
|
>
|
|
{name}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function OptionSetting({name, label}){
|
|
return (
|
|
<div className={styles.optionContainer}>
|
|
<input
|
|
name={name}
|
|
type="checkbox"
|
|
checked={videoOptions[name]}
|
|
onChange={ev => setVideoOptions(current => ({
|
|
...current,
|
|
[name]: ev.target.checked
|
|
}))}
|
|
/>
|
|
<label htmlFor={name}>{label}</label>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function SaveFile({slot: [data, saveData], name}){
|
|
function save() {
|
|
if(data) {
|
|
const proceed = window.confirm(`Save over ${name}?`)
|
|
if(!proceed) return;
|
|
}
|
|
|
|
saveData(serializeState(gameState))
|
|
|
|
setTimeout(() => setCurrentMenu(null), 200)
|
|
}
|
|
|
|
function load() {
|
|
const newData = deserializeState(data)
|
|
const proceed = window.confirm("Load save from " + name + "?")
|
|
|
|
if(!proceed) return;
|
|
|
|
loadGame(newData)
|
|
|
|
setCurrentMenu(null)
|
|
}
|
|
|
|
return (
|
|
<div className={styles.saveFile}>
|
|
<div className={styles.saveInfo}>
|
|
<p><u>{name}:</u></p>
|
|
{data ? (
|
|
<p>{DateTime.fromISO(data.saved).toLocal().toLocaleString(DateTime.DATETIME_SHORT)}</p>
|
|
) : (
|
|
<p>No data</p>
|
|
)}
|
|
</div>
|
|
<button onClick={save} className={styles.saveButton}>Save</button>
|
|
<button disabled={!data} onClick={load} className={styles.saveButton}>Load</button>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className={styles.container}>
|
|
<div className={styles.sidebar}>
|
|
<OptionButton name="data"/>
|
|
<OptionButton name="video"/>
|
|
</div>
|
|
<div className={styles.settings}>
|
|
{currentTab === 'video' && (
|
|
<>
|
|
<h3>Video Options</h3>
|
|
<p>Feel free to tweak these to your liking - they have no effect on gameplay.</p>
|
|
<OptionSetting name="fuzzing" label="Text Glow"/>
|
|
<OptionSetting name="flickering" label="Screen Flickering"/>
|
|
<OptionSetting name="scanLines" label="Scan Lines"/>
|
|
<OptionSetting name="imageBackground" label="Image Background"/>
|
|
</>
|
|
)}
|
|
{currentTab === 'data' && (
|
|
<>
|
|
<h3>Data Files</h3>
|
|
<SaveFile slot={saveFile1} name="File 1"/>
|
|
<SaveFile slot={saveFile2} name="File 2"/>
|
|
<SaveFile slot={saveFile3} name="File 3"/>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
|
|
function serializeState(state) {
|
|
return JSON.parse(JSON.stringify({...state, saved: DateTime.local().toISO()}, (key, value) => {
|
|
if(value instanceof Map)
|
|
return Array.from(value).reduce((obj, [key, value]) => {
|
|
obj[key] = value;
|
|
return obj;
|
|
}, {_serializedType: 'map'});
|
|
|
|
if(value instanceof Set)
|
|
throw new Error("Do not know how to safely serialize sets")
|
|
|
|
return value
|
|
}))
|
|
}
|
|
|
|
function deserializeState(state) {
|
|
return JSON.parse(JSON.stringify(state), (key, value) => {
|
|
if(value._serializedType === 'map') {
|
|
const map = new Map()
|
|
for(const item in value)
|
|
if(item !== '_serializedType')
|
|
map.set(item, value[item])
|
|
return map
|
|
}
|
|
|
|
return value
|
|
})
|
|
}
|