feat(engine): read verb narrates item.readableText
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -212,3 +212,43 @@ describe('ambiguous → disambiguation flow', () => {
|
||||
expect(result.state.inventory.find((i) => i.id === 'iron-key')).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
function readWorld(): World {
|
||||
return {
|
||||
startingRoom: 'r',
|
||||
startingInventory: [],
|
||||
rooms: { r: { id: 'r', title: '[ R ]', descriptions: { firstVisit: '.', revisit: '.', examined: '.' }, exits: {}, items: [] } },
|
||||
items: {
|
||||
letter: { id: 'letter', names: ['letter'], short: 'a letter', long: 'A letter.', initialState: {}, takeable: true, readable: true, readableText: 'You loved Halfstreet, the letter says.' },
|
||||
rock: { id: 'rock', names: ['rock'], short: 'a rock', long: 'A rock.', initialState: {}, takeable: true },
|
||||
},
|
||||
encounters: {},
|
||||
endings: {
|
||||
true: { whenFlags: {}, narration: '' },
|
||||
wrong: { whenFlags: {}, narration: '' },
|
||||
bad: { whenFlags: {}, narration: '' },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
describe('read verb', () => {
|
||||
it('narrates readableText for a readable item in inventory', () => {
|
||||
const world = readWorld()
|
||||
let state = initialStateFor(world)
|
||||
state = { ...state, inventory: [{ id: 'letter', state: {} }] }
|
||||
const result = dispatch(state, {
|
||||
kind: 'verb-target', verb: 'read', target: { canonical: 'letter', raw: 'letter' },
|
||||
}, world)
|
||||
expect(result.appended.at(-1)?.text).toBe('You loved Halfstreet, the letter says.')
|
||||
})
|
||||
|
||||
it('errors politely on non-readable items', () => {
|
||||
const world = readWorld()
|
||||
let state = initialStateFor(world)
|
||||
state = { ...state, inventory: [{ id: 'rock', state: {} }] }
|
||||
const result = dispatch(state, {
|
||||
kind: 'verb-target', verb: 'read', target: { canonical: 'rock', raw: 'rock' },
|
||||
}, world)
|
||||
expect(result.appended.at(-1)?.text).toBe("There's nothing to read on it.")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -116,6 +116,7 @@ export function dispatch(state: GameState, command: ParsedCommand, world: World)
|
||||
if (command.verb === 'take') return handleTake(stateWithNoun, command.target.canonical, world)
|
||||
if (command.verb === 'drop') return handleDrop(stateWithNoun, command.target.canonical, world)
|
||||
if (command.verb === 'examine' || command.verb === 'look') return handleExamine(stateWithNoun, command.target.canonical, world)
|
||||
if (command.verb === 'read') return handleRead(stateWithNoun, command.target.canonical, world)
|
||||
return narrate(stateWithNoun, [{ kind: 'narration', text: `You're not sure how to ${command.verb} that.` }])
|
||||
}
|
||||
|
||||
@@ -262,3 +263,16 @@ function handleExamine(state: GameState, itemId: string, world: World): Dispatch
|
||||
if (!visible) return narrate(state, [{ kind: 'narration', text: 'You don\'t see anything like that.' }])
|
||||
return narrate(state, [{ kind: 'narration', text: item.long }])
|
||||
}
|
||||
|
||||
function handleRead(state: GameState, itemId: string, world: World): DispatchResult {
|
||||
const item = world.items[itemId]
|
||||
if (!item) return narrate(state, [{ kind: 'narration', text: "You don't see anything like that." }])
|
||||
const visible =
|
||||
state.inventory.find((i) => i.id === itemId) ||
|
||||
getItemsInRoom(state, world, state.location).includes(itemId)
|
||||
if (!visible) return narrate(state, [{ kind: 'narration', text: "You don't see anything like that." }])
|
||||
if (!item.readable || !item.readableText) {
|
||||
return narrate(state, [{ kind: 'narration', text: "There's nothing to read on it." }])
|
||||
}
|
||||
return narrate(state, [{ kind: 'narration', text: item.readableText }])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user