/src/cell.ts
import Storable from './storable'; import { ID, generateID } from './id'; import { GameEvent, GameEventProperties, GameEventType } from './event'; import { GameObject, GameObjectProperties, GameObjectType } from './object'; import { GameAgent } from './agent'; import { Direction } from './direction'; import gs from './gamestate'; /* Cell A Cell is the basic spatial unit of the map. It has a title and a basic description and it contains any number of Objects, Events, and Agents. Upon entering a cell, the title and description are presented to the player, any ENTER events are fired, and the available Actions of all present Objects are enumerated and displayed. Upon leaving a cell, any EXIT events are fired. */ export interface CellProperties { x: number y: number id: ID title: string description: string events: GameEventProperties[] objects: ID[] exits: [boolean, boolean, boolean, boolean] // agents are not saved } export class Cell extends Storable { id: ID x: number y: number title: string description: string exits = [true, true, true, true]; events: Map<ID, GameEvent> objects: Map<ID, GameObject> agents: Map<ID, GameAgent> navigable: boolean saveProperties = ['x', 'y', 'id', 'title', 'description', 'exits'] constructor(x: number, y: number) { super(); this.id = generateID(); this.x = x; this.y = y; this.title = ''; this.description = ''; this.events = new Map(); this.objects = new Map(); this.navigable = false; } addObject(o: GameObject) { // ensure that this object is not already in the gamestate if (this.objects.has(o.id)) { throw new Error('Object already in cell: ' + o.id) } this.objects.set(o.id, o); } removeObject(o: GameObject) { if (this.objects.has(o.id)) { this.objects.delete(o.id); } } addEvent(e: GameEvent) { if (this.events.has(e.id)) { throw new Error('Event already in cell: ' + e.id); } this.events.set(e.id, e); } removeEvent(e: GameEvent) { if (this.events.has(e.id)) { this.events.delete(e.id); } } canMove(d: Direction): boolean { return this.exits[d]; } store() { return Object.assign(<CellProperties>super.store(), { objects: Array.from(this.objects).map( ([id, obj]) => id), events: Array.from(this.events).map( ([id, e]) => e.store()), }); } load(properties: CellProperties) { // x and y are ignored here - they are used only to address the // particular cell and load this data in this.id = properties.id; this.title = properties.title; this.description = properties.description; // At this point the objects should already be loaded in gamestate this.objects = new Map(); for (let id of properties.objects) { if (!gs.objects.has(id)) { throw new Error('Object not found in gamestate:' + id); } this.objects.set(id, gs.objects.get(id)); } this.events = new Map(); for (let event of properties.events) { const ge = new GameEvent(); ge.load(event); this.events.set(event.id, ge); } // We assume that since this cell was saved, it is navigable this.navigable = true; } }