Handle multiple objects with same alias - as long as they're not in the same location

main
Ashelyn Dawn 4 years ago
parent dac4e86855
commit fdc3dbea39

@ -227,11 +227,11 @@ export default class Game {
b.neighbors.set(opposite, a.name)
}
findObjectByName(name : string | undefined | null, type : ObjectType) : GameObject | null {
if(!name) return null;
findObjectsByName(name : string | undefined | null, type : ObjectType) : GameObject[] {
if(!name) return [];
if(/^the /.test(name))
return this.findObjectByName(name.replace(/^the /, ''), type)
return this.findObjectsByName(name.replace(/^the /, ''), type)
let lowerCaseName = name.toLocaleLowerCase()
@ -254,17 +254,36 @@ export default class Game {
break
}
const objects = [...collection!.values()]
const objects : GameObject[] = [...collection!.values()]
const matching = [
// Exact name
...objects.filter((object) => lowerCaseName === object.name.toLocaleLowerCase()),
// Aliases
...objects.filter(({aliases}) => aliases.map(a => a.toLocaleLowerCase()).includes(lowerCaseName))
]
// Filter duplicates
const seenDict : any = {}
return matching.filter(({name}) => {
if(seenDict[name])
return false
seenDict[name] = name
return true
})
}
findObjectByName(name : string | undefined | null, type : ObjectType) : GameObject | null {
const candidates = this.findObjectsByName(name, type)
const exactMatch = objects.find((object) => lowerCaseName === object.name.toLocaleLowerCase())
if(exactMatch)
return exactMatch
if(candidates.length < 1)
return null
const aliasMatch = objects.find(({aliases}) => aliases.map(a => a.toLocaleLowerCase()).includes(lowerCaseName))
if(aliasMatch)
return aliasMatch
if(candidates.length > 1)
console.warn(`Duplicate objects found for name ${name}`)
return null
return candidates[0]
}
findObjectsInRoom(name : string | undefined) : Draft<Item> [] {

@ -21,7 +21,8 @@ export default class Parser {
this.game.outputCommand(rawCommand)
this.game.saveDraft()
const timer = delay(200)
const timerDelay = 100
const timer = delay(timerDelay)
try {
renderer.hidePrompt()
@ -29,8 +30,9 @@ export default class Parser {
await this.runCommand(rawCommand)
let end = window.performance.now()
if(end - start > 200)
if(end - start > timerDelay)
console.warn(`Command execution took ${end - start}ms`)
await timer
} catch (err) {
await timer
@ -39,7 +41,6 @@ export default class Parser {
else if(err.message)
game.say(err.message)
else{
game.say('An unknown error occured')
console.error(err)
}
} finally {

@ -10,5 +10,6 @@ export default [
require('./help'),
require('./options'),
require('./map'),
require('./hint')
require('./hint'),
require('./start')
]

@ -5,6 +5,14 @@ import { ObjectType, Door } from "../types/GameState";
import { Draft } from "immer";
export default function(parser : Parser, rules : RulesEngine, game : Game) {
parser.understand('openItem')
.as('open [item]')
.as('open [item] with [item|object]')
rules.onCommand('openItem', () => {
game.say(`You don't believe that can be opened!`)
})
parser.understand('openDoor')
.as('open [door]')
@ -23,13 +31,4 @@ export default function(parser : Parser, rules : RulesEngine, game : Game) {
const mutable = game.findObjectByName(door.name, ObjectType.Door);
(mutable as Draft<Door>).open = true
})
parser.understand('openItem')
.as('open [item]')
.as('open [item] with [item|object]')
rules.onCommand('openItem', () => {
game.say(`You don't believe that can be opened!`)
})
}

@ -0,0 +1,14 @@
import Parser from "../Parser";
import RulesEngine from "../RulesEngine";
import Game from "../Game";
export default function(parser : Parser, rules : RulesEngine, game : Game) {
parser.understand('start')
.as('start [item]')
.as('restart [item]')
.as('turn on [item]')
rules.onCommand('start', command => {
game.say(`That isn't something you can turn on.`)
})
}

@ -75,8 +75,8 @@ export default class ParsedCommand {
let object : GameObject | null = null
for(const noun of nouns) {
let gameObject = game.findObjectByName(noun.name, noun.itemType)
if(!gameObject || (gameObject.type === ObjectType.Item && !((gameObject as Item).seen)))
let possibleObjects = game.findObjectsByName(noun.name, noun.itemType).filter(gameObject => (gameObject.type !== ObjectType.Item || ((gameObject as Item).seen)))
if(possibleObjects.length < 1)
return {
isValid: false,
command: this,
@ -84,10 +84,10 @@ export default class ParsedCommand {
severity: ParsingErrorSeverity.NoSuchObject
}
// TODO: Optionally print "the" depending on if the original
// command name had one at the beginning (don't print the the book)
// (but also don't do "you cannot see heart of the cards")
if(!game.isVisible(gameObject))
let visibleObjects = possibleObjects.filter(gameObject => game.isVisible(gameObject))
if(visibleObjects.length < 1) {
const gameObject = possibleObjects[0]
return {
isValid: false,
command: this,
@ -98,7 +98,9 @@ export default class ParsedCommand {
})()}`,
severity: ParsingErrorSeverity.NotVisible
}
}
const gameObject = visibleObjects[0]
if(noun.sentencePosition === NounPosition.Subject)
subject = gameObject
else

@ -6,6 +6,13 @@ A dark and dingy room with a single bunk bed along the starboard side.
The washroom is to the aft, with the comms room to port.
`)
const cabinDoor = game.addItem('cabin door', `
Large, metal retractable doors designed to keep air from escaping through them.
`, 'cabin')
cabinDoor.aliases = ['security doors', 'door', 'doors']
cabinDoor.printableName = 'security doors'
game.addRoom('bathroom', 'Washroom', `
Tight, cramped, but serviceable. The _Dawn_ was really only meant for a crew
of one or two, and that is no more evident than here.
@ -48,6 +55,14 @@ event it would still save your life . . . at least you hope it would.
The stairwell is to the aft, with the comms room to starboard.
`)
const medDoor = game.addItem('med door', `
Large, metal retractable doors designed to keep air from escaping through them.
`, 'medbay')
medDoor.aliases = ['security doors', 'door', 'doors']
medDoor.printableName = 'security doors'
game.addRoom('stairupper', 'Upper Stairwell', `
A large window in the aft wall shows the view of an unknown star system
in the distance. It's almost peaceful to gaze at, if it didn't remind
@ -114,8 +129,8 @@ game.setNeighbor('stairupper', 'down', 'stairlower')
game.setNeighbor('stairlower', 'fore', 'mainframe')
game.setNeighbor('mainframe', 'starboard', 'engine')
game.setNeighbor('engine', 'starboard', 'docking')
game.setNeighbor('cabin', 'port', 'comms')
game.setNeighbor('medbay', 'starboard', 'comms')
// DEBUG hallways
// game.setNeighbor('bathroom', 'down', 'docking')
// game.setNeighbor('cabin', 'port', 'comms')
// game.setNeighbor('comms', 'port', 'medbay')
game.setNeighbor('bathroom', 'down', 'docking')

@ -1,4 +1,4 @@
import {game, rules} from '../engine'
import {game, rules, parser} from '../engine'
import { ObjectType, Item } from '../engine/types/GameState'
import { Draft } from 'immer'
import { Phase } from './2-phases-and-hints'
@ -15,6 +15,47 @@ rules.on('beforePrintItems', () => {
throw new Error('You cannot make out much more without light.')
})
/**
* Do not allow going west from cabin
*/
rules.onBeforeCommand(command => {
const playerLocation = game.getCurrentRoom()?.name
if(command.verb.name !== 'go' || playerLocation !== 'cabin' || command.subject?.name !== 'port')
return;
throw new Error(`The security doors have sealed - you're either going to need to restart the mainframe or find a way to force these open before you can access the comms room.`)
})
/**
* Do not allow going east from medbay until opened
*/
rules.onBeforeCommand(command => {
const playerLocation = game.getCurrentRoom()?.name
if(command.verb.name !== 'go' || playerLocation !== 'medbay' || command.subject?.name !== 'starboard')
return;
if(game.getProperty('gamePhase') < Phase.openedDoor)
throw new Error(`The security doors have sealed - you're either going to need to restart the mainframe or find a way to force these open before you can access the comms room.`)
})
/**
* Do not allow opening security doors
*/
rules.onBeforeCommand(command => {
const playerLocation = game.getCurrentRoom()?.name
if(command.verb.name !== 'openItem' || !command.subject?.aliases.includes('security doors'))
return;
if(playerLocation === 'cabin')
parser.runCommand('go port')
if(playerLocation === 'medbay')
parser.runCommand('go starboard')
// Do not print regular command output
throw new Error()
})
/**
* Update hint after getting the flashlight
*/
@ -112,3 +153,35 @@ rules.onAfterCommand(command => {
if(game.getProperty('gamePhase') < Phase.fixedLifeSupport)
game.say(`_Focus_, you remind yourself. _The engine is pretty but I've gotta fix that CO<sub>2</sub> filter before I'll have time to bother with this._`)
})
/**
* Turn on flashlight
*/
rules.onBeforeCommand(command => {
if(command.verb.name !== 'start' || command.subject?.name !== 'flashlight') return;
const light = game.findObjectByName('flashlight', ObjectType.Item) as Item
if(light.location === 'inventory')
throw new Error('It is already on')
else{
parser.runCommand(`take ${light.name}`)
throw new Error()
}
})
/**
* Cannot turn on engine
*/
rules.onBeforeCommand(command => {
if(command.verb.name !== 'start' || command.subject?.name !== 'engine') return;
const currentPhase = game.getProperty('gamePhase')
if(currentPhase < Phase.fixedLifeSupport)
throw new Error(`You probably should restart the CO<sub>2</sub> filter before worrying about the engine.`)
if(currentPhase < Phase.examinedMainframe)
throw new Error(`As far as you can tell the engine _itself_ is fine, perhaps something is wrong with the mainframe's control systems?`)
throw new Error(`The mainframe's engine control systems have been damaged and will have to be repaired before the engine can be started.`)
})

@ -3,7 +3,6 @@ import Game from "../engine/Game"
export function printLocDescription(game : Game) {
const location = game.getCurrentRoom()!
console.log('printing')
game.say(`**${capitalize(location.printableName)}**`)
game.say(location.description!)

Loading…
Cancel
Save