1
0
Fork 0

lint: fix most lint errors

This commit is contained in:
Sean Sube 2022-10-16 13:47:56 -05:00
parent 6a6506dab6
commit b92eb5bed6
60 changed files with 372 additions and 439 deletions

View File

@ -337,8 +337,7 @@ module.exports = {
"MemberExpression[optional=true]",
"IfStatement[alternate.type='IfStatement']",
"UnaryExpression[operator='!']",
"BinaryExpression[operator='==='][right.value=true]",
"BinaryExpression[operator='!==']"
"BinaryExpression[operator='==='][right.value=true]"
],
"no-return-await": "error",
"no-sequences": "error",

View File

@ -1,8 +1,8 @@
import { Box, Text, useFocus } from 'ink';
import TextInputModule from 'ink-text-input';
import * as React from 'react';
import { LegacyModule } from '../../util/types.js';
import { LegacyModule } from '../../util/types.js';
import { InputProps } from '../shared.js';
const { default: TextInput } = (TextInputModule as unknown as LegacyModule<typeof TextInputModule>);

View File

@ -3,8 +3,8 @@ import { Box, Text, useFocus } from 'ink';
import SelectInputModule from 'ink-select-input';
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { LegacyModule } from '../../util/types.js';
import { LegacyModule } from '../../util/types.js';
import { SHORTCUT_TABS, ShortcutKeys, ShortcutProps } from '../shared.js';
const { default: SelectInput } = (SelectInputModule as unknown as LegacyModule<typeof SelectInputModule>);

View File

@ -1,10 +1,10 @@
import { InvalidArgumentError, isNil } from '@apextoaster/js-utils';
import { InvalidArgumentError, isNone } from '@apextoaster/js-utils';
import { BaseOptions, Container, Module } from 'noicejs';
import { BunyanLogger } from './logger/BunyanLogger.js';
import { INJECT_EVENT, INJECT_LOCALE } from './module/index.js';
import { BrowserModule } from './module/BrowserModule.js';
import { CoreModule } from './module/CoreModule.js';
import { INJECT_EVENT, INJECT_LOCALE } from './module/index.js';
import { NodeModule } from './module/NodeModule.js';
import { EventBus } from './service/event/index.js';
import { LocaleService } from './service/locale/index.js';
@ -47,7 +47,7 @@ export async function main(args: Array<string>): Promise<number> {
// create DI modules
const modules = arg.module.map((it) => {
const ctor = LOADED_MODULES.get(it);
if (isNil(ctor)) {
if (isNone(ctor)) {
throw new InvalidArgumentError('module not found');
}
const module = new ctor();

View File

@ -1,15 +1,13 @@
import { mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { ActorSource, isActor } from '../../../model/entity/Actor.js';
import { ActorSource } from '../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { assertActor } from '../../../util/script/assert.js';
export async function SignalActorGet(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
if (this.source === ActorSource.PLAYER) {
if (actor.source === ActorSource.PLAYER) {
const item = mustExist(context.item);
await context.state.show(context.source, 'actor.signal.get.item', { item });
}

View File

@ -1,21 +1,18 @@
import { mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { decrementKey, getKey } from '../../../util/collection/map.js';
import { STAT_DAMAGE, STAT_HEALTH } from '../../../util/constants.js';
import { assertActor } from '../../../util/script/assert.js';
export async function SignalActorHit(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const attacker = mustExist(context.actor);
const item = mustExist(context.item);
await context.state.show(context.source, 'actor.signal.hit.item', {
actor: this,
actor,
attacker,
item,
});
@ -23,21 +20,21 @@ export async function SignalActorHit(this: ScriptTarget, context: ScriptContext)
const maxDamage = getKey(item.stats, STAT_DAMAGE, 1) + getKey(attacker.stats, STAT_DAMAGE, 0);
const damage = context.random.nextInt(maxDamage);
const [stats, health] = decrementKey(this.stats, STAT_HEALTH, damage);
await context.state.update(this, { stats });
const [stats, health] = decrementKey(actor.stats, STAT_HEALTH, damage);
await context.state.update(actor, { stats });
if (health > 0) {
await context.state.show(context.source, 'actor.signal.hit.health', { actor: this, damage, health });
await context.state.show(context.source, 'actor.signal.hit.health', { actor, damage, health });
} else {
// drop inventory
const room = mustExist(context.room);
for (const dropItem of this.items) {
for (const dropItem of actor.items) {
await context.state.move({
moving: dropItem,
source: this,
source: actor,
target: room,
}, context);
}
await context.state.show(context.source, 'actor.signal.hit.dead', { actor: this, damage });
await context.state.show(context.source, 'actor.signal.hit.dead', { actor, damage });
}
}

View File

@ -1,31 +1,28 @@
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { getKey } from '../../../util/collection/map.js';
import { SIGNAL_LOOK, STAT_HEALTH } from '../../../util/constants.js';
import { assertActor } from '../../../util/script/assert.js';
export async function SignalActorLook(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const health = getKey(this.stats, STAT_HEALTH, 0);
const health = getKey(actor.stats, STAT_HEALTH, 0);
if (this === context.actor) {
await context.state.show(context.source, 'actor.signal.look.self', { actor: this });
if (actor === context.actor) {
await context.state.show(context.source, 'actor.signal.look.self', { actor });
if (health > 0) {
await context.state.show(context.source, 'actor.signal.look.health', { actor: this, health });
await context.state.show(context.source, 'actor.signal.look.health', { actor, health });
}
for (const item of this.items) {
for (const item of actor.items) {
await context.script.invoke(item, SIGNAL_LOOK, context);
}
} else {
await context.state.show(context.source, 'actor.signal.look.seen', { actor: this });
await context.state.show(context.source, 'actor.signal.look.seen', { actor });
}
if (health <= 0) {
await context.state.show(context.source, 'actor.signal.look.dead', { actor: this });
await context.state.show(context.source, 'actor.signal.look.dead', { actor });
}
}

View File

@ -1,41 +1,39 @@
import { isNil, mustExist } from '@apextoaster/js-utils';
import { isNone, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { ActorSource, isActor } from '../../../model/entity/Actor.js';
import { ActorSource } from '../../../model/entity/Actor.js';
import { LocaleContext } from '../../../service/locale/index.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { StateSource } from '../../../util/actor/index.js';
import { getKey } from '../../../util/collection/map.js';
import { STAT_HEALTH, STAT_SCORE } from '../../../util/constants.js';
import { assertActor } from '../../../util/script/assert.js';
import { getVerbScripts } from '../../../util/script/index.js';
export async function SignalActorStep(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const health = getKey(this.stats, STAT_HEALTH, 0);
const health = getKey(actor.stats, STAT_HEALTH, 0);
if (health <= 0) {
if (this.source === ActorSource.PLAYER) {
await context.state.show(context.source, 'actor.signal.step.dead', { actor: this });
await context.state.quit('quit.dead', { actor: this }, [STAT_SCORE]);
if (actor.source === ActorSource.PLAYER) {
await context.state.show(context.source, 'actor.signal.step.dead', { actor });
await context.state.quit('quit.dead', { actor }, [STAT_SCORE]);
}
return;
}
if (isNil(context.command)) {
context.logger.debug({ target: this }, 'actor has nothing to do');
if (isNone(context.command)) {
context.logger.debug({ target: actor }, 'actor has nothing to do');
return;
}
const { command } = context;
const showContext: LocaleContext = {
actor: this,
actor,
command,
};
const source: StateSource = {
actor: this,
actor,
room: mustExist(context.room),
};
@ -45,7 +43,7 @@ export async function SignalActorStep(this: ScriptTarget, context: ScriptContext
return context.state.show(context.source, 'actor.signal.step.verb.missing', showContext);
}
if (this.source === ActorSource.PLAYER) {
if (actor.source === ActorSource.PLAYER) {
if (command.targets.length > 0) {
await context.state.show(context.source, 'actor.signal.step.verb.target', showContext);
} else {
@ -53,5 +51,5 @@ export async function SignalActorStep(this: ScriptTarget, context: ScriptContext
}
}
return context.script.invoke(this, command.verb, context);
return context.script.invoke(actor, command.verb, context);
}

View File

@ -1,15 +1,12 @@
import { mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { getKey, incrementKey } from '../../../util/collection/map.js';
import { STAT_DAMAGE, STAT_HEALTH } from '../../../util/constants.js';
import { assertActor } from '../../../util/script/assert.js';
export async function SignalActorUse(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const item = mustExist(context.item);
@ -18,12 +15,12 @@ export async function SignalActorUse(this: ScriptTarget, context: ScriptContext)
const damageRoll = context.random.nextInt(maxDamage);
const healthRoll = context.random.nextInt(maxHealth);
const [stats, health] = incrementKey(this.stats, STAT_HEALTH, healthRoll - damageRoll);
const [stats, health] = incrementKey(actor.stats, STAT_HEALTH, healthRoll - damageRoll);
await context.state.update(this, { stats });
await context.state.update(actor, { stats });
await context.state.show(context.source, 'actor.use.item.health', {
actor: this,
actor,
item,
health,
});

View File

@ -1,9 +1,8 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { WorldEntity } from '../../../../model/entity/index.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext } from '../../../../service/script/index.js';
import { getKey } from '../../../../util/collection/map.js';
import { STAT_HEALTH } from '../../../../util/constants.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* Looking at the character of Lucy should:
@ -11,19 +10,17 @@ import { STAT_HEALTH } from '../../../../util/constants.js';
* - note her condition
*/
export async function SignalActorLookLucy(this: WorldEntity, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
await context.state.show(context.source, 'actor.signal.look.seen', { actor: this });
await context.state.show(context.source, 'actor.signal.look.seen', { actor });
const health = getKey(this.stats, STAT_HEALTH, 0);
const health = getKey(actor.stats, STAT_HEALTH, 0);
switch (true) {
case (health <= 0):
return context.state.show(context.source, 'actor.signal.look.dead', { actor: this });
return context.state.show(context.source, 'actor.signal.look.dead', { actor });
case (health <= 10):
return context.state.show(context.source, 'actor.signal.look.pale', { actor: this });
return context.state.show(context.source, 'actor.signal.look.pale', { actor });
default:
return context.state.show(context.source, 'actor.signal.look.healthy', { actor: this });
return context.state.show(context.source, 'actor.signal.look.healthy', { actor });
}
}

View File

@ -1,7 +1,6 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { getKey } from '../../../../util/collection/map.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* The maids should:
@ -10,17 +9,15 @@ import { getKey } from '../../../../util/collection/map.js';
* - wake up after a few turns
*/
export async function SignalActorLookMaid(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
const actor = assertActor(this);
const behavior = context.random.nextFloat();
context.logger.debug({ behavior }, 'received room event from state');
const turn = getKey(this.stats, 'awaken', 10);
const turn = getKey(actor.stats, 'awaken', 10);
if (context.step.turn <= turn) {
return context.state.show(context.source, 'actor.signal.look.asleep', { actor: this });
return context.state.show(context.source, 'actor.signal.look.asleep', { actor });
} else {
return context.state.show(context.source, 'actor.signal.look.awake', { actor: this });
return context.state.show(context.source, 'actor.signal.look.awake', { actor });
}
}

View File

@ -1,22 +1,19 @@
import { doesExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { setKey } from '../../../../util/collection/map.js';
import { STAT_HEALTH } from '../../../../util/constants.js';
import { assertActor } from '../../../../util/script/assert.js';
import { SignalActorStep } from '../ActorStep.js';
export async function SignalActorStepHGStepmother(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
const actor = assertActor(this);
const deathTurn = this.stats.get('death-turn');
const deathTurn = actor.stats.get('death-turn');
if (doesExist(deathTurn) && context.step.turn > deathTurn) {
const stats = setKey(this.stats, STAT_HEALTH, 0);
await context.state.update(this, { stats });
const stats = setKey(actor.stats, STAT_HEALTH, 0);
await context.state.update(actor, { stats });
}
return SignalActorStep.call(this, context);
return SignalActorStep.call(actor, context);
}

View File

@ -1,6 +1,5 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* The Cheshire Cat should:
@ -8,10 +7,8 @@ import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js
* - enter the world on the Nth turn
* - remove itself from the world on the Mth turn
*/
export async function SignalBehaviorAliceCat(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
export async function SignalBehaviorAliceCat(this: ScriptTarget, _context: ScriptContext): Promise<void> {
assertActor(this);
// TODO: behavior
}

View File

@ -1,6 +1,5 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* The guests in the Queen's croquet party should:
@ -9,10 +8,8 @@ import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js
* - play croquet once on the grounds
* - gather around the Cheshire Cat
*/
export async function SignalBehaviorAliceGuest(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
export async function SignalBehaviorAliceGuest(this: ScriptTarget, _context: ScriptContext): Promise<void> {
assertActor(this);
// TODO: behavior
}

View File

@ -1,6 +1,5 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* The hedgehogs in the croquet ground should:
@ -8,10 +7,8 @@ import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js
* - move into a random room when hit with the flamingo
* - start to wander if they have not been hit in the last turn
*/
export async function SignalBehaviorAliceHedgehog(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
export async function SignalBehaviorAliceHedgehog(this: ScriptTarget, _context: ScriptContext): Promise<void> {
assertActor(this);
// TODO: behavior
}

View File

@ -1,17 +1,17 @@
import { doesExist, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { makeCommand } from '../../../../model/Command.js';
import { ActorSource, isActor } from '../../../../model/entity/Actor.js';
import { ActorSource } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { randomItem } from '../../../../util/collection/array.js';
import { getKey } from '../../../../util/collection/map.js';
import { VERB_HIT, VERB_MOVE, VERB_WAIT } from '../../../../util/constants.js';
import { assertActor } from '../../../../util/script/assert.js';
export const WANDER_RATE = 0.25;
export async function SignalBehaviorEnemy(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
const actor = assertActor(this);
const behavior = context.random.nextFloat();
context.logger.debug({ behavior }, 'received room event from state');
@ -20,15 +20,15 @@ export async function SignalBehaviorEnemy(this: ScriptTarget, context: ScriptCon
// attack player if possible
const player = room.actors.find((it) => it.source === ActorSource.PLAYER);
const attack = getKey(this.stats, 'attack', 1.00);
const attack = getKey(actor.stats, 'attack', 1.00);
if (behavior < attack && doesExist(player)) {
context.logger.debug({ player }, 'attacking visible player');
return context.behavior.queue(this, makeCommand(VERB_HIT, player.meta.id));
return context.behavior.queue(actor, makeCommand(VERB_HIT, player.meta.id));
}
// or randomly move
const portals = room.portals.filter((it) => it.dest.length > 0);
const wander = getKey(this.stats, 'wander', 0.25);
const wander = getKey(actor.stats, 'wander', WANDER_RATE);
if (behavior < wander && portals.length > 0) {
const portal = randomItem(portals, context.random);
context.logger.debug({
@ -36,8 +36,8 @@ export async function SignalBehaviorEnemy(this: ScriptTarget, context: ScriptCon
portalCount: portals.length,
}, 'moving through random portal');
return context.behavior.queue(this, makeCommand(VERB_MOVE, portal.meta.id));
return context.behavior.queue(actor, makeCommand(VERB_MOVE, portal.meta.id));
}
return context.behavior.queue(this, makeCommand(VERB_WAIT));
return context.behavior.queue(actor, makeCommand(VERB_WAIT));
}

View File

@ -1,17 +1,15 @@
import { doesExist, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { makeCommand } from '../../../../model/Command.js';
import { ACTOR_TYPE, isActor } from '../../../../model/entity/Actor.js';
import { ACTOR_TYPE } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { randomItem } from '../../../../util/collection/array.js';
import { VERB_MOVE } from '../../../../util/constants.js';
import { assertActor } from '../../../../util/script/assert.js';
import { SignalBehaviorEnemy } from './BehaviorEnemy.js';
export async function SignalBehaviorFlee(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
const actor = assertActor(this);
const behavior = context.random.nextFloat();
context.logger.debug({ behavior }, 'received room event from state');
@ -19,7 +17,7 @@ export async function SignalBehaviorFlee(this: ScriptTarget, context: ScriptCont
const room = mustExist(context.room);
// move away from the flagged actors
const flee = this.flags.get('flee');
const flee = actor.flags.get('flee');
if (doesExist(flee)) {
const actors = await context.state.find({
meta: {
@ -34,9 +32,9 @@ export async function SignalBehaviorFlee(this: ScriptTarget, context: ScriptCont
if (actors.length > 0) {
// pick a portal and move
const portal = randomItem(room.portals, context.random);
return context.behavior.queue(this, makeCommand(VERB_MOVE, portal.meta.name));
return context.behavior.queue(actor, makeCommand(VERB_MOVE, portal.meta.name));
}
}
return SignalBehaviorEnemy.call(this, context);
return SignalBehaviorEnemy.call(actor, context);
}

View File

@ -1,10 +1,9 @@
import { isNil, mustExist } from '@apextoaster/js-utils';
import { isNone, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { makeCommand } from '../../../../model/Command.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { VERB_MOVE } from '../../../../util/constants.js';
import { assertActor } from '../../../../util/script/assert.js';
import { SignalBehaviorEnemy } from './BehaviorEnemy.js';
/**
@ -13,25 +12,23 @@ import { SignalBehaviorEnemy } from './BehaviorEnemy.js';
* - follow the queen
*/
export async function SignalBehaviorFollow(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
const actor = assertActor(this);
const behavior = context.random.nextFloat();
context.logger.debug({ behavior }, 'received room event from state');
const room = mustExist(context.room);
const pathKey = this.flags.get('follow');
const pathKey = actor.flags.get('follow');
if (isNil(pathKey)) {
return SignalBehaviorEnemy.call(this, context);
if (isNone(pathKey)) {
return SignalBehaviorEnemy.call(actor, context);
}
const path = room.flags.get(pathKey);
if (isNil(path)) {
return SignalBehaviorEnemy.call(this, context);
if (isNone(path)) {
return SignalBehaviorEnemy.call(actor, context);
}
// follow the path if possible
return context.behavior.queue(this, makeCommand(VERB_MOVE, path));
return context.behavior.queue(actor, makeCommand(VERB_MOVE, path));
}

View File

@ -1,10 +1,9 @@
import { mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { makeCommand } from '../../../../model/Command.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { VERB_MOVE, VERB_WAIT } from '../../../../util/constants.js';
import { assertActor } from '../../../../util/script/assert.js';
import { matchIdSegments } from '../../../../util/string.js';
/**
@ -16,20 +15,18 @@ import { matchIdSegments } from '../../../../util/string.js';
* - give blood to Lucy
*/
export async function SignalBehaviorDraculaQuincey(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
const actor = assertActor(this);
const behavior = context.random.nextFloat();
context.logger.debug({ behavior }, 'received room event from state');
const room = mustExist(context.room);
if (matchIdSegments(room.meta.id, 'intro-quincey') && context.step.turn > 10) {
return context.behavior.queue(this, makeCommand(VERB_MOVE));
return context.behavior.queue(actor, makeCommand(VERB_MOVE));
}
// if in the hallway with player, greet and move to Lucy
// if with Lucy and player, give her blood
return context.behavior.queue(this, makeCommand(VERB_WAIT));
return context.behavior.queue(actor, makeCommand(VERB_WAIT));
}

View File

@ -1,10 +1,10 @@
import { doesExist, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { makeCommand } from '../../../../model/Command.js';
import { ACTOR_TYPE, ActorSource, isActor } from '../../../../model/entity/Actor.js';
import { ACTOR_TYPE, ActorSource } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { VERB_MOVE, VERB_WAIT } from '../../../../util/constants.js';
import { assertActor } from '../../../../util/script/assert.js';
import { matchIdSegments } from '../../../../util/string.js';
/**
@ -19,9 +19,7 @@ import { matchIdSegments } from '../../../../util/string.js';
*/
// eslint-disable-next-line complexity
export async function SignalBehaviorDraculaVanHelsing(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
const actor = assertActor(this);
const room = mustExist(context.room);
const actors = await context.state.find({
@ -34,27 +32,27 @@ export async function SignalBehaviorDraculaVanHelsing(this: ScriptTarget, contex
const player = actors.find((it) => it.source === ActorSource.PLAYER);
if (doesExist(player) && matchIdSegments(room.meta.id, 'room-gate')) {
context.logger.debug({ actor: this }, 'intro trigger');
context.logger.debug({ actor }, 'intro trigger');
}
if (doesExist(player) && matchIdSegments(room.meta.id, 'room-house-back')) {
context.logger.debug({ actor: this }, 'back of house trigger');
context.logger.debug({ actor }, 'back of house trigger');
}
if (doesExist(player) && matchIdSegments(room.meta.id, 'room-house-dining')) {
context.logger.debug({ actor: this }, 'dining room trigger');
context.logger.debug({ actor }, 'dining room trigger');
}
if (doesExist(player) && matchIdSegments(room.meta.id, 'room-house-lucy')) {
context.logger.debug({ actor: this }, 'Lucy\'s bedroom trigger');
context.logger.debug({ actor }, 'Lucy\'s bedroom trigger');
}
// TODO: follow VH path
const path = room.flags.get('path-van-helsing');
if (doesExist(path)) {
context.logger.debug({ actor: this }, 'following VH path');
return context.behavior.queue(this, makeCommand(VERB_MOVE, path));
context.logger.debug({ actor }, 'following VH path');
return context.behavior.queue(actor, makeCommand(VERB_MOVE, path));
}
return context.behavior.queue(this, makeCommand(VERB_WAIT));
return context.behavior.queue(actor, makeCommand(VERB_WAIT));
}

View File

@ -1,6 +1,5 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* The father character should:
@ -8,10 +7,8 @@ import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js
* - lead the children into the woods
* - go back to the house and wait
*/
export async function SignalBehaviorHGFather(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
export async function SignalBehaviorHGFather(this: ScriptTarget, _context: ScriptContext): Promise<void> {
assertActor(this);
// if turn < A, wander normally
// if turn > A, wait for children outside

View File

@ -1,16 +1,13 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* The witch character should:
*
* - push the non-player sibling into the cage
*/
export async function SignalBehaviorHGWitch(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
export async function SignalBehaviorHGWitch(this: ScriptTarget, _context: ScriptContext): Promise<void> {
assertActor(this);
// TODO: behavior
}

View File

@ -1,6 +1,5 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* The hunter character should:
@ -8,10 +7,8 @@ import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js
* - head to grandma's house
* - eat any cake along the way
*/
export async function SignalBehaviorRRHHunter(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
export async function SignalBehaviorRRHHunter(this: ScriptTarget, _context: ScriptContext): Promise<void> {
assertActor(this);
// TODO: behavior
}

View File

@ -1,6 +1,5 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* The first wolf from the forest should:
@ -10,10 +9,8 @@ import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js
* - eat red riding hood and teleport her into the wolf's belly
* - empty the wolf's belly on death
*/
export async function SignalBehaviorRRHWolfForest(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
export async function SignalBehaviorRRHWolfForest(this: ScriptTarget, _context: ScriptContext): Promise<void> {
assertActor(this);
// TODO: behavior
}

View File

@ -1,16 +1,13 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { isActor } from '../../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { assertActor } from '../../../../util/script/assert.js';
/**
* The second wolf from the roof should:
*
* - fall into the water trough after sausage water has been added
*/
export async function SignalBehaviorRRHWolfRoof(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('target must be an actor');
}
export async function SignalBehaviorRRHWolfRoof(this: ScriptTarget, _context: ScriptContext): Promise<void> {
assertActor(this);
// TODO: behavior
}

View File

@ -1,17 +1,14 @@
import { doesExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isItem } from '../../../model/entity/Item.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { assertItem } from '../../../util/script/assert.js';
export async function SignalItemLook(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isItem(this)) {
throw new ScriptTargetError('script target must be an item');
}
const item = assertItem(this);
if (doesExist(context.actor) && context.actor.items.includes(this)) {
await context.state.show(context.source, 'item.signal.look.held', { item: this });
if (doesExist(context.actor) && context.actor.items.includes(item)) {
await context.state.show(context.source, 'item.signal.look.held', { item });
} else {
await context.state.show(context.source, 'item.signal.look.seen', { item: this });
await context.state.show(context.source, 'item.signal.look.seen', { item });
}
}

View File

@ -1,19 +1,16 @@
import { isNil } from '@apextoaster/js-utils';
import { isNone } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { WorldEntityType } from '../../../model/entity/index.js';
import { isItem } from '../../../model/entity/Item.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { splitChain, SPLIT_LIMIT } from '../../../util/template/SplitChain.js';
import { assertItem } from '../../../util/script/assert.js';
import { SPLIT_LIMIT, splitChain } from '../../../util/template/SplitChain.js';
export async function SignalItemReplace(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isItem(this)) {
throw new ScriptTargetError('script target must be an item');
}
const item = assertItem(this);
const replaceStr = this.flags.get('replace');
if (isNil(replaceStr)) {
return context.state.show(context.source, 'item.replace.missing', { item: this });
const replaceStr = item.flags.get('replace');
if (isNone(replaceStr)) {
return context.state.show(context.source, 'item.replace.missing', { item });
}
// TODO: use join helper and respect normal ordering of and/or groups
@ -30,8 +27,8 @@ export async function SignalItemReplace(this: ScriptTarget, context: ScriptConte
for (const group of replaceGroups) {
const [type, id] = group.split(':');
const entity = await context.state.create(id, type as WorldEntityType, context.source);
await context.state.show(context.source, 'item.replace.entity', { entity, item: this });
await context.state.show(context.source, 'item.replace.entity', { entity, item });
}
await context.state.show(context.source, 'item.replace.done', { item: this });
await context.state.show(context.source, 'item.replace.done', { item });
}

View File

@ -1,9 +1,6 @@
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isItem } from '../../../model/entity/Item.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { assertItem } from '../../../util/script/assert.js';
export async function SignalItemStep(this: ScriptTarget, _context: ScriptContext): Promise<void> {
if (!isItem(this)) {
throw new ScriptTargetError('script target must be an item');
}
assertItem(this);
}

View File

@ -1,11 +1,8 @@
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isItem } from '../../../model/entity/Item.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { assertItem } from '../../../util/script/assert.js';
export async function SignalItemUse(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isItem(this)) {
throw new ScriptTargetError('script target must be an item');
}
const item = assertItem(this);
await context.state.show(context.source, 'item.use.any', { item: this });
await context.state.show(context.source, 'item.use.any', { item });
}

View File

@ -1,31 +1,28 @@
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isPortal } from '../../../model/entity/Portal.js';
import { ROOM_TYPE } from '../../../model/entity/Room.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { getPortalStats } from '../../../util/entity/index.js';
import { assertPortal } from '../../../util/script/assert.js';
export async function SignalPortalLook(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isPortal(this)) {
throw new ScriptTargetError('script target must be a portal');
const portal = assertPortal(this);
await context.state.show(context.source, 'portal.signal.look.seen', { portal });
if (portal.dest.length === 0) {
return context.state.show(context.source, 'portal.signal.look.dest.missing', { portal });
}
await context.state.show(context.source, 'portal.signal.look.seen', { portal: this });
if (this.dest.length === 0) {
return context.state.show(context.source, 'portal.signal.look.dest.missing', { portal: this });
}
const { closed } = getPortalStats(this);
const { closed } = getPortalStats(portal);
if (closed) {
return context.state.show(context.source, 'portal.signal.look.closed', { portal: this });
return context.state.show(context.source, 'portal.signal.look.closed', { portal });
}
const [room] = await context.state.find({
meta: {
id: this.dest,
id: portal.dest,
},
type: ROOM_TYPE,
});
return context.state.show(context.source, 'portal.signal.look.dest.room', { portal: this, room });
return context.state.show(context.source, 'portal.signal.look.dest.room', { portal, room });
}

View File

@ -1,28 +1,25 @@
import { doesExist, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isPortal } from '../../../model/entity/Portal.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { setKey } from '../../../util/collection/map.js';
import { STAT_LOCKED } from '../../../util/constants.js';
import { assertPortal } from '../../../util/script/assert.js';
import { matchIdSegments } from '../../../util/string.js';
export async function SignalPortalUse(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isPortal(this)) {
throw new ScriptTargetError('script target must be a portal');
}
const portal = assertPortal(this);
const item = mustExist(context.item);
const key = item.flags.get('key');
// if item is key, unlock
if (doesExist(key)) {
if (matchIdSegments(this.meta.id, key)) {
const stats = setKey(this.stats, STAT_LOCKED, 0);
await context.state.update(this, { stats });
await context.state.show(context.source, 'portal.use.key.unlock', { item, portal: this });
if (matchIdSegments(portal.meta.id, key)) {
const stats = setKey(portal.stats, STAT_LOCKED, 0);
await context.state.update(portal, { stats });
await context.state.show(context.source, 'portal.use.key.unlock', { item, portal });
} else {
await context.state.show(context.source, 'portal.use.key.wrong', { item, portal: this });
await context.state.show(context.source, 'portal.use.key.wrong', { item, portal });
}
}

View File

@ -1,22 +1,19 @@
import { ScriptTargetError } from '../../../../error/ScriptTargetError.js';
import { ACTOR_TYPE } from '../../../../model/entity/Actor.js';
import { isPortal } from '../../../../model/entity/Portal.js';
import { ScriptContext, ScriptTarget } from '../../../../service/script/index.js';
import { assertPortal } from '../../../../util/script/assert.js';
import { SignalPortalLook } from '../PortalLook.js';
/**
* Describe the room on the other side, and whether it contains one of the siblings.
*/
export async function SignalPortalLookHGOven(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isPortal(this)) {
throw new ScriptTargetError('script target must be a portal');
}
const portal = assertPortal(this);
await SignalPortalLook.call(this, context);
await SignalPortalLook.call(portal, context);
const actors = await context.state.find({
room: {
id: this.meta.id,
id: portal.meta.id,
},
type: ACTOR_TYPE,
});

View File

@ -1,19 +1,17 @@
import { doesExist, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isRoom, ROOM_TYPE } from '../../../model/entity/Room.js';
import { ROOM_TYPE } from '../../../model/entity/Room.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { setKey } from '../../../util/collection/map.js';
import { assertRoom } from '../../../util/script/assert.js';
export async function SignalRoomEnter(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isRoom(this)) {
throw new ScriptTargetError('script target must be a room');
}
const room = assertRoom(this);
// if room has scene flag and actor does not
const actor = mustExist(context.actor);
const sceneKey = `scene-${this.meta.id}`;
const sceneRoom = this.flags.get('scene');
const sceneKey = `scene-${room.meta.id}`;
const sceneRoom = room.flags.get('scene');
if (doesExist(sceneRoom) && actor.flags.has(sceneKey) === false) {
// teleport actor to scene room

View File

@ -1,16 +1,13 @@
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isRoom } from '../../../model/entity/Room.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { SIGNAL_LOOK } from '../../../util/constants.js';
import { assertRoom } from '../../../util/script/assert.js';
export async function SignalRoomLook(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isRoom(this)) {
throw new ScriptTargetError('script target must be a room');
}
const room = assertRoom(this);
await context.state.show(context.source, 'room.signal.look.seen', { room: this });
await context.state.show(context.source, 'room.signal.look.seen', { room });
for (const actor of this.actors) {
for (const actor of room.actors) {
if (actor === context.actor) {
continue;
}
@ -18,11 +15,11 @@ export async function SignalRoomLook(this: ScriptTarget, context: ScriptContext)
await context.script.invoke(actor, SIGNAL_LOOK, context);
}
for (const item of this.items) {
for (const item of room.items) {
await context.script.invoke(item, SIGNAL_LOOK, context);
}
for (const portal of this.portals) {
for (const portal of room.portals) {
await context.script.invoke(portal, SIGNAL_LOOK, context);
}
}

View File

@ -1,9 +1,6 @@
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isRoom } from '../../../model/entity/Room.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { assertRoom } from '../../../util/script/assert.js';
export async function SignalRoomStep(this: ScriptTarget, _context: ScriptContext): Promise<void> {
if (!isRoom(this)) {
throw new ScriptTargetError('script target must be a room');
}
assertRoom(this);
}

View File

@ -1,23 +1,20 @@
import { isNil, mustExist } from '@apextoaster/js-utils';
import { isNone, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { isItem } from '../../../model/entity/Item.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { head } from '../../../util/collection/array.js';
import { createFuzzyMatcher, indexEntity } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorDrop(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const command = mustExist(context.command);
const room = mustExist(context.room);
const results = await context.state.find({
actor: {
id: this.meta.id,
id: actor.meta.id,
},
meta: {
name: head(command.targets),
@ -29,17 +26,17 @@ export async function VerbActorDrop(this: ScriptTarget, context: ScriptContext):
});
const moving = indexEntity(results, command.index, isItem);
if (isNil(moving)) {
if (isNone(moving)) {
return context.state.show(context.source, 'actor.verb.drop.type', { command });
}
if (this.items.includes(moving) === false) {
if (actor.items.includes(moving) === false) {
return context.state.show(context.source, 'actor.verb.drop.owner', { command, item: moving });
}
return context.state.move({
moving,
source: this,
source: actor,
target: room,
}, context);
}

View File

@ -1,26 +1,23 @@
import { defaultWhen, isNone, lengthOf, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { isItem } from '../../../model/entity/Item.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { head } from '../../../util/collection/array.js';
import { setKey } from '../../../util/collection/map.js';
import { findActorSlots } from '../../../util/entity/find.js';
import { createFuzzyMatcher, indexEntity } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
import { hasText, matchIdSegments } from '../../../util/string.js';
export async function VerbActorEquip(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const command = mustExist(context.command);
const [targetName, targetSlot] = command.targets;
const results = await context.state.find({
actor: {
id: this.meta.id,
id: actor.meta.id,
},
meta: {
name: targetName,
@ -41,13 +38,13 @@ export async function VerbActorEquip(this: ScriptTarget, context: ScriptContext)
return context.state.show(context.source, 'actor.verb.equip.slot.invalid', { item, slot: slotName });
}
const validSlots = findActorSlots(this, slotName);
const validSlots = findActorSlots(actor, slotName);
if (lengthOf(validSlots) === 0) {
return context.state.show(context.source, 'actor.verb.equip.slot.missing', { item, slot: slotName });
}
const slot = head(validSlots);
const slots = setKey(this.slots, slot, item.meta.id);
await context.state.update(this, { slots });
const slots = setKey(actor.slots, slot, item.meta.id);
await context.state.update(actor, { slots });
return context.state.show(context.source, 'actor.verb.equip.item', { item, slot });
}

View File

@ -1,20 +1,16 @@
import { isNil, mustExist } from '@apextoaster/js-utils';
import { isNone, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { head } from '../../../util/collection/array.js';
import { SIGNAL_HIT } from '../../../util/constants.js';
import { findActorSlots, findSlotItem } from '../../../util/entity/find.js';
import { createFuzzyMatcher, indexEntity } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorHit(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
// eslint-disable-next-line @typescript-eslint/no-this-alias
const actor = this;
const command = mustExist(context.command);
const room = mustExist(context.room);
@ -29,18 +25,18 @@ export async function VerbActorHit(this: ScriptTarget, context: ScriptContext):
});
const target = indexEntity(results, command.index, isActor);
if (isNil(target)) {
if (isNone(target)) {
return context.state.show(context.source, 'actor.verb.hit.type', { command });
}
if (this === target) {
if (actor === target) {
return context.state.show(context.source, 'actor.verb.hit.self', { command });
}
const [slot] = findActorSlots(this, 'weapon');
const [slot] = findActorSlots(actor, 'weapon');
const item = findSlotItem(actor, slot);
if (isNil(item)) {
if (isNone(item)) {
return context.state.show(context.source, 'actor.verb.hit.item', { target });
}

View File

@ -1,21 +1,18 @@
import { doesExist, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { head } from '../../../util/collection/array.js';
import { SIGNAL_LOOK } from '../../../util/constants.js';
import { createFuzzyMatcher } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorLook(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const room = mustExist(context.room);
const sourceContext = {
...context,
actor: this,
actor,
};
const command = mustExist(context.command);

View File

@ -1,7 +1,6 @@
import { doesExist, isNil, mustExist, NotFoundError } from '@apextoaster/js-utils';
import { doesExist, isNone, mustExist, NotFoundError } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { ActorSource, isActor } from '../../../model/entity/Actor.js';
import { ActorSource } from '../../../model/entity/Actor.js';
import { isPortal } from '../../../model/entity/Portal.js';
import { isRoom, ROOM_TYPE } from '../../../model/entity/Room.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
@ -10,11 +9,10 @@ import { setKey } from '../../../util/collection/map.js';
import { SIGNAL_LOOK } from '../../../util/constants.js';
import { getPortalStats } from '../../../util/entity/index.js';
import { indexEntity } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorMove(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
// find the new room
const command = mustExist(context.command);
@ -30,7 +28,7 @@ export async function VerbActorMove(this: ScriptTarget, context: ScriptContext):
});
const targetPortal = indexEntity(portals, command.index, isPortal);
if (isNil(targetPortal)) {
if (isNone(targetPortal)) {
return context.state.show(context.source, 'actor.verb.move.missing', { command });
}
@ -48,17 +46,17 @@ export async function VerbActorMove(this: ScriptTarget, context: ScriptContext):
const targetRoom = indexEntity(rooms, command.index, isRoom);
if (!isRoom(targetRoom)) {
context.logger.warn({ actor: this, command, rooms, targetPortal }, 'destination room not found');
context.logger.warn({ actor, command, rooms, targetPortal }, 'destination room not found');
throw new NotFoundError('destination room not found');
}
await context.state.show(context.source, 'actor.verb.move.portal', {
actor: this,
actor,
portal: targetPortal,
});
// leader movement flags
const pathKey = this.flags.get('leader');
const pathKey = actor.flags.get('leader');
if (doesExist(pathKey)) {
const flags = setKey(currentRoom.flags, pathKey, targetPortal.meta.id);
await context.state.update(currentRoom, { flags });
@ -66,13 +64,13 @@ export async function VerbActorMove(this: ScriptTarget, context: ScriptContext):
// move the actor and focus
await context.state.move({
moving: this,
moving: actor,
source: currentRoom,
target: targetRoom,
}, context);
if (this.source === ActorSource.PLAYER) {
context.logger.debug({ actor: this, room: targetRoom }, 'player entered room');
if (actor.source === ActorSource.PLAYER) {
context.logger.debug({ actor, room: targetRoom }, 'player entered room');
await context.script.invoke(targetRoom, SIGNAL_LOOK, context);
}
}

View File

@ -1,17 +1,14 @@
import { mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { isPortal, PORTAL_TYPE } from '../../../model/entity/Portal.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { getKey, setKey } from '../../../util/collection/map.js';
import { SIGNAL_LOOK, STAT_CLOSED } from '../../../util/constants.js';
import { createFuzzyMatcher } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorOpen(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
assertActor(this);
const command = mustExist(context.command);

View File

@ -1,17 +1,15 @@
import { mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { ACTOR_TYPE, isActor } from '../../../model/entity/Actor.js';
import { isPortal, PORTAL_TYPE } from '../../../model/entity/Portal.js';
import { isRoom, ROOM_TYPE } from '../../../model/entity/Room.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { getPortalStats } from '../../../util/entity/index.js';
import { createFuzzyMatcher } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorPush(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
assertActor(this);
const command = mustExist(context.command);

View File

@ -1,15 +1,13 @@
import { mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { isItem, ITEM_TYPE } from '../../../model/entity/Item.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { SIGNAL_REPLACE } from '../../../util/constants.js';
import { createFuzzyMatcher } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorReplace(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
assertActor(this);
// find the target
const command = mustExist(context.command);
@ -23,7 +21,7 @@ export async function VerbActorReplace(this: ScriptTarget, context: ScriptContex
type: ITEM_TYPE,
});
if (!isItem(item)) {
if (isItem(item) === false) {
return context.state.show(context.source, 'actor.verb.replace.missing', { command });
}

View File

@ -1,17 +1,14 @@
import { mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { ShowVolume } from '../../../util/actor/index.js';
import { head } from '../../../util/collection/array.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorSay(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const command = mustExist(context.command);
const line = head(command.targets);
return context.state.show(context.source, 'actor.verb.say.line', { actor: this, line }, ShowVolume.ROOM);
return context.state.show(context.source, 'actor.verb.say.line', { actor, line }, ShowVolume.ROOM);
}

View File

@ -1,16 +1,13 @@
import { isNil, mustExist } from '@apextoaster/js-utils';
import { isNone, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { isItem, Item } from '../../../model/entity/Item.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { head } from '../../../util/collection/array.js';
import { createFuzzyMatcher, indexEntity } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorTake(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const command = mustExist(context.command);
const room = mustExist(context.room);
@ -40,13 +37,13 @@ export async function VerbActorTake(this: ScriptTarget, context: ScriptContext):
const moving = indexEntity(results, command.index, isItem);
if (isNil(moving)) {
if (isNone(moving)) {
return context.state.show(context.source, 'actor.verb.take.type', { command });
}
await context.state.move({
moving,
source: room,
target: this
target: actor,
}, context);
}

View File

@ -1,19 +1,17 @@
import { isNil, mustExist, Optional } from '@apextoaster/js-utils';
import { isNone, Maybe, mustExist } from '@apextoaster/js-utils';
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { ReadonlyActor } from '../../../model/entity/Actor.js';
import { WorldEntity } from '../../../model/entity/index.js';
import { isActor, ReadonlyActor } from '../../../model/entity/Actor.js';
import { isItem } from '../../../model/entity/Item.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { head } from '../../../util/collection/array.js';
import { SIGNAL_USE } from '../../../util/constants.js';
import { createFuzzyMatcher, indexEntity } from '../../../util/entity/match.js';
import { assertActor } from '../../../util/script/assert.js';
import { Immutable } from '../../../util/types.js';
export async function VerbActorUse(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
const command = mustExist(context.command);
const room = mustExist(context.room);
@ -32,8 +30,8 @@ export async function VerbActorUse(this: ScriptTarget, context: ScriptContext):
return context.state.show(context.source, 'actor.verb.use.type', { command });
}
const target = await getUseTarget(this, context);
if (isNil(target)) {
const target = await getUseTarget(actor, context);
if (isNone(target)) {
return context.state.show(context.source, 'actor.verb.use.target', { command });
}
@ -43,7 +41,7 @@ export async function VerbActorUse(this: ScriptTarget, context: ScriptContext):
});
}
export async function getUseTarget(actor: ReadonlyActor, context: ScriptContext): Promise<Optional<Immutable<WorldEntity>>> {
export async function getUseTarget(actor: ReadonlyActor, context: ScriptContext): Promise<Maybe<Immutable<WorldEntity>>> {
const command = mustExist(context.command);
const room = mustExist(context.room);

View File

@ -1,11 +1,8 @@
import { ScriptTargetError } from '../../../error/ScriptTargetError.js';
import { isActor } from '../../../model/entity/Actor.js';
import { ScriptContext, ScriptTarget } from '../../../service/script/index.js';
import { assertActor } from '../../../util/script/assert.js';
export async function VerbActorWait(this: ScriptTarget, context: ScriptContext): Promise<void> {
if (!isActor(this)) {
throw new ScriptTargetError('script target must be an actor');
}
const actor = assertActor(this);
context.logger.debug({ target: this }, 'actor is skipping a turn');
context.logger.debug({ target: actor }, 'actor is skipping a turn');
}

View File

@ -1,8 +1,7 @@
import { doesExist, isNil, mustExist, NotImplementedError } from '@apextoaster/js-utils';
import { doesExist, isNone, mustExist, NotImplementedError } from '@apextoaster/js-utils';
import { JSONSchemaType } from 'ajv';
import { Inject, Logger } from 'noicejs';
import { ActorService } from './index.js';
import { ConfigError } from '../../error/ConfigError.js';
import { Command } from '../../model/Command.js';
import { ActorSource, ReadonlyActor } from '../../model/entity/Actor.js';
@ -17,15 +16,16 @@ import {
EVENT_STATE_STEP,
SIGNAL_BEHAVIOR,
} from '../../util/constants.js';
import { zeroStep } from '../../util/entity/index.js';
import { findMatching } from '../../util/entity/find.js';
import { zeroStep } from '../../util/entity/index.js';
import { makeSchema } from '../../util/schema/index.js';
import { makeServiceLogger } from '../../util/service/index.js';
import { EventBus } from '../event/index.js';
import { RandomService } from '../random/index.js';
import { ScriptService } from '../script/index.js';
import { StepResult } from '../state/index.js';
import { StateOutputEvent, StateRoomEvent, StateStepEvent } from '../state/events.js';
import { StepResult } from '../state/index.js';
import { ActorService } from './index.js';
export interface ScriptActorConfig {
data: Map<string, number>;
@ -150,7 +150,7 @@ export class ScriptActorService implements ActorService {
*/
public async getOutput(target: StateSource): Promise<Array<string>> {
return this.output.filter((event) => {
if (isNil(event.source)) {
if (isNone(event.source)) {
return false;
}

View File

@ -1,4 +1,4 @@
import { isNil } from '@apextoaster/js-utils';
import { isNone } from '@apextoaster/js-utils';
import { Counter } from './index.js';
@ -13,7 +13,7 @@ export class LocalCounter implements Counter {
public next(group: string): number {
const last = this.groups.get(group);
if (isNil(last)) {
if (isNone(last)) {
this.groups.set(group, INITIAL_VALUE);
return INITIAL_VALUE;
} else {

View File

@ -1,7 +1,6 @@
import { isNil, mergeMap } from '@apextoaster/js-utils';
import { isNone, mergeMap } from '@apextoaster/js-utils';
import { Inject, Logger } from 'noicejs';
import { ScriptFunction, ScriptService, ScriptTarget, SuppliedScope } from './index.js';
import { WorldEntity, WorldEntityType } from '../../model/entity/index.js';
import { INJECT_LOGGER, InjectedOptions } from '../../module/index.js';
import { SignalActorGet } from '../../script/signal/actor/ActorGet.js';
@ -34,6 +33,7 @@ import { VerbActorWait } from '../../script/verb/actor/ActorWait.js';
import { SearchFilter } from '../../util/entity/find.js';
import { getSignalScripts, getVerbScripts } from '../../util/script/index.js';
import { makeServiceLogger } from '../../util/service/index.js';
import { ScriptFunction, ScriptService, ScriptTarget, SuppliedScope } from './index.js';
export type ScriptPairs = Array<[string, ScriptFunction]>;
/**
@ -90,14 +90,14 @@ export class LocalScriptService implements ScriptService {
mergeMap(scripts, getSignalScripts(target));
const scriptRef = scripts.get(slot);
if (isNil(scriptRef)) {
if (isNone(scriptRef)) {
const scriptNames = Array.from(scripts.keys());
this.logger.debug({ slot, scriptNames, target: target.meta.id }, 'target does not have a script defined for slot');
return;
}
const scriptName = this.scripts.get(scriptRef.name);
if (isNil(scriptName)) {
if (isNone(scriptName)) {
this.logger.error({
scriptRef,
scripts: Array.from(scripts.keys()),

View File

@ -1,20 +1,26 @@
/* eslint-disable max-lines */
import { doesExist, InvalidArgumentError, isNil, mustCoalesce, mustExist, mustFind } from '@apextoaster/js-utils';
import { doesExist, InvalidArgumentError, isNone, mustDefault, mustExist, mustFind } from '@apextoaster/js-utils';
import { Container, Inject, Logger } from 'noicejs';
import { StateService, StepResult } from './index.js';
import { NotInitializedError } from '../../error/NotInitializedError.js';
import { ScriptTargetError } from '../../error/ScriptTargetError.js';
import { Command } from '../../model/Command.js';
import { EntityForType, WorldEntity, WorldEntityType } from '../../model/entity/index.js';
import { Actor, ACTOR_TYPE, ActorSource, isActor, ReadonlyActor } from '../../model/entity/Actor.js';
import { EntityForType, WorldEntity, WorldEntityType } from '../../model/entity/index.js';
import { ITEM_TYPE } from '../../model/entity/Item.js';
import { PORTAL_TYPE } from '../../model/entity/Portal.js';
import { Room, ROOM_TYPE } from '../../model/entity/Room.js';
import { DataFile } from '../../model/file/Data.js';
import { WorldState } from '../../model/world/State.js';
import { WorldTemplate } from '../../model/world/Template.js';
import { INJECT_COUNTER, INJECT_EVENT, INJECT_LOGGER, INJECT_RANDOM, INJECT_SCRIPT, InjectedOptions } from '../../module/index.js';
import {
INJECT_COUNTER,
INJECT_EVENT,
INJECT_LOGGER,
INJECT_RANDOM,
INJECT_SCRIPT,
InjectedOptions,
} from '../../module/index.js';
import { ShowVolume, StateSource } from '../../util/actor/index.js';
import { CompletionSet } from '../../util/async/CompletionSet.js';
import { catchAndLog, onceEvent } from '../../util/async/event.js';
@ -49,7 +55,6 @@ import {
STAT_SCORE,
VERB_PREFIX,
} from '../../util/constants.js';
import { zeroStep } from '../../util/entity/index.js';
import { debugState, graphState } from '../../util/entity/debug.js';
import { StateEntityGenerator } from '../../util/entity/EntityGenerator.js';
import {
@ -60,6 +65,7 @@ import {
StateEntityTransfer,
} from '../../util/entity/EntityTransfer.js';
import { findMatching, findRoom, SearchFilter } from '../../util/entity/find.js';
import { zeroStep } from '../../util/entity/index.js';
import { getVerbScripts } from '../../util/script/index.js';
import { makeServiceLogger } from '../../util/service/index.js';
import { findByBaseId } from '../../util/template/index.js';
@ -71,6 +77,7 @@ import { hasState, LoaderReadEvent, LoaderStateEvent, LoaderWorldEvent } from '.
import { LocaleContext } from '../locale/index.js';
import { RandomService } from '../random/index.js';
import { ScriptContext, ScriptService, SuppliedScope } from '../script/index.js';
import { StateService, StepResult } from './index.js';
type StateScope = Omit<SuppliedScope, 'source'>;
@ -314,7 +321,7 @@ export class LocalStateService implements StateService {
* Print debug representation of the world state.
*/
public async doDebug(): Promise<void> {
if (isNil(this.state)) {
if (isNone(this.state)) {
this.event.emit(EVENT_STATE_OUTPUT, {
line: 'meta.debug.missing',
step: zeroStep(),
@ -338,7 +345,7 @@ export class LocalStateService implements StateService {
* Print graphviz representation of the world state.
*/
public async doGraph(event: ActorCommandEvent): Promise<void> {
if (isNil(this.state)) {
if (isNone(this.state)) {
this.event.emit(EVENT_STATE_OUTPUT, {
line: 'meta.graph.missing',
step: zeroStep(),
@ -410,7 +417,37 @@ export class LocalStateService implements StateService {
});
const loadEvent = await Promise.race([doneEvent, stateEvent]);
if (!hasState(loadEvent)) {
if (hasState(loadEvent)) {
// was a state event
const { state } = loadEvent;
const world = mustExist(this.loadedWorlds.get(state.meta.template));
this.logger.debug({ bundle: world.locale }, 'loading world locale bundle');
this.event.emit(EVENT_LOCALE_BUNDLE, {
bundle: world.locale,
name: 'world',
});
this.state = state;
this.world = world;
mustExist(this.generator).setWorld(world);
this.logger.debug('emitting state loaded event');
this.event.emit(EVENT_STATE_OUTPUT, {
context: {
meta: state.meta,
path,
},
line: 'meta.load.state',
step: state.step,
volume: ShowVolume.WORLD,
});
this.event.emit(EVENT_STATE_LOAD, {
state: state.meta.name,
world: state.meta.template,
});
} else {
this.logger.debug({ loadEvent }, 'path read event received first');
this.event.emit(EVENT_STATE_OUTPUT, {
context: {
@ -420,38 +457,7 @@ export class LocalStateService implements StateService {
step: zeroStep(),
volume: ShowVolume.WORLD,
});
return;
}
// was a state event
const { state } = loadEvent;
const world = mustExist(this.loadedWorlds.get(state.meta.template));
this.logger.debug({ bundle: world.locale }, 'loading world locale bundle');
this.event.emit(EVENT_LOCALE_BUNDLE, {
bundle: world.locale,
name: 'world',
});
this.state = state;
this.world = world;
mustExist(this.generator).setWorld(world);
this.logger.debug('emitting state loaded event');
this.event.emit(EVENT_STATE_OUTPUT, {
context: {
meta: state.meta,
path,
},
line: 'meta.load.state',
step: state.step,
volume: ShowVolume.WORLD,
});
this.event.emit(EVENT_STATE_LOAD, {
state: state.meta.name,
world: state.meta.template,
});
}
/**
@ -462,7 +468,7 @@ export class LocalStateService implements StateService {
}
public async doSave(event: ActorCommandEvent): Promise<void> {
if (isNil(this.state)) {
if (isNone(this.state)) {
this.event.emit(EVENT_STATE_OUTPUT, {
line: 'meta.save.missing',
step: zeroStep(),
@ -507,7 +513,7 @@ export class LocalStateService implements StateService {
const { actor, command } = event;
// if there is no world state, there won't be an actor, but this error is more informative
if (isNil(actor) || isNil(this.state)) {
if (isNone(actor) || isNone(this.state)) {
this.event.emit(EVENT_STATE_OUTPUT, {
line: 'meta.step.missing',
step: zeroStep(),
@ -555,7 +561,7 @@ export class LocalStateService implements StateService {
// eslint-disable-next-line sonarjs/cognitive-complexity
public async step(): Promise<StepResult> {
if (isNil(this.state)) {
if (isNone(this.state)) {
throw new NotInitializedError('state has not been initialized');
}
@ -702,7 +708,7 @@ export class LocalStateService implements StateService {
case ITEM_TYPE: {
const template = findByBaseId(world.templates.items, id);
const item = await generator.createItem(template);
const targetEntity = mustCoalesce<Immutable<Actor | Room>>(target.actor, target.room);
const targetEntity = mustDefault<Immutable<Actor | Room>>(target.actor, target.room);
await this.stepUpdate(targetEntity, {
items: [...targetEntity.items, item],

View File

@ -1,7 +1,6 @@
import { getOrDefault, isNil, mustExist } from '@apextoaster/js-utils';
import { getOrDefault, isNone, mustExist } from '@apextoaster/js-utils';
import { Inject, Logger } from 'noicejs';
import { TokenizerService } from './index.js';
import { Command } from '../../model/Command.js';
import { LocaleBundle } from '../../model/file/Locale.js';
import { INJECT_EVENT, INJECT_LOCALE, INJECT_LOGGER, InjectedOptions } from '../../module/index.js';
@ -11,9 +10,10 @@ import { EVENT_LOCALE_BUNDLE, EVENT_RENDER_INPUT, EVENT_TOKEN_COMMAND, SPLIT_CHA
import { makeServiceLogger } from '../../util/service/index.js';
import { splitWords, trim } from '../../util/string.js';
import { EventBus } from '../event/index.js';
import { LocaleService } from '../locale/index.js';
import { LocaleBundleEvent } from '../locale/events.js';
import { LocaleService } from '../locale/index.js';
import { RenderInputEvent } from '../render/events.js';
import { TokenizerService } from './index.js';
@Inject(INJECT_EVENT, INJECT_LOCALE, INJECT_LOGGER)
export class SplitTokenizer implements TokenizerService {
@ -103,7 +103,7 @@ export class SplitTokenizer implements TokenizerService {
const current = this.locale.getLocale();
const lng = bundle.languages[current];
if (isNil(lng)) {
if (isNone(lng)) {
this.logger.debug({ bundle }, 'bundle does not include current language');
return;
}

View File

@ -1,4 +1,4 @@
import { isNil } from '@apextoaster/js-utils';
import { isNone } from '@apextoaster/js-utils';
export type SingletonConstructor<TValue> = () => Promise<TValue>;
@ -12,9 +12,10 @@ export class Singleton<TValue> {
}
public async get(): Promise<TValue> {
if (isNil(this.value)) {
if (isNone(this.value)) {
this.value = await this.ctor();
}
return this.value;
}
}

View File

@ -1,4 +1,4 @@
import { InvalidArgumentError, isNil } from '@apextoaster/js-utils';
import { InvalidArgumentError, isNone } from '@apextoaster/js-utils';
import { Inject, Logger } from 'noicejs';
import { isActor, ReadonlyActor } from '../../model/entity/Actor.js';
@ -6,9 +6,9 @@ import { isItem, ReadonlyItem } from '../../model/entity/Item.js';
import { isRoom, ReadonlyRoom } from '../../model/entity/Room.js';
import { INJECT_LOGGER, InjectedOptions } from '../../module/index.js';
import { ScriptContext } from '../../service/script/index.js';
import { remove } from '../collection/array.js';
import { SIGNAL_ENTER, SIGNAL_GET } from '../constants.js';
import { makeServiceLogger } from '../service/index.js';
import { remove } from '../collection/array.js';
export interface ActorTransfer {
moving: ReadonlyActor;
@ -39,7 +39,7 @@ export function isItemTransfer(tx: EntityTransfer): tx is ItemTransfer {
}
export function isRoomTransfer(tx: EntityTransfer): tx is RoomTransfer {
return isNil(tx.moving);
return isNone(tx.moving);
}
@Inject(INJECT_LOGGER)

View File

@ -1,8 +1,8 @@
import { doesExist, mustCoalesce, Optional } from '@apextoaster/js-utils';
import { doesExist, Maybe, mustDefault } from '@apextoaster/js-utils';
import { EntityForType, WorldEntityType } from '../../model/entity/index.js';
import { Actor, ActorType, ReadonlyActor } from '../../model/entity/Actor.js';
import { Entity } from '../../model/entity/Base.js';
import { EntityForType, WorldEntityType } from '../../model/entity/index.js';
import { ReadonlyItem } from '../../model/entity/Item.js';
import { isRoom, ReadonlyRoom, Room, RoomType } from '../../model/entity/Room.js';
import { Metadata } from '../../model/Metadata.js';
@ -31,7 +31,7 @@ export interface SearchFilter<TType extends WorldEntityType> {
*/
// eslint-disable-next-line complexity,sonarjs/cognitive-complexity
export function findMatching<TType extends WorldEntityType>(rooms: ReadonlyArray<ReadonlyRoom>, search: SearchFilter<TType>): Array<Immutable<EntityForType<TType>>> {
const matchers = mustCoalesce(search.matchers, createStrictMatcher<TType>());
const matchers = mustDefault(search.matchers, createStrictMatcher<TType>());
const results: Array<EntityForType<TType>> = [];
for (const room of rooms) {
@ -89,7 +89,7 @@ export function findRoom(state: WorldState, search: SearchFilter<RoomType>): Arr
*/
// eslint-disable-next-line complexity,sonarjs/cognitive-complexity
export function findContainer<TType extends ActorType | RoomType>(state: WorldState, search: SearchFilter<TType>): Array<Actor | Room> {
const matchers = mustCoalesce(search.matchers, createStrictMatcher<TType>());
const matchers = mustDefault(search.matchers, createStrictMatcher<TType>());
const results = new Set<Actor | Room>();
for (const room of state.rooms) {
@ -132,7 +132,7 @@ export function findContainer<TType extends ActorType | RoomType>(state: WorldSt
/**
* Find the item equipped in a particular slot.
*/
export function findSlotItem(actor: ReadonlyActor, slot: string): Optional<ReadonlyItem> {
export function findSlotItem(actor: ReadonlyActor, slot: string): Maybe<ReadonlyItem> {
const id = actor.slots.get(slot);
if (doesExist(id) && hasText(id)) {
return actor.items.find((it) => it.meta.id === id);

View File

@ -1,7 +1,7 @@
import { doesExist, mustCoalesce, Optional } from '@apextoaster/js-utils';
import { doesExist, mustDefault, Optional } from '@apextoaster/js-utils';
import { EntityForType, WorldEntityType } from '../../model/entity/index.js';
import { Entity } from '../../model/entity/Base.js';
import { EntityForType, WorldEntityType } from '../../model/entity/index.js';
import { isPortal } from '../../model/entity/Portal.js';
import { Metadata } from '../../model/Metadata.js';
import { matchIdSegments } from '../string.js';
@ -22,7 +22,7 @@ export function indexEntity<TEntity extends Entity>(entities: Array<Immutable<En
}
export function matchEntity<TType extends WorldEntityType>(entity: Immutable<Entity>, search: SearchFilter<TType>): entity is EntityForType<TType> {
const matchers = mustCoalesce(search.matchers, createStrictMatcher<TType>());
const matchers = mustDefault(search.matchers, createStrictMatcher<TType>());
let matched = true;

43
src/util/script/assert.ts Normal file
View File

@ -0,0 +1,43 @@
import { ScriptTargetError } from '../../error/ScriptTargetError.js';
import { Actor, isActor } from '../../model/entity/Actor.js';
import { isItem, Item } from '../../model/entity/Item.js';
import { isPortal, Portal } from '../../model/entity/Portal.js';
import { isRoom, Room } from '../../model/entity/Room.js';
import { ScriptTarget } from '../../service/script/index.js';
import { Immutable } from '../types.js';
export function assertActor(it: ScriptTarget): Immutable<Actor> {
const val = it;
if (isActor(val)) {
return val;
}
throw new ScriptTargetError('script target must be an actor');
}
export function assertItem(it: ScriptTarget): Immutable<Item> {
const val = it;
if (isItem(val)) {
return val;
}
throw new ScriptTargetError('script target must be an item');
}
export function assertPortal(it: ScriptTarget): Immutable<Portal> {
const val = it;
if (isPortal(val)) {
return val;
}
throw new ScriptTargetError('script target must be a portal');
}
export function assertRoom(it: ScriptTarget): Immutable<Room> {
const val = it;
if (isRoom(val)) {
return val;
}
throw new ScriptTargetError('script target must be a room');
}

View File

@ -1,9 +1,9 @@
import { InvalidArgumentError, mustCoalesce } from '@apextoaster/js-utils';
import { InvalidArgumentError, mustDefault } from '@apextoaster/js-utils';
import { BaseOptions, Container, Inject } from 'noicejs';
import { ConfigServices } from '../../model/file/Config.js';
import { Service } from '../../service/index.js';
import { ActorService } from '../../service/actor/index.js';
import { Service } from '../../service/index.js';
import { LoaderService } from '../../service/loader/index.js';
import { RenderService } from '../../service/render/index.js';
import { StateService } from '../../service/state/index.js';
@ -30,7 +30,7 @@ export class ServiceManager {
}
const svc = await this.container.create<StateService, BaseOptions>(state.kind, {
config: mustCoalesce(state.data, {}),
config: mustDefault(state.data, {}),
});
await svc.start();
@ -43,7 +43,7 @@ export class ServiceManager {
}
const svc = await this.container.create<LoaderService, BaseOptions>(loader.kind, {
config: mustCoalesce(loader.data, {}),
config: mustDefault(loader.data, {}),
});
await svc.start();
@ -56,7 +56,7 @@ export class ServiceManager {
}
const svc = await this.container.create<RenderService, BaseOptions>(render.kind, {
config: mustCoalesce(render.data, {}),
config: mustDefault(render.data, {}),
});
await svc.start();
@ -69,7 +69,7 @@ export class ServiceManager {
}
const svc = await this.container.create<TokenizerService, BaseOptions>(tokenizer.kind, {
config: mustCoalesce(tokenizer.data, {}),
config: mustDefault(tokenizer.data, {}),
});
await svc.start();
@ -82,7 +82,7 @@ export class ServiceManager {
}
const svc = await this.container.create<ActorService, BaseOptions>(actor.kind, {
config: mustCoalesce(actor.data, {}),
config: mustDefault(actor.data, {}),
});
await svc.start();

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { doesExist } from '@apextoaster/js-utils';
import parsimmon from 'parsimmon';

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/naming-convention */
import parsimmon from 'parsimmon';
import { InputChain } from './index.js';