Video options and initial setup page

main
Ashelyn Dawn 4 years ago
parent 811207dc87
commit ca264d4e6b

@ -3,6 +3,7 @@ import useWindowSize from '../../hooks/useWindowSize'
import styles from './App.module.css';
import Screen from '../Screen/Screen';
import {Provider} from '../../hooks/useGameState'
import useLocalStorage from '../../hooks/useLocalStorage'
import backgroundURL from './background.png'
@ -14,10 +15,10 @@ function App({promptVisible, onCommand, game}) {
const scaleY = height / 400
const scale = 0 || Math.min(scaleX, scaleY)
const fuzzing = true
const flickering = true
const scanLines = true
const imageBackground = true
const [effects] = useLocalStorage('video')
console.log(effects)
const {fuzzing, flickering, scanLines, imageBackground} = effects
useEffect(() => {
game.onChange(setState)

@ -33,8 +33,8 @@ export default function ({containerRef}) {
if(currentMenu === 'inventory')
return <Inventory/>
// if(currentMenu === 'options')
// return <Options/>
if(currentMenu === 'options')
return <Options/>
return <p>Not implemented yet, sorry</p>
})()}

@ -57,6 +57,7 @@
right: 0;
bottom: 0;
border: solid 4px white;
pointer-events: none;
}
.modalTitle {

@ -1,11 +1,72 @@
import React from 'react'
import useGameState from '../../hooks/useGameState'
import useLocalStorage from '../../hooks/useLocalStorage'
import styles from './Options.module.css'
import useSharedState from '../../hooks/useSharedState'
export default function () {
const [currentTab, setCurrentTab] = useSharedState('optionsTab', 'video')
const gameState = useGameState()
const saveFile1 = useLocalStorage('save1', null)
const saveFile2 = useLocalStorage('save2', null)
const saveFile3 = useLocalStorage('save3', null)
const [videoOptions, setVideoOptions] = useLocalStorage('video')
console.log(videoOptions)
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>
)
}
return (
<>
<ul>
<li>Nothing</li>
</ul>
<div className={styles.container}>
<div className={styles.sidebar}>
<OptionButton name="video"/>
<OptionButton name="save / load"/>
</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 === 'save / load' && (
<p>Save / load</p>
)}
</div>
</div>
</>
)
}

@ -0,0 +1,37 @@
.container {
display: flex;
flex-direction: row;
height: 100%;
}
.sidebar {
padding-top: 10px;
width: 100px;
border-right: solid 1px rgba(255,255,255,.2);
}
.settings {
flex: 1;
padding: 0 10px;
}
.optionMenuButton {
display: block;
width: 80px;
margin: 10px;
background: transparent;
color: white;
border: solid 1px white;
padding: 4px;
cursor: pointer;
}
.optionMenuButton.selected {
color: black;
background: white;
}
.optionContainer input {
position: relative;
top: 2px;
}

@ -66,7 +66,7 @@ export default function Text({promptVisible, handleCommand, showReflection}) {
<>
<div ref={textRef} className={styles.playArea}>
<Menu containerRef={menuRef}/>
<div ref={outputRef} onScroll={() => setCurrentScroll(outputRef.current?.scrollTop)} className={styles.output}>
<div ref={outputRef} onScroll={() => setCurrentScroll(outputRef.current?.scrollTop)} className={styles.output + (currentMenu !== null ? ' ' + styles.noMouse : '')}>
{messages.map((message, i) => {
if(message.type === 'message')
return <ReactMarkdown key={i}>{message.message}</ReactMarkdown>

@ -73,6 +73,10 @@
font-weight: bold;
}
.output.noMouse {
pointer-events: none;
}
/**
* Shadow
*/

@ -0,0 +1,56 @@
import React from 'react'
import styles from './Setup.module.css'
export default function Setup() {
return (
<div className={styles.options}>
<h1>Setup</h1>
<p>
This game has visual effects which could be problematic for players
with photosensitive epilepsy or impaired vision, including:
</p>
<ul>
<li>Rapid pulsing text glow</li>
<li>Screen flickering</li>
<li>Moving and repeating screen overlays</li>
<li>An image background that may lower visual contrast in reading text</li>
</ul>
<p>
These effects are <strong><em>entirely optional</em></strong>, and do not affect
the gameplay in any way. Do you wish to start with these effects turned
on?
</p>
<p style={{textAlign: 'center'}}>
<button onClick={startWithEffects}>Start with effects</button>
<button onClick={startWithoutEffects}>Start without effects</button>
</p>
<p style={{opacity: .6}}>
<strong>Note:</strong> Each of these options can be enabled or disabled
later via the in-game video options menu.
</p>
</div>
)
}
function startWithEffects() {
window.localStorage.setItem('video', JSON.stringify({
fuzzing: true,
flickering: true,
scanLines: true,
imageBackground: true
}))
window.location.reload()
}
function startWithoutEffects() {
window.localStorage.setItem('video', JSON.stringify({
fuzzing: false,
flickering: false,
scanLines: false,
imageBackground: false
}))
window.location.reload()
}

@ -0,0 +1,22 @@
.options {
max-width: 800px;
width: calc(100vw - 200px);
}
.options button {
background: transparent;
border: solid 1px white;
margin: 5px 15px;
color: white;
padding: 5px 10px;
font-family: inherit;
cursor: pointer;
}
.options {
color: rgba(255,255,255,.7);
}
.options strong {
color: white;
}

@ -2,6 +2,7 @@ import React from 'react'
import ReactDOM from 'react-dom'
import '../index.css';
import App from '../components/App/App';
import Setup from '../components/Setup/Setup';
import Game from "./Game";
import Parser from "./Parser";
@ -16,6 +17,7 @@ export default class Renderer {
private output : GameEvent[] = []
private target : HTMLElement | null = null
private promptVisible : boolean = true
private videoSettingsSet : boolean = !!window.localStorage.getItem('video')
constructor(parser : Parser, game : Game, rules : RulesEngine) {
this.parser = parser
@ -49,11 +51,20 @@ export default class Renderer {
if(!this.target)
throw new Error("Renderer error: target is null")
ReactDOM.render(
<React.StrictMode>
<App promptVisible={this.promptVisible} game={this.game} onCommand={this.handleCommand.bind(this)}/>
</React.StrictMode>,
this.target
)
if(!this.videoSettingsSet) {
ReactDOM.render(
<React.StrictMode>
<Setup/>
</React.StrictMode>,
this.target
)
} else {
ReactDOM.render(
<React.StrictMode>
<App promptVisible={this.promptVisible} game={this.game} onCommand={this.handleCommand.bind(this)}/>
</React.StrictMode>,
this.target
)
}
}
}

@ -0,0 +1,25 @@
import {useState, useEffect} from 'react'
import useSharedState from './useSharedState'
export default function useLocalStorage(key, initialValue) {
const raw = window.localStorage.getItem(key)
let init
try {
init = raw ? JSON.parse(raw) : initialValue
} catch {
init = initialValue
}
const [storedValue, setStoredValue] = useSharedState('localstorage_' + key, init)
useEffect(() => {
try {
window.localStorage.setItem(key, JSON.stringify(storedValue));
} catch (error) {
console.log(error);
}
}, [storedValue])
return [storedValue, setStoredValue];
}

@ -9,8 +9,8 @@ const updateSharedState = (key, state) => {
stateChanged.emit(key)
}
export default function useSharedState(key) {
const [localState, setLocalState] = useState()
export default function useSharedState(key, initial) {
const [localState, setLocalState] = useState(initial)
useEffect(() => {
const updateLocal = () => setLocalState(sharedState[key])

@ -6,10 +6,11 @@ html, body {
#root {
display: flex;
flex-direction: column;
min-height: 100vh;
align-items: center;
justify-content: center;
background: black;
background: #171717;
/* font-family: 'VT323', monospace; */
font-family: 'Share Tech Mono', monospace;
overflow: hidden;

Loading…
Cancel
Save