forum-logic/src/classes/display/actor.js

110 lines
2.8 KiB
JavaScript

import { displayNumber } from '../../util/helpers.js';
export class Actor {
/**
* @param {string} name
* @param {Scene} scene
* @param {boolean} options.announce
* @param {boolean} options.hide
*/
constructor(name, scene, options = {}) {
if (!scene) throw new Error('An actor without a scene!');
this.name = name;
this.scene = scene;
this.callbacks = new Map();
this.status = scene.addDisplayValue(`${this.name} status`);
this.status.set('Created');
this.values = new Map();
this.valueFunctions = new Map();
this.active = 0;
this.options = options;
scene?.registerActor(this);
}
activate() {
this.active += 1;
this.scene?.sequence?.activate(this.name);
}
async deactivate() {
if (!this.active) {
throw new Error(`${this.name} is not active, can not deactivate`);
}
this.active -= 1;
await this.scene?.sequence?.deactivate(this.name);
}
async send(dest, action, detail) {
await action.log(this, dest, detail ? JSON.stringify(detail) : '');
await dest.recv(this, action, detail);
return this;
}
async recv(src, action, detail) {
const cb = this.callbacks.get(action.name);
if (!cb) {
throw new Error(
`[${this.scene?.name} actor ${this.name} does not have a callback registered for ${action.name}`,
);
}
await cb(src, detail);
return this;
}
on(action, cb) {
this.callbacks.set(action.name, cb);
return this;
}
setStatus(status) {
this.status.set(status);
return this;
}
async addComputedValue(label, fn) {
this.values.set(label, this.scene?.addDisplayValue(`${this.name} ${label}`));
if (fn) {
this.valueFunctions.set(label, fn);
await this.computeDisplayValues();
}
return this;
}
async setDisplayValue(label, value) {
if (typeof value === 'function') {
return this.addComputedValue(label, value);
}
const displayValue = this.values.get(label) ?? this.scene?.addDisplayValue(`${this.name} ${label}`);
if (value !== displayValue.get()) {
await this.scene?.sequence?.log(`note over ${this.name} : ${label} = ${displayNumber(value)}`);
}
displayValue.set(value);
this.values.set(label, displayValue);
return this;
}
/**
* @param {(label: string, value) => {}} cb
*/
async computeDisplayValues(cb) {
for (const [label, fn] of this.valueFunctions.entries()) {
const value = fn();
console.log('computeDisplay', {
label, value, fn, cb,
});
await this.setDisplayValue(label, value);
if (cb) {
cb(label, value);
}
}
}
getValuesMap() {
return new Map(Array.from(this.values.entries())
.map(([key, displayValue]) => [key, {
name: displayValue.getName(),
value: displayValue.get(),
}]));
}
}