docs(mystery): spec for engine prereqs (verbs, disambiguation, ending UI) #1
@@ -169,3 +169,17 @@
|
|||||||
@media (pointer: coarse) {
|
@media (pointer: coarse) {
|
||||||
.mystery-chips { display: flex; }
|
.mystery-chips { display: flex; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mystery-transcript .ending {
|
||||||
|
margin-top: 2em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding-top: 1em;
|
||||||
|
border-top: 1px solid currentColor;
|
||||||
|
font-style: italic;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-mystery-input]:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ if (!transcriptEl || !inputEl) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const syncEndedUI = (): void => {
|
||||||
|
inputEl!.disabled = state.endedWith !== null
|
||||||
|
}
|
||||||
|
|
||||||
const buildParserContext = (s: GameState): ParserContext => {
|
const buildParserContext = (s: GameState): ParserContext => {
|
||||||
const room = world.rooms[s.location]
|
const room = world.rooms[s.location]
|
||||||
const visibleNouns: { id: string; aliases: string[] }[] = []
|
const visibleNouns: { id: string; aliases: string[] }[] = []
|
||||||
@@ -81,6 +85,7 @@ if (!transcriptEl || !inputEl) {
|
|||||||
|
|
||||||
renderAll(state.transcript)
|
renderAll(state.transcript)
|
||||||
refreshChips()
|
refreshChips()
|
||||||
|
syncEndedUI()
|
||||||
inputEl.focus()
|
inputEl.focus()
|
||||||
|
|
||||||
inputEl.addEventListener('keydown', (e) => {
|
inputEl.addEventListener('keydown', (e) => {
|
||||||
@@ -91,6 +96,15 @@ if (!transcriptEl || !inputEl) {
|
|||||||
if (!raw.trim()) return
|
if (!raw.trim()) return
|
||||||
appendLines([{ kind: 'player', text: raw }])
|
appendLines([{ kind: 'player', text: raw }])
|
||||||
|
|
||||||
|
// Once the game has ended, only restart and undo are allowed.
|
||||||
|
if (state.endedWith !== null) {
|
||||||
|
const lower = raw.trim().toLowerCase()
|
||||||
|
if (lower !== 'restart' && lower !== 'undo') {
|
||||||
|
appendLines([{ kind: 'system', text: 'The story has ended. Type `restart` or `undo`.' }])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Engine-level meta-commands handled here so the engine stays pure.
|
// Engine-level meta-commands handled here so the engine stays pure.
|
||||||
const trimmed = raw.trim().toLowerCase()
|
const trimmed = raw.trim().toLowerCase()
|
||||||
if (trimmed === 'restart') {
|
if (trimmed === 'restart') {
|
||||||
@@ -105,6 +119,7 @@ if (!transcriptEl || !inputEl) {
|
|||||||
renderAll(state.transcript)
|
renderAll(state.transcript)
|
||||||
saveState(state)
|
saveState(state)
|
||||||
refreshChips()
|
refreshChips()
|
||||||
|
syncEndedUI()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (trimmed === 'undo') {
|
if (trimmed === 'undo') {
|
||||||
@@ -114,6 +129,7 @@ if (!transcriptEl || !inputEl) {
|
|||||||
appendLines([{ kind: 'system', text: '(undone)' }])
|
appendLines([{ kind: 'system', text: '(undone)' }])
|
||||||
saveState(state)
|
saveState(state)
|
||||||
refreshChips()
|
refreshChips()
|
||||||
|
syncEndedUI()
|
||||||
} else {
|
} else {
|
||||||
appendLines([{ kind: 'system', text: 'There is no further back.' }])
|
appendLines([{ kind: 'system', text: 'There is no further back.' }])
|
||||||
}
|
}
|
||||||
@@ -139,6 +155,7 @@ if (!transcriptEl || !inputEl) {
|
|||||||
document.dispatchEvent(new CustomEvent('halfstreet-toggle-theme'))
|
document.dispatchEvent(new CustomEvent('halfstreet-toggle-theme'))
|
||||||
}
|
}
|
||||||
refreshChips()
|
refreshChips()
|
||||||
|
syncEndedUI()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[halfstreet] dispatch error', err)
|
console.error('[halfstreet] dispatch error', err)
|
||||||
appendLines([{ kind: 'system', text: '[ The terminal hums and resets. ]' }])
|
appendLines([{ kind: 'system', text: '[ The terminal hums and resets. ]' }])
|
||||||
|
|||||||
Reference in New Issue
Block a user