Initial area

main
Ashelyn Dawn 4 years ago
parent 9b2b267e20
commit 59377ed38f

@ -50,7 +50,6 @@ export default function Help({parentRef}) {
<li>take [thing]</li>
<li>drop [thing]</li>
<li>open [thing]</li>
<li>close [thing]</li>
</ul>
</>
}

@ -59,7 +59,7 @@ export default function Map() {
{itemsInRoom.length > 0 && (<>
<p>You {(playerLocation === roomName) ? 'see' : 'recall seeing'} the following items here:</p>
<ul>
{itemsInRoom.map(({name}) => <li>{name}</li>)}
{itemsInRoom.map(({name, printableName}) => <li>{printableName || name}</li>)}
</ul>
</>)}
</>)

@ -110,7 +110,7 @@ export default function Text({promptVisible: promptEnabled, handleCommand, showR
<div ref={outputRef} onScroll={() => setCurrentScroll(outputRef.current?.scrollTop)} className={styles.output + (!!currentMenu ? ' ' + styles.noMouse : '')}>
{finalMessages.map((message, i) => {
if(message.type === 'message')
return <ReactMarkdown key={i}>{message.message}</ReactMarkdown>
return <ReactMarkdown escapeHtml={false} key={i}>{message.message}</ReactMarkdown>
if(message.type === 'command')
return <p key={i} className={styles.command}>{message.command}</p>

@ -127,12 +127,16 @@ export default class Game {
createProperty(key : string, value : any) {
let state = this.getState()
if(state.properties.has(key))
if(this.hasProperty(key))
throw new Error(`Game prop ${key} has already been defined`)
state.properties.set(key, value)
}
hasProperty(key : string) : boolean {
return this.getState().properties.has(key)
}
setProperty(key : string, value : any) {
let state = this.getState()
@ -181,14 +185,19 @@ export default class Game {
}
addItem(name : string, description : string, location : string, carryable : boolean = false) : Draft<Item> {
let item : Item = {
let item : Draft<Item> = {
type: ObjectType.Item,
name, aliases: [], printableName: name, description,
location,
seen: location === this.getCurrentRoom()?.name,
seen: false,
carryable
}
if(location === this.getCurrentRoom()?.name){
item.seen = true
item.lastKnownLocation = location
}
let state = this.getState()
state.items.set(item.name, item)

@ -13,15 +13,12 @@ export default function(parser : Parser, rules : RulesEngine, game : Game) {
const current = game.getCurrentRoom()
const neighborName = current?.neighbors.get(direction.name)
let lookingAt = game.findObjectByName(neighborName, ObjectType.Room)
|| game.findObjectByName(neighborName, ObjectType.Door)
if(!lookingAt){
console.warn(`Unable to find object ${neighborName}`)
game.say(`You cannot go ${direction.name}`)
return;
}
if(!lookingAt)
throw new Error(`You cannot go ${direction.name}`)
let room = lookingAt
if(lookingAt.type === ObjectType.Door) {
@ -42,4 +39,4 @@ export default function(parser : Parser, rules : RulesEngine, game : Game) {
game.getState().player.location = room.name
})
}
}

@ -1,7 +1,4 @@
import {game, rules} from '../engine'
import { ObjectType, Item } from '../engine/types/GameState'
import { Draft } from 'immer'
import { Phase } from './2-phases-and-hints'
import {game} from '../engine'
/**
* Cabin
@ -12,38 +9,6 @@ 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.
`)
rules.on('beforePrintItems', () => {
const state = game.getState()
const playerLocation = state.player.location
const flashlightLocation = state.items.get('flashlight')?.location
if(flashlightLocation !== 'inventory' && playerLocation === 'cabin')
throw new Error('You cannot make out much more without light.')
})
// After picking up flashlight, update game phase
rules.onAfterCommand(() => {
const state = game.getState()
const flashlightLocation = state.items.get('flashlight')?.location
const wrenchExists = state.items.has('wrench')
if(flashlightLocation === 'inventory' && !wrenchExists){
if(game.getProperty('gamePhase') < Phase.hasFlashlight)
game.setProperty('gamePhase', Phase.hasFlashlight)
game.addItem('wrench', 'Just generally useful for repairs and adjustments to the various mechanical parts of the ship.', 'cabin', true)
}
})
// After picking up wrench, update game phase
rules.onAfterCommand(command => {
if(command.verb.name !== 'take' || command.subject?.name !== 'wrench')
return
if(game.getProperty('gamePhase') < Phase.gotWrench)
game.setProperty('gamePhase', Phase.gotWrench)
})
/**
* Washroom
*/
@ -65,49 +30,6 @@ cupboard.aliases.push('cupboard')
cupboard.aliases.push('cupboard door')
cupboard.aliases.push('cabinet door')
rules.onBeforeCommand(command => {
if(command.verb.name !== 'openItem') return;
if(command.subject?.name !== 'cabinet') return;
const wrench = game.findObjectByName('wrench', ObjectType.Item) as Item
const item = game.findObjectByName('cabinet', ObjectType.Item) as Draft<Item>
item.description = `
A small metal cupboard beneath the sing. It is currently open.
At the bottom of the cupboard you see a loose metal panel you might be able to fit through.
`
const sinkPanel = game.addItem('floor panel', 'A loose metal panel in the bathroom floor.', 'bathroom')
sinkPanel.aliases.push('panel')
sinkPanel.aliases.push('loose panel')
if(wrench?.location === 'inventory')
game.setProperty('gamePhase', Phase.gotWrench)
else
game.setProperty('gamePhase', Phase.checkedUnderSink)
// Prevent normal command execution
throw new Error('You open the sink cupboard, revealing a loose metal panel in the bathroom floor.')
})
rules.onBeforeCommand(command => {
if(command.verb.name !== 'openItem') return;
if(command.subject?.name !== 'floor panel') return;
const wrench = game.findObjectByName('wrench', ObjectType.Item) as Item
if(wrench?.location !== 'inventory')
throw new Error(`It's bolted down pretty tightly - you'll need a tool to open this panel.`)
game.setNeighbor('bathroom', 'down', 'docking')
if(game.getProperty('gamePhase') < Phase.openedSinkPanel)
game.setProperty('gamePhase', Phase.openedSinkPanel)
const panel = game.findObjectByName('floor panel', ObjectType.Item) as Draft<Item>
panel.printableName = 'hole in the floor'
throw new Error('It takes you a few minutes, but eventually you pull up the floor panel. You should be able to get down to the docking bay from here.')
})
/**
* Comms
@ -179,11 +101,14 @@ the ceiling you can see light coming from the bathroom.
// Regular hallways
game.setNeighbor('cabin', 'aft', 'bathroom')
game.setNeighbor('cabin', 'port', 'comms')
game.setNeighbor('comms', 'port', 'medbay')
game.setNeighbor('comms', 'fore', 'bridge')
game.setNeighbor('medbay', 'aft', 'stairupper')
game.setNeighbor('stairupper', 'down', 'stairlower')
game.setNeighbor('stairlower', 'fore', 'mainframe')
game.setNeighbor('mainframe', 'starboard', 'engine')
game.setNeighbor('engine', 'starboard', 'docking')
// DEBUG hallways
// game.setNeighbor('bathroom', 'down', 'docking')
// game.setNeighbor('cabin', 'port', 'comms')
// game.setNeighbor('comms', 'port', 'medbay')

@ -0,0 +1,104 @@
import {game, rules} from '../engine'
import { ObjectType, Item } from '../engine/types/GameState'
import { Draft } from 'immer'
import { Phase } from './2-phases-and-hints'
/**
* Small message about not having flashlight in cabin
*/
rules.on('beforePrintItems', () => {
const state = game.getState()
const playerLocation = state.player.location
const flashlightLocation = state.items.get('flashlight')?.location
if(flashlightLocation !== 'inventory' && playerLocation === 'cabin')
throw new Error('You cannot make out much more without light.')
})
/**
* Update hint after getting the flashlight
*/
rules.onAfterCommand(() => {
const state = game.getState()
const flashlightLocation = state.items.get('flashlight')?.location
const wrenchExists = state.items.has('wrench')
if(flashlightLocation === 'inventory' && !wrenchExists){
if(game.getProperty('gamePhase') < Phase.hasFlashlight)
game.setProperty('gamePhase', Phase.hasFlashlight)
game.addItem('wrench', 'Just generally useful for repairs and adjustments to the various mechanical parts of the ship.', 'cabin', true)
}
})
/**
* Update hint after getting wrench
*/
rules.onAfterCommand(command => {
if(command.verb.name !== 'take' || command.subject?.name !== 'wrench')
return
const panel = game.findObjectByName('floor panel', ObjectType.Item) as Item
if(game.getProperty('gamePhase') < Phase.gotWrench && panel !== null)
game.setProperty('gamePhase', Phase.gotWrench)
})
/**
* Don't allow the flashlight to be dropped
*/
rules.onBeforeCommand(command => {
if(command.verb.name === 'drop' && command.subject?.name === 'flashlight')
throw new Error(`If you put down the flashlight, you will likely not be able to find it again in the dark.`)
})
/**
* When opening the cabinet, insert floor panel
*/
rules.onBeforeCommand(command => {
if(command.verb.name !== 'openItem') return;
if(command.subject?.name !== 'cabinet') return;
const wrench = game.findObjectByName('wrench', ObjectType.Item) as Item
const item = game.findObjectByName('cabinet', ObjectType.Item) as Draft<Item>
item.description = `
A small metal cupboard beneath the sing. It is currently open.
At the bottom of the cupboard you see a loose metal panel you might be able to fit through.
`
const sinkPanel = game.addItem('floor panel', 'A loose metal panel in the bathroom floor.', 'bathroom')
sinkPanel.aliases.push('panel')
sinkPanel.aliases.push('loose panel')
if(wrench?.location === 'inventory')
game.setProperty('gamePhase', Phase.gotWrench)
else
game.setProperty('gamePhase', Phase.checkedUnderSink)
// Prevent normal command execution
throw new Error('You open the sink cupboard, revealing a loose metal panel in the bathroom floor.')
})
/**
* Handle opening floor panel
*/
rules.onBeforeCommand(command => {
if(command.verb.name !== 'openItem') return;
if(command.subject?.name !== 'floor panel') return;
const wrench = game.findObjectByName('wrench', ObjectType.Item) as Item
if(wrench?.location !== 'inventory')
throw new Error(`It's bolted down pretty tightly - you'll need a tool to open this panel.`)
game.setNeighbor('bathroom', 'down', 'docking')
if(game.getProperty('gamePhase') < Phase.openedSinkPanel)
game.setProperty('gamePhase', Phase.openedSinkPanel)
const panel = game.findObjectByName('floor panel', ObjectType.Item) as Draft<Item>
panel.printableName = 'hole in the floor'
throw new Error('It takes you a few minutes, but eventually you pull up the floor panel. You should be able to get down to the docking bay from here.')
})

@ -0,0 +1,103 @@
import {game, rules} from '../engine'
import { Phase } from './2-phases-and-hints'
/**
* Intro
*/
rules.onGameStart(() => {
game.say(`A loud blaring alarm slowly drags you out of your sleep. For a moment you consider rolling over and returning to your rest, but you know that's a bad idea. The ship's alarm wouldn't be going off for no reason, and most of the reasons it would be going off are deadly.`)
game.say(`You sit up, rub the sleep from your eyes and glance around. Primary lights are off, but you can make out darkened silhouettes from the emergency light in the washroom. The computer panel in the wall is also darkened, so the engine must have stopped for long enough that the ship's primary power banks are drained.`)
game.say(`Then you notice the worst part - the security doors to the comms room are shut, sealing you off from the rest of the ship.`)
game.pause()
game.clear()
game.say(`You groan.`)
game.pause()
game.say(`Looks like this job just got a lot more complicated.`)
game.pause()
game.clear()
})
/**
* Upon picking up the flashlight
*/
rules.onAfterCommand(command => {
if(command.verb.name !== 'take' || command.subject?.name !== 'flashlight')
return
if(game.hasProperty('pickedUpFlashlight'))
return
else
game.createProperty('pickedUpFlashlight', true)
game.clear()
game.say(`You click the light on and glance around, sighing. The Dawn has certainly seen better days. She flies just fine, but assuming you survive you'll definitely have to use the money from this job to finally replace all the rusty patches with new parts.`)
game.say(`It figures that the easy delivery would turn out to be the one where you have the most problems. All you had to do was take a few sealed boxes to the far side of the galaxy and then fly back - no sneaking, no lying, no fighting or anything!`)
game.pause()
game.clear()
game.say(`(Of course the people you were delivering it to are outlaws, but who's going to turn their nose up on the perfect job just because of a few laws?)`)
game.say(`A sharp pain in your chest quickly pulls you back to the present - the CO<sub>2</sub> scrubber must have stopped when the ship dropped out of hyperspace. Looks like that's gotta be priority number one, unless you want to die before you can get home and collect your pay!`)
game.pause()
game.clear()
rules.printArea()
})
/**
* Upon picking up wrench
*/
rules.onAfterCommand(command => {
if(command.verb.name !== 'take' || command.subject?.name !== 'wrench')
return
if(game.hasProperty('pickedUpWrench'))
return
else
game.createProperty('pickedUpWrench', true)
game.clear()
game.say(`You suppose this kind of equipment failure is inevitable, although it's a bit strange since you had the engine checked last week. It was the same cousin who checked the engine as who told you about this job actually.`)
game.say(`"Listen, I know you don't want to get involved in the synth trade but it's just one supply run and they can pay you a lot for it." Wren had said. "I'd do it myself but the Aurora's a flying collection of scrap at this point, and you know how I hate having to find new pilots."`)
game.pause()
game.clear()
game.say(`You had groaned at that. "And you think the Ashen Dawn is in any better condition? That's why I brought her to you, numbskull."`)
game.say(`Wren's grin was wide, but knowing. "Listen, after I fix her up let me introduce you to my client Rosalyn - it's a simple supply run, and would be a good shakedown for Dawn after the repairs."`)
game.pause()
game.clear()
game.say(`It looks like taking a simple job as your first shakedown flight was a good idea after all, although when you get out of this you're going to have some serious words with Wren about the quality of his work the last few visits.`)
game.say(`You're not sure if your throat is actually growing scratchy, or if it's all in your head . . . either way you'd better get the CO<sub>2</sub> scrubber back online.`)
game.pause()
game.clear()
rules.printArea()
})
/**
* Dropping from bathroom to docking bay for the first time
*/
rules.onAfterCommand(command => {
// When going down from the bathroom . . .
if(command.verb.name !== 'go' || command.subject?.name !== 'down' || game.getCurrentRoom()?.name !== 'bathroom')
return
// Only do once
if(game.getProperty('gamePhase') >= Phase.droppedBelow)
return
else
game.setProperty('gamePhase', Phase.droppedBelow)
game.clear()
game.say(`As you lower yourself down into the cargo bay you're struck by how empty it looks. Normally this storage bay would have a lot more general-purpose supplies, but you had to clear it out to make room for this delivery. Since you've dropped the cargo and were on your way to get paid, they're no longer here to fill that space.`)
game.pause()
game.say(`You weren't permitted to know what was in the boxes you delivered. "Wares to be sold in the outer markets," Rosalyn said when you asked. "The less you know the less you have to worry." `)
game.say(`You weren't even sure how heavy or light the boxes were - she arranged crews for loading and unloading ahead of time, and the time requirements for delivery were just close enough you hadn't dared stop to investigate along the way. It really was as easy as Wren had said it would be...`)
game.pause()
game.clear()
})

@ -1,34 +1,11 @@
import {game, rules, renderer} from './engine/'
import {game, renderer} from './engine/'
import './gameSetup/0-item-visibility'
import './gameSetup/1-rooms'
import './gameSetup/1-rooms-and-items'
import './gameSetup/2-phases-and-hints'
import './gameSetup/3-game-rules'
import './gameSetup/4-story-hooks'
game.saveDraft()
// Print description on game start
rules.onGameStart(() => {
game.say(`A loud blaring alarm slowly drags you out of your sleep. For a moment you consider rolling over and returning to your rest, but you know that's a bad idea. The ship's alarm wouldn't be going off for no reason, and most of the reasons it would be going off are deadly.`)
game.say(`You sit up, rub the sleep from your eyes and glance around. Primary lights are off, but you can make out darkened silhouettes from the emergency light in the washroom. The computer panel in the wall is also darkened, so the engine must have stopped for long enough that the ship's primary power banks are drained.`)
game.say(`Then you notice the worst part - the security doors to the comms room are shut, sealing you off from the rest of the ship.`)
game.pause()
game.clear()
game.say(`You groan.`)
game.pause()
game.say(`Looks like this job just got a lot more complicated.`)
game.pause()
game.clear()
})
rules.onBeforeCommand(command => {
if(command.verb.name !== 'openItem') return
if(command.subject?.name !== 'block') return;
console.log('opening block')
throw new Error()
})
renderer.start(document.getElementById('root'))

Loading…
Cancel
Save