Drop the high score wipe; scores leave only by being beaten
The table was clearable behind a confirm. It should not be: a stand earns its place and loses it only to a better summer, so the control and clearScores() are gone and the screen says so.
This commit is contained in:
@@ -41,12 +41,16 @@ Retiring writes every player's closing balance to a top-ten table kept in
|
|||||||
from the summer you just finished are picked out in yellow. Ties break on the
|
from the summer you just finished are picked out in yellow. Ties break on the
|
||||||
shorter season, then on the earlier date.
|
shorter season, then on the earlier date.
|
||||||
|
|
||||||
|
There is no way to clear the table. A stand leaves the list only by being
|
||||||
|
pushed off the bottom by a better one, so a good summer stands until somebody
|
||||||
|
beats it.
|
||||||
|
|
||||||
The table is per-browser, not per-device, and it is the one piece of state the
|
The table is per-browser, not per-device, and it is the one piece of state the
|
||||||
game keeps between visits. Anything already in storage can be edited by hand,
|
game keeps between visits. Anything already in storage can be edited by hand,
|
||||||
so every field is validated on the way back in and malformed rows are dropped
|
so every field is validated on the way back in and malformed rows are dropped
|
||||||
rather than trusted. If storage is unavailable — a private window, or a browser
|
rather than trusted. If storage is unavailable — a private window, or a browser
|
||||||
set to block site data — the game plays normally and the table simply stays
|
set to block site data — the game plays normally and the table simply stays
|
||||||
empty. **WIPE TABLE** clears it, and asks once before it does.
|
empty.
|
||||||
|
|
||||||
## How it is put together
|
## How it is put together
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -4,7 +4,7 @@ import { synth } from './audio/synth'
|
|||||||
import { WEATHER } from './game/constants'
|
import { WEATHER } from './game/constants'
|
||||||
import { dollars, randomSeed, rollDay, simulate } from './game/engine'
|
import { dollars, randomSeed, rollDay, simulate } from './game/engine'
|
||||||
import { makeRng, type Rng } from './game/rng'
|
import { makeRng, type Rng } from './game/rng'
|
||||||
import { addScores, clearScores, loadScores, type Score } from './game/highscores'
|
import { addScores, loadScores, type Score } from './game/highscores'
|
||||||
import { activePlayers, initialState, reducer } from './game/reducer'
|
import { activePlayers, initialState, reducer } from './game/reducer'
|
||||||
import type { Decision } from './game/types'
|
import type { Decision } from './game/types'
|
||||||
import { BriefingScreen } from './components/BriefingScreen'
|
import { BriefingScreen } from './components/BriefingScreen'
|
||||||
@@ -267,8 +267,6 @@ export default function App() {
|
|||||||
synth.select()
|
synth.select()
|
||||||
dispatch({ type: 'CLOSE_SCORES' })
|
dispatch({ type: 'CLOSE_SCORES' })
|
||||||
}}
|
}}
|
||||||
onClear={() => setScores(clearScores())}
|
|
||||||
onBlip={blip}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Fit>
|
</Fit>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useState } from 'react'
|
|
||||||
import { dollars } from '../game/engine'
|
import { dollars } from '../game/engine'
|
||||||
import { MAX_SCORES, type Score } from '../game/highscores'
|
import { MAX_SCORES, type Score } from '../game/highscores'
|
||||||
import { Btn, Line } from './Crt'
|
import { Btn, Line } from './Crt'
|
||||||
@@ -10,16 +9,11 @@ export function HighScoreScreen({
|
|||||||
scores,
|
scores,
|
||||||
highlight,
|
highlight,
|
||||||
onBack,
|
onBack,
|
||||||
onClear,
|
|
||||||
onBlip,
|
|
||||||
}: {
|
}: {
|
||||||
scores: Score[]
|
scores: Score[]
|
||||||
highlight: string[]
|
highlight: string[]
|
||||||
onBack: () => void
|
onBack: () => void
|
||||||
onClear: () => void
|
|
||||||
onBlip: () => void
|
|
||||||
}) {
|
}) {
|
||||||
const [confirming, setConfirming] = useState(false)
|
|
||||||
const fresh = new Set(highlight)
|
const fresh = new Set(highlight)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -52,26 +46,12 @@ export function HighScoreScreen({
|
|||||||
|
|
||||||
<Line />
|
<Line />
|
||||||
<Line className="center dim">TOP {MAX_SCORES}, KEPT IN THIS BROWSER.</Line>
|
<Line className="center dim">TOP {MAX_SCORES}, KEPT IN THIS BROWSER.</Line>
|
||||||
|
<Line className="center dim">A STAND LEAVES ONLY BY BEING BEATEN.</Line>
|
||||||
<Line />
|
<Line />
|
||||||
<div className="row center">
|
<div className="row center">
|
||||||
<Btn kind="primary" onClick={onBack}>
|
<Btn kind="primary" onClick={onBack}>
|
||||||
BACK
|
BACK
|
||||||
</Btn>
|
</Btn>
|
||||||
{scores.length > 0 && (
|
|
||||||
<Btn
|
|
||||||
onClick={() => {
|
|
||||||
onBlip()
|
|
||||||
if (confirming) {
|
|
||||||
onClear()
|
|
||||||
setConfirming(false)
|
|
||||||
} else {
|
|
||||||
setConfirming(true)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{confirming ? 'REALLY WIPE?' : 'WIPE TABLE'}
|
|
||||||
</Btn>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
+5
-10
@@ -67,7 +67,11 @@ const newId = () =>
|
|||||||
? crypto.randomUUID()
|
? crypto.randomUUID()
|
||||||
: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`
|
: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`
|
||||||
|
|
||||||
/** Returns the saved table and the ids of the entries this call added. */
|
/**
|
||||||
|
* Returns the saved table and the ids of the entries this call added. The
|
||||||
|
* table only ever loses a row by being pushed past MAX_SCORES by a better
|
||||||
|
* one - there is no way to clear it.
|
||||||
|
*/
|
||||||
export function addScores(entries: NewScore[]): { table: Score[]; added: string[] } {
|
export function addScores(entries: NewScore[]): { table: Score[]; added: string[] } {
|
||||||
const at = Date.now()
|
const at = Date.now()
|
||||||
const fresh: Score[] = entries.map((e) => ({ ...e, id: newId(), at }))
|
const fresh: Score[] = entries.map((e) => ({ ...e, id: newId(), at }))
|
||||||
@@ -76,12 +80,3 @@ export function addScores(entries: NewScore[]): { table: Score[]; added: string[
|
|||||||
const kept = new Set(table.map((s) => s.id))
|
const kept = new Set(table.map((s) => s.id))
|
||||||
return { table, added: fresh.filter((s) => kept.has(s.id)).map((s) => s.id) }
|
return { table, added: fresh.filter((s) => kept.has(s.id)).map((s) => s.id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearScores(): Score[] {
|
|
||||||
try {
|
|
||||||
window.localStorage.removeItem(KEY)
|
|
||||||
} catch {
|
|
||||||
// Ignored - the table is rendered from the return value either way.
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user