refactor: yarn runner man
This commit is contained in:
parent
8d5b15ad51
commit
e13ead2309
|
|
@ -2,9 +2,8 @@ import { customElement, noShadowDOM } from 'solid-element';
|
||||||
import { For, Show, createEffect } from 'solid-js';
|
import { For, Show, createEffect } from 'solid-js';
|
||||||
import type {TextResult, RuntimeResult, OptionsResult} from '../yarn-spinner/runtime/results';
|
import type {TextResult, RuntimeResult, OptionsResult} from '../yarn-spinner/runtime/results';
|
||||||
import { createYarnStore } from './stores/yarnStore';
|
import { createYarnStore } from './stores/yarnStore';
|
||||||
import {RunnerOptions} from "../yarn-spinner/runtime/runner";
|
|
||||||
|
|
||||||
customElement<RunnerOptions>('md-yarn-spinner', {startAt: 'start'}, (props, { element }) => {
|
customElement<{start: string}>('md-yarn-spinner', {start: 'start'}, (props, { element }) => {
|
||||||
noShadowDOM();
|
noShadowDOM();
|
||||||
|
|
||||||
let historyContainer: HTMLDivElement | undefined;
|
let historyContainer: HTMLDivElement | undefined;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export function getTtrpgFunctions(runner: IRunner){
|
||||||
}
|
}
|
||||||
/* stat related */
|
/* stat related */
|
||||||
function ensure_stat(stat: string){
|
function ensure_stat(stat: string){
|
||||||
if(!runner.getVariable(stat)){
|
if(runner.getVariable(stat) === undefined){
|
||||||
const statBase = `${stat}_base`;
|
const statBase = `${stat}_base`;
|
||||||
const statMod = `${stat}_mod`;
|
const statMod = `${stat}_mod`;
|
||||||
const statDamage = `${stat}_damage`;
|
const statDamage = `${stat}_damage`;
|
||||||
|
|
@ -74,6 +74,7 @@ export function getTtrpgFunctions(runner: IRunner){
|
||||||
const progress = runner.getVariable(key) as number || 0;
|
const progress = runner.getVariable(key) as number || 0;
|
||||||
const newProgress = progress + Math.ceil(Math.random() * 4);
|
const newProgress = progress + Math.ceil(Math.random() * 4);
|
||||||
runner.setVariable(key, newProgress);
|
runner.setVariable(key, newProgress);
|
||||||
|
console.log(`check ${stat}(${statVal}) ${pass ? 'pass' : 'fail'}, now ${newProgress}`);
|
||||||
return pass ? newProgress : -newProgress;
|
return pass ? newProgress : -newProgress;
|
||||||
}
|
}
|
||||||
function rollStat(){
|
function rollStat(){
|
||||||
|
|
@ -94,15 +95,17 @@ export function getTtrpgFunctions(runner: IRunner){
|
||||||
heal(stat, 1);
|
heal(stat, 1);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
add_minutes: add_minute,
|
commands: {
|
||||||
add_hours: add_hour,
|
add_minute,
|
||||||
add_days: add_day,
|
add_hour,
|
||||||
|
add_day,
|
||||||
damage,
|
damage,
|
||||||
heal,
|
heal,
|
||||||
check,
|
fatigue,
|
||||||
|
regen
|
||||||
fatigue,
|
} as Record<string, (...args: any[]) =>any>,
|
||||||
regen,
|
functions: {
|
||||||
};
|
check
|
||||||
|
} as Record<string, (...args: any[]) =>any>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import {compile, parseYarn, YarnRunner} from "../../yarn-spinner";
|
||||||
import {loadElementSrc, resolvePath} from "../utils/path";
|
import {loadElementSrc, resolvePath} from "../utils/path";
|
||||||
import {createStore} from "solid-js/store";
|
import {createStore} from "solid-js/store";
|
||||||
import {RunnerOptions} from "../../yarn-spinner/runtime/runner";
|
import {RunnerOptions} from "../../yarn-spinner/runtime/runner";
|
||||||
|
import {getTtrpgFunctions} from "./ttrpgRunner";
|
||||||
|
|
||||||
type YarnSpinnerStore = {
|
type YarnSpinnerStore = {
|
||||||
dialogueHistory: (RuntimeResult | OptionsResult['options'][0])[],
|
dialogueHistory: (RuntimeResult | OptionsResult['options'][0])[],
|
||||||
|
|
@ -12,7 +13,7 @@ type YarnSpinnerStore = {
|
||||||
runnerInstance: YarnRunner | null,
|
runnerInstance: YarnRunner | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createYarnStore(element: HTMLElement, props: RunnerOptions){
|
export function createYarnStore(element: HTMLElement, props: {start: string}){
|
||||||
const [store, setStore] = createStore<YarnSpinnerStore>({
|
const [store, setStore] = createStore<YarnSpinnerStore>({
|
||||||
dialogueHistory: [],
|
dialogueHistory: [],
|
||||||
currentOptions: null,
|
currentOptions: null,
|
||||||
|
|
@ -39,19 +40,11 @@ export function createYarnStore(element: HTMLElement, props: RunnerOptions){
|
||||||
const program = compile(ast);
|
const program = compile(ast);
|
||||||
|
|
||||||
const runner = new YarnRunner(program, {
|
const runner = new YarnRunner(program, {
|
||||||
functions: {
|
startAt: props.start,
|
||||||
check(id: string, stat: string): number {
|
|
||||||
const statVal = runner.getVariable(stat) as number || 10;
|
|
||||||
const pass = Math.ceil(Math.random() * 20) <= statVal;
|
|
||||||
const key = `${id}_${pass ? 'pass' : 'fail'}`;
|
|
||||||
const progress = runner.getVariable(key) as number || 0;
|
|
||||||
const newProgress = progress + Math.ceil(Math.random() * 4);
|
|
||||||
runner.setVariable(key, newProgress);
|
|
||||||
return pass ? newProgress : -newProgress;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
startAt: props.startAt,
|
|
||||||
});
|
});
|
||||||
|
const {commands, functions} = getTtrpgFunctions(runner);
|
||||||
|
runner.registerFunctions(functions);
|
||||||
|
runner.registerCommands(commands);
|
||||||
return runner;
|
return runner;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize YarnRunner:', error);
|
console.error('Failed to initialize YarnRunner:', error);
|
||||||
|
|
|
||||||
|
|
@ -499,4 +499,11 @@ export class ExpressionEvaluator {
|
||||||
getVariable(name: string): unknown {
|
getVariable(name: string): unknown {
|
||||||
return this.variables[name];
|
return this.variables[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerFunctions(functions: Record<string, (...args: unknown[]) => unknown>){
|
||||||
|
this.functions = {
|
||||||
|
...this.functions,
|
||||||
|
...functions
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ type CompiledOption = {
|
||||||
export class YarnRunner {
|
export class YarnRunner {
|
||||||
private readonly program: IRProgram;
|
private readonly program: IRProgram;
|
||||||
private readonly variables: Record<string, unknown>;
|
private readonly variables: Record<string, unknown>;
|
||||||
private readonly functions: Record<string, (...args: unknown[]) => unknown>;
|
|
||||||
private readonly handleCommand?: (command: string, parsed?: ReturnType<typeof parseCommand>) => void;
|
private readonly handleCommand?: (command: string, parsed?: ReturnType<typeof parseCommand>) => void;
|
||||||
private readonly commandHandler: CommandHandler;
|
private readonly commandHandler: CommandHandler;
|
||||||
private readonly evaluator: ExpressionEvaluator;
|
private readonly evaluator: ExpressionEvaluator;
|
||||||
|
|
@ -59,7 +58,7 @@ export class YarnRunner {
|
||||||
this.variables[normalizedKey] = value;
|
this.variables[normalizedKey] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.functions = {
|
let functions = {
|
||||||
// Default conversion helpers
|
// Default conversion helpers
|
||||||
string: (v: unknown) => String(v ?? ""),
|
string: (v: unknown) => String(v ?? ""),
|
||||||
number: (v: unknown) => Number(v),
|
number: (v: unknown) => Number(v),
|
||||||
|
|
@ -115,12 +114,25 @@ export class YarnRunner {
|
||||||
} as Record<string, (...args: unknown[]) => unknown>;
|
} as Record<string, (...args: unknown[]) => unknown>;
|
||||||
this.handleCommand = opts.handleCommand;
|
this.handleCommand = opts.handleCommand;
|
||||||
this.onStoryEnd = opts.onStoryEnd;
|
this.onStoryEnd = opts.onStoryEnd;
|
||||||
this.evaluator = new ExpressionEvaluator(this.variables, this.functions, this.program.enums);
|
this.evaluator = new ExpressionEvaluator(this.variables, functions, this.program.enums);
|
||||||
this.commandHandler = opts.commandHandler ?? new CommandHandler(this.variables);
|
this.commandHandler = opts.commandHandler ?? new CommandHandler(this.variables);
|
||||||
this.nodeTitle = opts.startAt;
|
this.nodeTitle = opts.startAt;
|
||||||
|
|
||||||
this.step();
|
this.step();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public registerFunctions(functions: Record<string, (...args: unknown[]) => unknown>){
|
||||||
|
this.evaluator.registerFunctions(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerCommands(commands: Record<string, (args: unknown[], evaluator?: ExpressionEvaluator) => void | Promise<void>>) {
|
||||||
|
for(const key in commands){
|
||||||
|
this.commandHandler.register(key, (args, evaluator) => {
|
||||||
|
if(!evaluator) return;
|
||||||
|
commands[key].call(this, args.map(arg => evaluator.evaluateExpression(arg)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve a node title to an actual node (handling node groups).
|
* Resolve a node title to an actual node (handling node groups).
|
||||||
|
|
@ -599,6 +611,8 @@ export class YarnRunner {
|
||||||
* Get variable value.
|
* Get variable value.
|
||||||
*/
|
*/
|
||||||
getVariable(name: string): unknown {
|
getVariable(name: string): unknown {
|
||||||
|
if(this.evaluator.isSmartVariable(name))
|
||||||
|
return this.evaluator.evaluateExpression(`$${name}`);
|
||||||
return this.variables[name];
|
return this.variables[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue