diff --git a/src/components/App/App.module.css b/src/components/App/App.module.css index 2a2ca8d..c5f0a59 100644 --- a/src/components/App/App.module.css +++ b/src/components/App/App.module.css @@ -16,12 +16,14 @@ overflow-y: auto; padding: 16px; padding-bottom: 0; + min-height: 16px; } .input { padding: 16px; padding-top: 0; position: relative; + left: -1px; font-weight: bold; } diff --git a/src/engine/Renderer.tsx b/src/engine/Renderer.tsx index bdd4583..8362734 100644 --- a/src/engine/Renderer.tsx +++ b/src/engine/Renderer.tsx @@ -6,19 +6,23 @@ import App from '../components/App/App'; import Game from "./Game"; import Parser from "./Parser"; import GameEvent, { GameEventCommand } from './types/GameEvent' +import RulesEngine from './RulesEngine'; export default class Renderer { private parser : Parser private game : Game + private rules : RulesEngine private output : GameEvent[] = [] - constructor(parser : Parser, game : Game) { + constructor(parser : Parser, game : Game, rules : RulesEngine) { this.parser = parser this.game = game + this.rules = rules } start() { + this.rules.gameStart() this.render() } diff --git a/src/engine/RulesEngine.ts b/src/engine/RulesEngine.ts index 28635e3..33b449e 100644 --- a/src/engine/RulesEngine.ts +++ b/src/engine/RulesEngine.ts @@ -1,12 +1,49 @@ import { ValidCommandDetails } from "./types/ParsedCommand"; +import Game from "./Game"; +import { EventEmitter } from "events"; +import printArea from "../utils/printArea" // This class allows for hooking up "global events" for things such as checking // victory conditions, acting when play begins, or other such things. These // event types are different from player actions, which are all considered // "command" events -export default class RulesEngine { +export default class RulesEngine extends EventEmitter{ + private game : Game + private lastLocation : string = '' + + constructor(game : Game) { + super() + + this.game = game + this.on('beforeCommand', () => {this.lastLocation = game.getState().player.location}) + this.on('afterCommand', () => { + if(this.lastLocation !== game.getState().player.location) + this.emit('locationChange') + }) + + this.on('locationChange', () => { + printArea(game.getCurrentRoom(), game.say.bind(game)) + }) + } + + gameStart() { + this.emit('gameStart', this.game) + this.emit('locationChange') + } + + // TODO: Potentially refactor to not use EventEmitter + // since that would maybe allow us to _cancel_ actions? runCommand(action: ValidCommandDetails) { + this.emit('beforeCommand', action, this.game) + + console.log('doing action') + this.emit('afterCommand', action, this.game) } + + onGameStart = (cb : (game : Game) => void) => this.on('gameStart', cb) + onBeforeCommand = (cb : (command : ValidCommandDetails, game : Game) => void) => this.on('beforeCommand', cb) + onAfterCommand = (cb : (command : ValidCommandDetails, game : Game) => void) => this.on('afterCommand', cb) + onLocationChange = (cb : (game : Game) => void) => this.on('locationChange', cb) } diff --git a/src/engine/types/GameState.ts b/src/engine/types/GameState.ts index 867d820..f4e5a2d 100644 --- a/src/engine/types/GameState.ts +++ b/src/engine/types/GameState.ts @@ -25,7 +25,9 @@ type ObjectID = string export type GameObject = { readonly type : ObjectType, readonly name : ObjectID, - readonly aliases : string[] + readonly aliases : string[], + readonly printableName?: string | undefined, + readonly description?: string } export type Direction = GameObject & { diff --git a/src/index.tsx b/src/index.tsx index 68bd57b..bb63977 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -5,9 +5,9 @@ import RulesEngine from './engine/RulesEngine' import { ObjectType, Room, Door } from './engine/types/GameState' let game = new Game() -let rules = new RulesEngine() +let rules = new RulesEngine(game) let parser = new Parser(game, rules) -let renderer = new Renderer(parser, game) +let renderer = new Renderer(parser, game, rules) parser.understand('look') .as('look') @@ -51,7 +51,8 @@ const entry : Room = { type: ObjectType.Room, name: 'entry', aliases: [], - neighbors: new Map() + neighbors: new Map(), + description: 'A tight corridor with yellow faded walls.' } const door : Door = { @@ -60,14 +61,16 @@ const door : Door = { aliases: ['white door'], neighbors: new Map(), locked: true, - key: 'brass key' + key: 'brass key', + description: 'A large white door with but a single keybole.' } const office : Room = { type: ObjectType.Room, name: 'office', aliases: [], - neighbors: new Map() + neighbors: new Map(), + description: 'An opulent office' } entry.neighbors.set('east', 'door') diff --git a/src/utils/capitalize.js b/src/utils/capitalize.js new file mode 100644 index 0000000..baa64d4 --- /dev/null +++ b/src/utils/capitalize.js @@ -0,0 +1,3 @@ +export default function capitalize(string) { + return string.slice(0,1).toUpperCase() + string.slice(1) +} \ No newline at end of file diff --git a/src/utils/printArea.js b/src/utils/printArea.js index 18c76f9..713d757 100644 --- a/src/utils/printArea.js +++ b/src/utils/printArea.js @@ -1,4 +1,6 @@ +import capitalize from "./capitalize" + export default function printArea(location, say) { - say(`**${location.name}**`) + say(`**${location.printableName || capitalize(location.name)}**`) say(location.description) }