Skip to content

Commit

Permalink
feat: support custom verbs (fixes #78), show actor verbs in help
Browse files Browse the repository at this point in the history
  • Loading branch information
ssube committed Jun 3, 2021
1 parent 80a3ff5 commit c7bfa2d
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 13 deletions.
9 changes: 9 additions & 0 deletions data/base.yml
Expand Up @@ -50,6 +50,10 @@ worlds:
data: !map {}
name:
base: verb-wait
verbs.world.swing:
data: !map {}
name:
base: verb-hit
item:
meta:
id: item-none
Expand Down Expand Up @@ -139,6 +143,11 @@ worlds:
use:
any: |-
{{item.meta.name}} has been used by {{actor.meta.name}}!
verbs:
world:
swing: swing
verbs:
- verbs.world.swing
meta:
id: test
name:
Expand Down
1 change: 1 addition & 0 deletions data/config.yml
Expand Up @@ -38,6 +38,7 @@ locale:
save: save
worlds: worlds
current: en
verbs: []
services:
actors:
- name: actor-player
Expand Down
9 changes: 8 additions & 1 deletion src/model/file/Locale.ts
Expand Up @@ -4,6 +4,7 @@ export type LocaleLanguage = Record<string, Record<string, string>>;

export interface LocaleBundle {
bundles: LocaleLanguage;
verbs: Array<string>;
}

export const LOCALE_SCHEMA: JSONSchemaType<LocaleBundle> = {
Expand All @@ -20,6 +21,12 @@ export const LOCALE_SCHEMA: JSONSchemaType<LocaleBundle> = {
},
},
},
verbs: {
type: 'array',
items: {
type: 'string',
},
},
},
required: ['bundles'],
required: ['bundles', 'verbs'],
};
9 changes: 6 additions & 3 deletions src/service/actor/PlayerActor.ts
Expand Up @@ -70,9 +70,12 @@ export class PlayerActorService implements ActorService {
this.pid = `player-${this.counter.next('player')}`;
}

public async start() {
public async start(): Promise<void> {
this.event.on(EVENT_LOCALE_BUNDLE, (event) => {
catchAndLog(this.tokenizer.translate(COMMON_VERBS), this.logger, 'error translating verbs');
catchAndLog(this.tokenizer.translate([
...COMMON_VERBS,
...event.bundle.verbs,
]), this.logger, 'error translating verbs');
}, this);
this.event.on(EVENT_RENDER_OUTPUT, (event) => {
catchAndLog(this.onInput(event), this.logger, 'error during render output');
Expand Down Expand Up @@ -100,7 +103,7 @@ export class PlayerActorService implements ActorService {
}, this);
}

public async stop() {
public async stop(): Promise<void> {
this.event.removeGroup(this);
}

Expand Down
4 changes: 3 additions & 1 deletion src/service/script/LocalScript.ts
Expand Up @@ -59,7 +59,7 @@ export class LocalScriptService implements ScriptService {
}

public async invoke(target: ScriptTarget, slot: string, scope: SuppliedScope): Promise<void> {
this.logger.debug({ slot, target }, 'invoke slot on target');
this.logger.debug({ slot, target }, 'trying to invoke slot on target');

const scriptRef = target.scripts.get(slot);
if (isNil(scriptRef)) {
Expand All @@ -73,6 +73,8 @@ export class LocalScriptService implements ScriptService {
return;
}

this.logger.debug({ script: scriptRef.name, target: target.meta.id }, 'invoking script on target');

await script.call(target, {
...scope,
logger: this.logger.child({
Expand Down
29 changes: 25 additions & 4 deletions src/service/state/TurnState.ts
@@ -1,4 +1,4 @@
import { constructorName, doesExist, isNil, mustExist, mustFind, NotFoundError } from '@apextoaster/js-utils';
import { constructorName, doesExist, isNil, mustExist, mustFind, NotFoundError, Optional } from '@apextoaster/js-utils';
import { BaseOptions, Container, Inject, Logger } from 'noicejs';

import { CreateParams, StateService, StepResult } from '.';
Expand Down Expand Up @@ -261,7 +261,7 @@ export class LocalStateService implements StateService {
await this.doGraph(command.target);
break;
case META_HELP:
await this.doHelp();
await this.doHelp(actor);
break;
case META_LOAD:
await this.doLoad(command.target);
Expand Down Expand Up @@ -350,8 +350,29 @@ export class LocalStateService implements StateService {
});
}

public async doHelp(): Promise<void> {
const verbs = COMMON_VERBS.map((it) => `$t(${it})`).join(', ');
/**
* @todo collect verbs from room, items
* @todo prevent/remove verbs
*/
public async getVerbs(actor: Optional<Actor>): Promise<ReadonlyArray<string>> {
if (doesExist(actor)) {
const verbs = new Set<string>(COMMON_VERBS);
for (const key of actor.scripts.keys()) {
if (key.startsWith('verbs.')) {
verbs.add(key);
}
}
return Array.from(verbs);
} else {
return COMMON_VERBS;
}
}

public async doHelp(actor: Optional<Actor>): Promise<void> {
const verbs = (await this.getVerbs(actor))
.map((it) => `$t(${it})`)
.join(', ');

this.event.emit(EVENT_STATE_OUTPUT, {
context: {
verbs,
Expand Down
15 changes: 11 additions & 4 deletions src/service/tokenizer/WordTokenizer.ts
@@ -1,9 +1,9 @@
import { getOrDefault, mustExist } from '@apextoaster/js-utils';
import { BaseOptions, Inject } from 'noicejs';
import { constructorName, getOrDefault, mustExist } from '@apextoaster/js-utils';
import { BaseOptions, Inject, Logger } from 'noicejs';

import { TokenizerService } from '.';
import { Command } from '../../model/Command';
import { INJECT_LOCALE } from '../../module';
import { INJECT_LOCALE, INJECT_LOGGER } from '../../module';
import { LocaleService } from '../locale';

const REMOVED_WORDS = new Set([
Expand All @@ -21,15 +21,20 @@ const SPLIT_CHAR = ' ';

interface WordTokenizerOptions extends BaseOptions {
[INJECT_LOCALE]?: LocaleService;
[INJECT_LOGGER]?: Logger;
}

@Inject(INJECT_LOCALE)
@Inject(INJECT_LOCALE, INJECT_LOGGER)
export class WordTokenizer implements TokenizerService {
protected locale: LocaleService;
protected logger: Logger;
protected verbs: Map<string, string>;

constructor(options: WordTokenizerOptions) {
this.locale = mustExist(options[INJECT_LOCALE]);
this.logger = mustExist(options[INJECT_LOGGER]).child({
kind: constructorName(this),
});
this.verbs = new Map();
}

Expand Down Expand Up @@ -67,6 +72,8 @@ export class WordTokenizer implements TokenizerService {
public async translate(verbs: ReadonlyArray<string>): Promise<void> {
this.verbs.clear();

this.logger.debug({ verbs }, 'translating verbs');

for (const verb of verbs) {
const translated = this.locale.translate(verb);
this.verbs.set(translated, verb); // trick i18next into translating them back
Expand Down
1 change: 1 addition & 0 deletions test/helper.ts
Expand Up @@ -23,6 +23,7 @@ export function getTestConfig(): ConfigFile {
locale: {
bundles: {},
current: 'en',
verbs: [],
},
services: {
actors: [],
Expand Down
3 changes: 3 additions & 0 deletions test/service/locale/TestNextLocale.ts
Expand Up @@ -28,13 +28,15 @@ describe('next locale service', () => {
foo: 'bar',
},
},
verbs: [],
});
locale.addBundle('world', {
bundles: {
en: {
foo: 'bin',
},
},
verbs: [],
});

expect(locale.translate('foo')).to.equal('bin');
Expand All @@ -51,6 +53,7 @@ describe('next locale service', () => {
foo: '{{size}} bar',
},
},
verbs: [],
});

expect(locale.translate('foo', { size: 4 })).to.equal('4 bar');
Expand Down
1 change: 1 addition & 0 deletions test/util/state/TestGenerator.ts
Expand Up @@ -79,6 +79,7 @@ const TEST_WORLD: WorldTemplate = {
},
locale: {
bundles: {},
verbs: [],
},
meta: {
desc: {
Expand Down

0 comments on commit c7bfa2d

Please sign in to comment.