/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;
}
}