103 lines
2.6 KiB
TypeScript
103 lines
2.6 KiB
TypeScript
/**
|
|
* Entity.ts contains the Entity class which is a base class that handles effects and
|
|
* containing items. It is the base class for Player and Scene.
|
|
*/
|
|
|
|
import type { Conditions, Item, EntityProperties } from "./types.ts";
|
|
|
|
export default class Entity<T extends EntityProperties> {
|
|
protected _conditions: Conditions<T>;
|
|
protected _properties: T;
|
|
protected _activeEffects: string[];
|
|
|
|
constructor(
|
|
properties: T,
|
|
conditions: Conditions<T>,
|
|
activeEffects: string[] = []
|
|
) {
|
|
this._conditions = conditions; // Conditional properties
|
|
this._properties = properties; // Base properties
|
|
this._activeEffects = activeEffects;
|
|
}
|
|
|
|
get activeEffects(): string[] {
|
|
return this._activeEffects;
|
|
}
|
|
|
|
set conditions(conditions: Conditions<T>) {
|
|
this._conditions = conditions;
|
|
}
|
|
|
|
get properties(): T {
|
|
return this._properties;
|
|
}
|
|
|
|
set properties(properties: T) {
|
|
this._properties = properties;
|
|
}
|
|
|
|
addEffect(effect: string): void {
|
|
this.activeEffects.push(effect);
|
|
}
|
|
|
|
// Player effects should be applied first, then scene effects should be applied.
|
|
// This will mean that scene effects will take precedence over player effects.
|
|
// Returns base properties with conditional properties applied.
|
|
applyEffects(
|
|
activePlayerEffects: string[],
|
|
activeSceneEffects: string[]
|
|
): T {
|
|
const playerSet = new Set(activePlayerEffects);
|
|
const sceneSet = new Set(activeSceneEffects);
|
|
|
|
const effects = this._conditions.effects.filter(({ name, source }) => {
|
|
const set = source === "player" ? playerSet : sceneSet;
|
|
return set.has(name);
|
|
});
|
|
|
|
const appliedProperties = { ...this._properties };
|
|
|
|
// for each effect, apply changed properties to the
|
|
for (const effect of effects) {
|
|
Object.assign(appliedProperties, effect.properties);
|
|
}
|
|
|
|
return appliedProperties;
|
|
}
|
|
|
|
// Generate a description of the contained items
|
|
description(items: Item[]): string | null {
|
|
if (items.length === 0) return null;
|
|
|
|
const vowels = ["a", "e", "i", "o", "u"];
|
|
const description = items
|
|
.map(({ name }, i) => {
|
|
let anItem = `${vowels.includes(name[0]) ? "an" : "a"} ${name}`;
|
|
|
|
// if we have more than one item, and this is the last item...
|
|
if (i > 1 && i + 1 === items.length) {
|
|
anItem = `and ${anItem}`;
|
|
}
|
|
|
|
return anItem;
|
|
})
|
|
.join(", ");
|
|
|
|
return description;
|
|
}
|
|
|
|
// Checks if a given effect exists as an active effect on this entity
|
|
hasActiveEffect(effect: string): boolean {
|
|
return this._activeEffects.includes(effect);
|
|
}
|
|
|
|
// Removes an effect if it is active on this entity
|
|
removeEffect(effect: string): void {
|
|
const idx = this._activeEffects.findIndex((e) => e === effect);
|
|
|
|
if (idx >= 0) {
|
|
this._activeEffects.splice(idx, 1);
|
|
}
|
|
}
|
|
}
|