@patterkit/cli 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +90 -43
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -200804,7 +200804,7 @@ function bundleOutputPath(loaded) {
|
|
|
200804
200804
|
}
|
|
200805
200805
|
|
|
200806
200806
|
// ../ops/src/playable-runtime.ts
|
|
200807
|
-
var PLAYABLE_RUNTIME_JS = 'var Patterplay=(()=>{var _=Object.defineProperty;var Te=Object.getOwnPropertyDescriptor;var Ge=Object.getOwnPropertyNames;var je=Object.prototype.hasOwnProperty;var Ve=(n,e)=>{for(var t in e)_(n,t,{get:e[t],enumerable:!0})},Le=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Ge(e))!je.call(n,s)&&s!==t&&_(n,s,{get:()=>e[s],enumerable:!(r=Te(e,s))||r.enumerable});return n};var Me=n=>Le(_({},"__esModule",{value:!0}),n);var st={};Ve(st,{Checkpoint:()=>A,Engine:()=>H,Flow:()=>I,buildTagIndex:()=>$,describeBundle:()=>Oe,effectiveGameData:()=>Ne,gameDataFields:()=>Be,gameDataValue:()=>te});function D(n,e){return n!==void 0&&Object.prototype.hasOwnProperty.call(n,e)?n[e]:void 0}function k(n){switch(n[0]){case"b":return{kind:"bool",value:n[1]};case"n":return{kind:"number",value:n[1]};case"s":return{kind:"string",value:n[1]};case"sv":return{kind:"scopedvar",scope:n[1],name:n[2]};case"u":return{kind:"unary",op:n[1],operand:k(n[2])};case"bin":return{kind:"binary",op:n[1],left:k(n[2]),right:k(n[3])};case"call":{let e=n.slice(2).map(k);return{kind:"call",name:n[1],args:e}}case"fd":return{kind:"flagdelta",sign:n[1],name:n[2]}}}var d=class extends Error{constructor(e){super(e),this.name="EvalError"}};function G(n,e,t){let r=new Map(t.scopes.map(i=>[i.token,i.missing??"false"])),s=i=>{switch(i.kind){case"bool":return i.value;case"number":return i.value;case"string":return i.value;case"scopedvar":{let o=D(e.scopes,i.scope);if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):D(o,i.name);if(a===void 0){if(r.get(i.scope)==="throw")throw new d(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{if(i.name==="advance"&&!D(t.functions,i.name)){let a=i.args[0];if(i.args.length!==1||a===void 0)throw new d(`advance() takes exactly 1 argument, got ${i.args.length}`);let c=U(a,e);if(c===void 0)throw new d("advance() needs a quality reference (@scope.name of a quality property)");let l=w(s(a),c,"advance");return c[Math.min(l+1,c.length-1)]}let o=D(t.functions,i.name);if(!o)throw new d(`unknown function \'${i.name}\'`);return o.eval(i.args,{evaluate:s,ctx:e})}case"flagdelta":throw new d("flagdelta node is only valid as an argument to a flag-delta function");case"unary":{if(i.op==="not"){let a=s(i.operand);if(typeof a!="boolean")throw new d(`\'not\' requires a boolean operand, got ${typeof a}`);return!a}let o=s(i.operand);if(typeof o!="number")throw new d(`unary \'-\' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let f=s(i.left);if(typeof f!="boolean")throw new d(`\'and\' requires boolean operands, left is ${typeof f}`);if(!f)return!1;let u=s(i.right);if(typeof u!="boolean")throw new d(`\'and\' requires boolean operands, right is ${typeof u}`);return u}if(i.op==="or"){let f=s(i.left);if(typeof f!="boolean")throw new d(`\'or\' requires boolean operands, left is ${typeof f}`);if(f)return!0;let u=s(i.right);if(typeof u!="boolean")throw new d(`\'or\' requires boolean operands, right is ${typeof u}`);return u}let o=s(i.left),a=s(i.right),c=U(i.left,e),l=U(i.right,e),p=c??l;if(p!==void 0){if(c&&l&&!$e(c,l)&&(i.op===">"||i.op===">="||i.op==="<"||i.op==="<="))throw new d(`\'${i.op}\' compares two different qualities, whose stage orders are unrelated`);switch(i.op){case">":return w(o,p,">")>w(a,p,">");case">=":return w(o,p,">=")>=w(a,p,">=");case"<":return w(o,p,"<")<w(a,p,"<");case"<=":return w(o,p,"<=")<=w(a,p,"<=");case"+":case"-":case"*":case"/":throw new d(`\'${i.op}\' cannot be applied to a quality - a stage is a position, not a number; use advance() to move it`);default:break}}switch(i.op){case"==":return ce(o,a);case"!=":return!ce(o,a);case">":return E(o,a,">"),o>a;case">=":return E(o,a,">="),o>=a;case"<":return E(o,a,"<"),o<a;case"<=":return E(o,a,"<="),o<=a;case"+":if(typeof o=="number"&&typeof a=="number"||typeof o=="string"&&typeof a=="string")return o+a;throw new d(`\'+\' requires two numbers or two strings, got ${typeof o} and ${typeof a}`);case"-":return E(o,a,"-"),o-a;case"*":return E(o,a,"*"),o*a;case"/":if(E(o,a,"/"),a===0)throw new d("division by zero");return o/a}}}};return s(n)}function ce(n,e){if(Array.isArray(n)||Array.isArray(e)){if(!Array.isArray(n)||!Array.isArray(e)||n.length!==e.length)return!1;let t=[...n].sort(),r=[...e].sort();for(let s=0;s<t.length;s++)if(t[s]!==r[s])return!1;return!0}return n===e}function E(n,e,t){if(typeof n!="number"||typeof e!="number")throw new d(`\'${t}\' requires numeric operands, got ${typeof n} and ${typeof e}`)}function U(n,e){if(!(n.kind!=="scopedvar"||e.qualities===void 0))return e.qualities(n.scope,n.name)}function w(n,e,t){if(typeof n!="string")throw new d(`\'${t}\' on a quality compares stages, got ${typeof n}`);let r=e.indexOf(n);if(r<0)throw new d(`"${n}" is not a stage of this quality (stages: ${e.join(", ")})`);return r}var $e=(n,e)=>n.length===e.length&&n.every((t,r)=>t===e[r]);function R(n){if(Number.isNaN(n)||!Number.isFinite(n))return 0;let e=Math.trunc(n)%4294967296;return e<0?e+4294967296:e}function W(n){let e=R(n);return{next(){e=e+1831565813>>>0;let t=Math.imul(e^e>>>15,1|e);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296},state(){return e}}}var He={name:"check_flags",count:n=>Math.max(1,n.args.length-1)},qe=[He];function le(n,e,t){let r=t?.countingCalls??qe;return j(n,t?.want??!0,e,r)}function j(n,e,t,r){if(n.kind==="binary"&&(n.op==="and"||n.op==="or")){let s=j(n.left,e,t,r),i=j(n.right,e,t,r);return n.op==="and"===e?s>0&&i>0?s+i:0:Math.max(s,i)}if(n.kind==="unary"&&n.op==="not")return j(n.operand,!e,t,r);if(n.kind==="call"){let s=r.find(i=>i.name===n.name);if(s){let i=s.count(n),o=t(n);return e?o?i:0:o?0:1}}return t(n)===e?1:0}var b=class n{values=Object.create(null);decls=new Map;subscribers=new Set;auditors=new Set;norm;pathPrefix;constructor(e=[],t){this.norm=t?.normalise??(r=>r.toLowerCase()),this.pathPrefix=t?.pathPrefix??"",this.seed(e)}seed(e){for(let t of e){let r=this.norm(t.name);this.decls.set(r,t),this.values[r]=structuredClone(t.default??P(t))}}get(e){return this.values[this.norm(e)]}normalise(e){return this.norm(e)}writable(e){return this.decls.get(this.norm(e))?.writable!==!1}set(e,t,r){let s=this.norm(e);if(!r?.host&&!this.writable(s))throw new Error(`\'${e}\' is read-only`);let i={name:s,prev:this.values[s],next:t,silent:r?.silent??!1,reason:r?.reason};this.values[s]=t;for(let o of[...this.auditors])o(i);if(!i.silent)for(let o of[...this.subscribers])o(i);return i}subscribe(e){return this.subscribers.add(e),()=>this.subscribers.delete(e)}onAudit(e){return this.auditors.add(e),()=>this.auditors.delete(e)}rows(){return[...this.decls.entries()].map(([e,t])=>de(t,this.get(e),void 0,e,this.pathPrefix))}declarations(){return[...this.decls.values()]}clone(){let e=new n([],{normalise:this.norm,pathPrefix:this.pathPrefix});return e.decls=new Map(this.decls),Object.assign(e.values,structuredClone(this.values)),e}reseed(e){for(let t of Object.keys(this.values))delete this.values[t];this.decls.clear(),this.seed(e)}save(){return structuredClone(this.values)}load(e){for(let[t,r]of Object.entries(e))this.values[this.norm(t)]=r}};function de(n,e,t,r,s=""){let i=r??n.name.toLowerCase();return{name:i,path:s+i,type:n.type,value:e,default:n.default??P(n),...n.values!==void 0?{values:n.values}:{},...n.stages!==void 0?{stages:n.stages}:{},writable:t??n.writable??!0}}var _e=n=>n.toLowerCase(),J=1,V=class{scopes=new Map;parked=new Map;rev=0;get revision(){return this.rev}defineOwned(e,t,r){let s=typeof r=="string"?{pathPrefix:r}:r??{},i=new b(t,{pathPrefix:s.pathPrefix??`${e}.`,...s.normalise?{normalise:s.normalise}:{}});return this.mountOwned(e,i,s.owner!==void 0?{owner:s.owner}:void 0)}mountOwned(e,t,r){this.assertFree(e,r?.owner),this.scopes.set(e,{kind:"owned",bag:t,...r?.owner!==void 0?{owner:r.owner}:{}}),this.rev++;let s=this.parked.get(e);return s&&(t.load(s),this.parked.delete(e)),this}remove(e,t){let r=this.scopes.get(e);if(!r)throw new Error(`unknown scope \'@${e}\'`);return t?.keep&&r.kind==="owned"&&this.parked.set(e,r.bag.save()),this.scopes.delete(e),this.rev++,this}discardParked(e){if(e===void 0)this.parked.clear();else for(let t of[...this.parked.keys()])t.startsWith(e)&&this.parked.delete(t);return this}ownedBag(e){let t=this.scopes.get(e);if(!t||t.kind!=="owned")throw new Error(`\'@${e}\' is not an owned scope`);return t.bag}reseedOwned(e,t){return this.ownedBag(e).reseed(t),this}defineForeign(e,t,r=[],s=!0){let i=typeof s=="boolean"?{writable:s}:s;this.assertFree(e,i.owner);let o=i.normalise??_e,a=new Map;for(let c of r)a.set(o(c.name),c);return this.scopes.set(e,{kind:"foreign",resolver:t,decls:a,scopeWritable:i.writable??!0,norm:o,...i.owner!==void 0?{owner:i.owner}:{}}),this.rev++,this}has(e){return this.scopes.has(e)}get(e,t){let r=this.scopes.get(e);if(r)return r.kind==="owned"?r.bag.get(t):r.resolver.get(r.norm(t))}set(e,t,r,s){let i=this.scopes.get(e);if(!i)throw new Error(`unknown scope \'@${e}\'`);if(i.kind==="owned"){if(!s?.host&&!i.bag.writable(t))throw new Error(`\'@${e}.${t}\' is read-only`);i.bag.set(t,r,s?.host?{host:!0}:void 0);return}let o=i.norm(t);if(!i.resolver.set)throw new Error(`\'@${e}.${t}\' is read-only`);if(!s?.host&&!this.foreignWritable(i,o))throw new Error(`\'@${e}.${t}\' is read-only`);i.resolver.set(o,r)}foreignWritable(e,t){return e.resolver.set?e.decls.get(t)?.writable??e.scopeWritable:!1}listProperties(){let e=[];for(let[t,r]of this.scopes){let s=r.owner!==void 0?{owner:r.owner}:{};if(r.kind==="owned")for(let i of r.bag.rows())e.push({scope:t,...s,...i});else for(let[i,o]of r.decls)e.push({scope:t,...s,...de(o,r.resolver.get(i),this.foreignWritable(r,i),i,`${t}.`)})}return e}toEvalContext(e,t){let r=this.view(t?.aliases),s={};for(let[o,a]of r)s[o]=a.kind==="owned"?a.bag.values:a.resolver;let i=this.qualityLadders(r);return i.size===0?{scopes:s,host:e}:{scopes:s,host:e,qualities:(o,a)=>{let c=r.get(o);return c?i.get(o)?.get(Ue(c)(a)):void 0}}}view(e){let t=new Map(this.scopes);for(let[r,s]of Object.entries(e??{})){let i=this.scopes.get(s);if(!i)throw new Error(`alias \'@${r}\' names \'${s}\', which is not registered`);t.set(r,i)}return t}qualityLadders(e){let t=new Map;for(let[r,s]of e)for(let[i,o]of pe(s)){if(o.type!=="quality"||o.stages===void 0)continue;let a=t.get(r);a||(a=new Map,t.set(r,a)),a.set(i,o.stages)}return t}toSchema(e){let t=new Map;for(let[r,s]of this.view(e?.aliases)){let i=pe(s);if(i.length===0)continue;let o=new Map;for(let[a,c]of i)o.set(a,{type:c.type,enumValues:c.values,...c.stages!==void 0?{stages:c.stages}:{}});t.set(r,o)}return{properties:t}}save(){let e={};for(let[t,r]of this.scopes)r.kind==="owned"&&(e[t]=r.bag.save());for(let[t,r]of this.parked)e[t]=structuredClone(r);return e}load(e,t){t?.keepParked||this.parked.clear();for(let[r,s]of Object.entries(e)){let i=this.scopes.get(r);i?.kind==="owned"?i.bag.load(s):i||this.parked.set(r,structuredClone(s))}}saveFragment(){return{version:J,scopes:this.save()}}loadFragment(e){if(e.version!==J)throw new Error(`unsupported owned-state fragment version ${e.version} (supported: ${J})`);this.load(e.scopes)}assertFree(e,t){let r=this.scopes.get(e);if(!r)return;let s=r.owner!==void 0?` by ${r.owner}`:"",i=t!==void 0?` (wanted by ${t})`:"";throw new Error(`scope \'@${e}\' is already registered${s}${i}`)}};function pe(n){return n.kind==="foreign"?[...n.decls.entries()]:n.bag.declarations().map(e=>[n.bag.normalise(e.name),e])}function Ue(n){return n.kind==="foreign"?n.norm:e=>n.bag.normalise(e)}function P(n){if(n.default!==void 0)return n.default;switch(n.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"enum":return n.values?.[0]??"";case"flags":return[];case"quality":return n.stages?.[0]??"";default:return!1}}var ge=[{token:"patter",engine:"Patterplay",means:"Patter\'s shared globals"},{token:"story",engine:"Storylet Engine",means:"the Storylet Engine\'s shared @story properties"}];function O(n){return n.ctx.host??{}}var K={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(n,e){if(n.length!==2)throw new d("random(a, b) requires exactly 2 arguments");let t=O(e).nextRandom;if(!t)throw new d("random() called without a PRNG in context");let r=e.evaluate(n[0]),s=e.evaluate(n[1]);if(typeof r!="number"||typeof s!="number")throw new d("random(a, b) arguments must be numbers");if(!Number.isInteger(r)||!Number.isInteger(s))throw new d("random(a, b) arguments must be integers");let i=Math.min(r,s),o=Math.max(r,s);return Math.floor(t()*(o-i+1))+i}},check_flags:{minArgs:1,returnType:"boolean",flagDeltaArgs:!0,validate:he("check_flags"),eval(n,e){let t=ue(n[0],e,"check_flags");for(let r=1;r<n.length;r++){let s=n[r];if(s.kind!=="flagdelta")throw new d("check_flags() flag args must be +flagName or -flagName");if(s.sign==="+"?!t.includes(s.name):t.includes(s.name))return!1}return!0}},set_flags:{minArgs:1,returnType:"flags",flagDeltaArgs:!0,validate:he("set_flags"),eval(n,e){let t=[...ue(n[0],e,"set_flags")];for(let r=1;r<n.length;r++){let s=n[r];if(s.kind!=="flagdelta")throw new d("set_flags() flag args must be +flagName or -flagName");if(s.sign==="+")t.includes(s.name)||t.push(s.name);else{let i=t.indexOf(s.name);i>=0&&t.splice(i,1)}}return t}},visits:{minArgs:1,maxArgs:1,returnType:"number",validate:M("visits"),eval:(n,e)=>O(e).visits?.(L(n,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:M("seen"),eval:(n,e)=>(O(e).visits?.(L(n,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:M("patter_visits"),eval:(n,e)=>O(e).patterVisits?.(L(n,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:M("patter_seen"),eval:(n,e)=>(O(e).patterVisits?.(L(n,e,"patter_seen"))??0)>0}}},xt=ge.map(n=>n.token).filter(n=>n!=="patter"&&n!=="scene");function fe(n,e){let t=n.replace(/^@/,"").split(".");return t.length===2&&e(t[0])?{scope:t[0],name:t[1].toLowerCase()}:{scope:"patter",name:t.join(".").toLowerCase()}}function L(n,e,t){let r=e.evaluate(n[0]);if(typeof r!="string")throw new d(`${t}(id) requires a string node id`);return r}function M(n){return(e,t)=>{let r=e[0];r&&r.kind!=="string"&&t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(id): the argument must be a string id literal (a scene / block / node id)`})}}function ue(n,e,t){if(!n)throw new d(`${t}() requires at least one argument (the flags variable)`);let r=e.evaluate(n);if(Array.isArray(r))return r;if(r===!1||r===null||r===void 0)return[];throw new d(`${t}() first argument must be a flags property`)}function he(n){return(e,t)=>{if(e.length===0)return;let r=e[0];if(r.kind!=="scopedvar"){t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(): first argument must be a flags property reference (@name or @scope.name)`});return}let s=t.schema.properties.get(r.scope)?.get(r.name);if(s&&s.type!=="flags"){let i=r.scope===t.defaultScope?r.name:`${r.scope}.${r.name}`;t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(): \'@${i}\' is not a flags property (got ${s.type})`});return}for(let i=1;i<e.length;i++){let o=e[i];o.kind!=="flagdelta"?t.report({path:[...t.path,"args",i],kind:"wrong-arg-type",severity:"error",message:`${n}(): argument ${i+1} must be +flagName or -flagName`}):s?.type==="flags"&&s.enumValues&&!s.enumValues.includes(o.name)&&t.report({path:[...t.path,"args",i],kind:"unknown-flag-name",severity:"error",message:`${n}(): unknown flag \'${o.name}\'`,reference:o.name})}}}var We=/^@[A-Za-z0-9_.]+$/;function*Je(n){let e="",t=0;for(;t<n.length;){let r=n[t];if(r==="{"&&n[t+1]==="{"){e+="{",t+=2;continue}if(r==="}"&&n[t+1]==="}"){e+="}",t+=2;continue}if(r==="{"){let s=n.indexOf("}",t+1);if(s!==-1){let i=n.slice(t,s+1),o=n.slice(t+1,s).trim();if(o.startsWith("@")){e&&(yield{kind:"text",value:e},e=""),yield{kind:"slot",raw:i,inner:o,ref:We.test(o)?o:void 0},t=s+1;continue}e+=i,t=s+1;continue}}e+=r,t+=1}e&&(yield{kind:"text",value:e})}function Ke(n){return Array.isArray(n)?n.join(", "):typeof n=="boolean"?n?"true":"false":String(n)}function ze(n){return n===" "||n===" "||n===`\n`||n==="\\r"||n==="\\f"||n==="\\v"}function Ye(n){let e="",t=!1;for(let r of n){if(ze(r)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=r}return e}function me(n,e,t){if(e.length===0||n.indexOf(e)<0)return n;let r="",s=0,i=!1;for(;s<n.length;){if(n.startsWith(e,s)){let o=n.indexOf(t,s+e.length);if(o>=0){s=o+t.length,i=!0;continue}r+=n.slice(s);break}r+=n[s],s+=1}return i?Ye(r):n}function Se(n,e){if(n.indexOf("{")<0)return n;let t="";for(let r of Je(n)){if(r.kind==="text"){t+=r.value;continue}if(!r.ref){t+=r.raw;continue}let s=e(r.ref);t+=s===void 0?"":Ke(s)}return t}function C(n,e){for(let t of n){e(t);let r=t.children;r&&C(r,e)}}function Qe(n){return n.toLowerCase().replace(/[\'\u2019]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function S(n){let e=n.gameId?.trim();return e||Qe(n.name)}function z(n){return`cast:${n}`}var Y={open:"[",close:"]"},ye="SFX";var Q=3;function B(n){let e=new Set,t=[];for(let r of n)e.has(r)||(e.add(r),t.push(r));return t}function $(n){let e=new Map,t=(r,s)=>{let i=B([...s,...r.tags??[]]);if(e.set(r.id,i),r.type==="group"&&r.prompt&&e.set(r.prompt.id,B([...i,...r.prompt.tags??[]])),r.type==="group")for(let o of r.children)t(o,i);else for(let o of r.beats??[])e.set(o.id,B([...i,...o.tags??[]]))};for(let r of Object.values(n.scenes)){let s=B(r.tags??[]);e.set(r.id,s);for(let i of r.blocks){let o=B([...s,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var ve=new WeakMap,F="Patter",N=n=>n.replace(/%/g,"%25").replace(/\\//g,"%2F"),we=Symbol("ownsRegistry"),y={stage:n=>`patter/scene/${N(n)}`,flow:n=>`patter/flow/${N(n)}/`,flowGlobals:n=>`patter/flow/${N(n)}/patter`,flowScene:(n,e)=>`patter/flow/${N(n)}/scene/${N(e)}`},A=class{constructor(e){this.journal=e}journal},H=class n{host;defaultSeed;flowsById=new Map;allStrings;currentLocale;sourceDebug;sceneGameIdToId=new Map;blockGameIdToId=new Map;creationOptions;engineLog=[];engineSeq=0;engineTraceHandlers=new Set;constructor(e,t={}){this.creationOptions=t;let r=t.locale??e.locales.default,s=e.strings;this.allStrings=s,this.currentLocale=r;let i=s[r]??{},o=s[e.locales.default]??{},a=e.localisation,c=a?.mode==="ids"&&!a.sourceDebug;this.sourceDebug=a?.mode==="ids"&&!!a.sourceDebug,this.sourceDebug&&typeof console<"u"&&console.warn("[Patterplay] source-only DEBUG build: strings are the source language for debugging, not a shippable localised build.");let l=new Map;for(let g of e.cast??[])g.displayName&&l.set(g.name,g.displayName);this.defaultSeed=(t.seed??2654435769)>>>0;let p=new Map,f=new Map,u=new Map;for(let[g,h]of Object.entries(e.scenes)){this.sceneGameIdToId.set(S(h),g);let v=new Map;for(let m of h.blocks)f.set(m.id,{sceneId:g}),u.set(m.id,m),v.set(S(m),m.id),C(m.children,ae=>p.set(ae.id,ae));this.blockGameIdToId.set(g,v)}let re=e.properties??[],q=re.filter(g=>g.shared??!0).map(Ee),Fe=re.filter(g=>!(g.shared??!0)).map(Ee),Ae=new Set(q.map(g=>g.name.toLowerCase())),x=t.registry??new V,ne=!t.registry||t[we]===!0,se=new b(q,{pathPrefix:"@patter."}),ie=[],T=[];try{x.mountOwned("patter",se,{owner:F}),T.push("patter");let g=new Set;if(t.world){let h=e.scopeRegistry?.scopes.find(m=>m.token==="world"),v=(h?.declarations??[]).map(Re);x.defineForeign("world",t.world,v,{writable:h?.writable??!0,owner:F}),T.push("world"),g.add("world")}for(let h of ne?e.scopeRegistry?.scopes??[]:[]){if(g.has(h.token)||x.has(h.token))continue;let v=(h.declarations??[]).map(m=>Ze(m,h.writable));x.defineOwned(h.token,v,{owner:F}),T.push(h.token),ie.push(h.token)}}catch(g){for(let h of T)x.remove(h,{keep:!0});throw g}let oe=new Map;for(let[g,h]of Object.entries(e.scenes)){let v=new Set((h.sceneProps??[]).filter(m=>m.shared??!1).map(m=>m.name.toLowerCase()));oe.set(g,v)}this.host={logEnabled:t.log??!1,emitEngine:(g,h,v)=>this.emitEngine(g,h,v),bundle:e,emitIds:c,strings:i,defaultStrings:o,castDisplay:l,nodeIndex:p,blockIndex:f,blockById:u,sceneGameIdToId:this.sceneGameIdToId,blockGameIdToId:this.blockGameIdToId,tagIndex:$(e),registry:x,ownsRegistry:ne,patterBag:se,hostScopes:ie,patterSharedDecls:q,patterLocalDecls:Fe,patterSharedNames:Ae,sceneSharedNames:oe,sharedVisits:new Map,sharedSelectors:new Map,stageBags:new Map,journal:null,customRng:t.rng,onDryChoice:t.onDryChoice,onError:t.onError??(g=>console.warn(`Patterplay: ${g.kind} on ${g.node} in flow \'${g.flow}\' failed, played through: ${g.message}`)),replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??Y).open,captionClose:(e.closedCaptions??Y).close,captionCharacter:e.closedCaptions?.character||ye,refSplitCache:new Map,refSplitRevision:x.revision}}get locale(){return this.currentLocale}get isSourceDebug(){return this.sourceDebug}setLocale(e){this.currentLocale=e,this.host.strings=this.allStrings[e]??{}}replaceStrings(e){this.allStrings=e.strings,this.host.strings=this.allStrings[this.currentLocale]??{},this.host.defaultStrings=this.allStrings[this.host.bundle.locales.default]??{}}hotSwap(e){this.refuseInCheckpoint("hotSwap");let t=this.saveGame(),r=o=>(o.setLocale(this.currentLocale),o.setClosedCaptions(this.host.captionsOn),o),s=()=>new n(e,{...this.creationOptions,registry:this.host.registry,[we]:this.host.ownsRegistry});this.release(!0);let i=s();try{return i.loadGame(t),r(i)}catch{i.release(!0);let o=s();for(let[a,c]of Object.entries(t.flows)){let l=c.cursor.currentSceneId;try{o.openFlow(a,l!==null?{scene:l}:{})}catch{}}return r(o)}}get closedCaptions(){return this.host.captionsOn}setClosedCaptions(e){this.host.captionsOn=e}openFlow(e,t={}){this.assertExternalScopes();let{sceneId:r,blockId:s}=this.resolveOpenAddress(t.scene,t.block),i=this.flowsById.get(e),o=this.host.journal;if(o&&i&&!i.isClosed)throw new Error(`openFlow would replace the open flow \'${e}\', which can\'t be undone while a checkpoint is open`);i?.close();let a=new I(e,this.host,t.seed??this.defaultSeed);return o&&(o.flows.add(a),o.opened.add(a),o.undo.push(()=>{a.close(),i?this.flowsById.set(e,i):this.flowsById.delete(e)})),this.flowsById.set(e,a),a.start(r,s),a}runFlow(e,t,r){let s=this.flowsById.get(e);if(!s)return this.openFlow(e,{scene:t,block:r}).advanceToStop().played;if(!s.goto(t,r))throw new Error(`runFlow: address not found: ${t}${r===void 0?"":` / ${r}`}`);return s.advanceToStop().played}assertExternalScopes(){for(let e of this.host.bundle.externalScopes??[])if(!this.host.registry.has(e))throw new Error(`this content names @${e}, which no engine on this registry registered: give every engine the game\'s one registry`)}resolveOpenAddress(e,t){if(e!==void 0){let r=X(this.host,e);if(r===void 0)throw new Error(`unknown scene: ${e}`);if(t===void 0)return{sceneId:r};let s=Z(this.host,r,t);if(s===void 0)throw new Error(`unknown block: ${t}`);return{sceneId:r,blockId:s}}if(t!==void 0){if(!this.host.blockIndex.has(t))throw new Error(`unknown block: ${t}`);return{blockId:t}}if(Object.keys(this.host.bundle.scenes).length===0)throw new Error("no scenes in bundle");return{}}resolveSceneRef(e){if(e!=null)return X(this.host,e)??e}resolveBlockRef(e,t){if(t!=null)return e==null?t:Z(this.host,e,t)}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?S(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?S(t):void 0}tagsForBeat(e){return this.host.tagIndex.get(e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?this.host.tagIndex.get(t):void 0)??[]}tagsForBlock(e,t){let r=this.resolveSceneRef(e),s=this.resolveBlockRef(r,t);return(s!=null?this.host.tagIndex.get(s):void 0)??[]}gameDataForScene(e){let t=this.resolveSceneRef(e);return{...(t!=null?this.host.bundle.scenes[t]:void 0)?.gameData}}gameDataForBlock(e,t){let r=this.resolveBlockRef(this.resolveSceneRef(e),t);return{...(r!=null?this.host.blockById.get(r):void 0)?.gameData}}getCast(){let e=[];for(let t of this.host.bundle.cast??[])t?.name&&e.push(t.name);return e}castForScene(e){let t=this.resolveSceneRef(e),r=t!=null?this.host.bundle.scenes[t]:void 0;if(!r)return[];let s=new Set;for(let i of r.blocks)be(i.children,s);return[...s]}castForBlock(e,t){let r=this.resolveSceneRef(e),s=this.resolveBlockRef(r,t),i=s!=null?this.host.blockById.get(s):void 0;if(!i)return[];let o=new Set;return be(i.children,o),[...o]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...S(e)?{gameId:S(e)}:{},name:e.name,...xe(e.gameData),...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...S(t)?{gameId:S(t)}:{},name:t.name,...xe(t.gameData),...this.tagsField(t.id),children:t.children.map(r=>this.outlineNode(r))}))}))}getBeatSequence(){let e=[];for(let t of Object.values(this.host.bundle.scenes))for(let r of t.blocks)C(r.children,s=>{if(s.type==="snippet")for(let i of s.beats??[])e.push({sceneId:t.id,blockId:r.id,snippetId:s.id,beat:this.beatInfo(i)})});return e}outlineNode(e){return e.type==="group"?{type:"group",id:e.id,...this.tagsField(e.id),...e.selector?{selector:e.selector}:{},...e.prompt?{prompt:this.beatInfo(e.prompt)}:{},children:e.children.map(t=>this.outlineNode(t))}:{type:"snippet",id:e.id,...this.tagsField(e.id),beats:(e.beats??[]).map(t=>this.beatInfo(t)),...e.jump?{jumpTo:e.jump.to,...e.jump.mode?{jumpMode:e.jump.mode}:{}}:{}}}beatInfo(e){let t=this.host.tagIndex.get(e.id),r={id:e.id,kind:e.kind};if(e.kind==="line"){if(e.character!==void 0){r.character=e.character;let s=this.host.defaultStrings[z(e.character)]??this.host.castDisplay.get(e.character);s!==void 0&&(r.characterName=s)}e.direction!==void 0&&(r.direction=e.direction)}if(e.kind==="line"||e.kind==="text"){let s=this.host.defaultStrings[e.id];s!==void 0&&(r.text=s)}return e.gameData&&Object.keys(e.gameData).length&&(r.gameData=e.gameData),t&&t.length&&(r.tags=t),r}tagsField(e){let t=this.host.tagIndex.get(e);return t&&t.length?{tags:t}:{}}getFlow(e){return this.flowsById.get(e)}flows(){return[...this.flowsById.values()]}listBags(){let e=[{bag:this.host.patterBag}];for(let[t,r]of this.host.stageBags)e.push({bag:r,pathPrefix:`@scene:${t}.`});return e}checkpoint(){if(this.host.journal)throw new Error("a checkpoint is already open: roll it back or commit it first");let e={undo:[],flows:new Set,opened:new Set,selectors:new Set,flowSelectors:new Map};return this.host.journal=e,new A(e)}rollback(e){this.endCheckpoint(e);let t=e.journal.undo;for(let r=t.length-1;r>=0;r--)t[r]();n.forget(e.journal)}commit(e){this.endCheckpoint(e),n.forget(e.journal)}get inCheckpoint(){return this.host.journal!==null}endCheckpoint(e){if(this.host.journal!==e.journal)throw new Error("that checkpoint is not the open one");this.host.journal=null}static forget(e){e.undo=[],e.flows.clear(),e.opened.clear(),e.selectors.clear(),e.flowSelectors.clear()}refuseInCheckpoint(e){if(this.host.journal)throw new Error(`${e} can\'t be undone, so it isn\'t allowed while a checkpoint is open`)}closeFlow(e){this.refuseInCheckpoint("closeFlow"),this.flowsById.get(e)?.close(),this.flowsById.delete(e)}reset(){this.refuseInCheckpoint("reset");for(let e of this.flowsById.values())e.close();this.flowsById.clear(),this.host.patterBag.reseed(this.host.patterSharedDecls),this.host.sharedVisits.clear(),this.host.sharedSelectors.clear();for(let e of this.host.stageBags.keys())this.host.registry.remove(y.stage(e));this.host.stageBags.clear(),this.host.registry.discardParked("patter/")}release(e){for(let r of this.flowsById.values())r.releaseBags(e),r.close();this.flowsById.clear();let t=this.host.registry;for(let r of this.host.stageBags.keys())t.remove(y.stage(r),{keep:e});this.host.stageBags.clear();for(let r of["patter",...this.host.hostScopes])t.has(r)&&t.remove(r,{keep:e});this.creationOptions.world&&t.has("world")&&t.remove("world")}getProperty(e){let{scope:t,name:r}=this.splitShared(e);return this.host.registry.get(t,r)}setProperty(e,t){let{scope:r,name:s}=this.splitShared(e),i=this.host.journal?this.host.registry.get(r,s):void 0;this.host.registry.set(r,s,t,{host:!0}),this.host.journal&&i!==void 0&&this.host.journal.undo.push(()=>this.host.registry.set(r,s,i,{host:!0}))}log(){return this.engineLog}clearLog(){this.engineLog.length=0}onTrace(e){return this.engineTraceHandlers.add(e),()=>this.engineTraceHandlers.delete(e)}emitEngine(e,t,r){for(let s of this.engineTraceHandlers)s(e,t);this.host.logEnabled&&this.engineLog.push({...t,flow:e,seq:this.engineSeq++,...r?{scene:r}:{}})}listProperties(){return this.host.patterSharedDecls.map(e=>({name:e.name,path:`@patter.${e.name}`,type:e.type,values:e.values,stages:e.stages,value:this.getProperty(`@${e.name}`),default:P(e),writable:e.writable??!0}))}splitShared(e){let t=Pe(this.host,e);if(t.scope==="scene")throw new Error(`\'${e}\': @scene properties are scene-scoped - read/write them on a Flow, not the Engine`);return t}save(){return{patter:this.host.patterBag.save()}}load(e){e.patter&&this.host.patterBag.load(e.patter)}saveGame(){let e={};for(let[t,r]of this.flowsById)e[t]=r.snapshot();return{version:Q,...this.host.ownsRegistry?{registry:this.host.registry.save()}:{},sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:Ie(this.host.sharedSelectors),flows:e}}loadGame(e){this.refuseInCheckpoint("loadGame");let t=e.version;if(t!==2&&t!==Q)throw new Error(`unsupported save version: ${String(t)}`);let r=e.flows;if(typeof r!="object"||r===null||Array.isArray(r))throw new Error("malformed save: no flows");this.assertExternalScopes();let s=this.host.registry;for(let[o,a]of this.flowsById)a.releaseBags(o in e.flows),a.close();this.flowsById.clear();for(let o of this.host.stageBags.keys())s.remove(y.stage(o),{keep:!0});this.host.stageBags.clear();let i=e.version===2?et(e):e.registry;i&&(this.host.ownsRegistry?s.load(i):s.load(i,{keepParked:!0})),this.host.sharedVisits.clear();for(let[o,a]of Object.entries(e.sharedVisits??{}))this.host.sharedVisits.set(o,a);this.host.sharedSelectors.clear();for(let[o,a]of De(e.sharedSelectors))this.host.sharedSelectors.set(o,a);for(let[o,a]of Object.entries(e.flows)){let c=new I(o,this.host,this.defaultSeed);c.restore(a),this.flowsById.set(o,c)}}},I=class{id;host;local;registered=new Set;rngState;started=!1;flowEnded=!1;closed=!1;currentSceneId=null;stack=[];activeSnippet=null;beatIndex=0;pendingChoice=null;pendingPrompt=null;pendingPromptOwnerId=null;selectors=new Map;visitCounts=new Map;sceneBags=new Map;patterResolver={get:e=>this.host.patterSharedNames.has(e)?this.host.patterBag.get(e):this.local.get(e),set:(e,t)=>{this.host.patterSharedNames.has(e)?this.host.registry.set("patter",e,t):this.local.set(e,t)}};sceneResolver={get:e=>{let t=this.currentSceneId;if(t!==null)return this.sceneBagFor(t,e)?.get(e)},set:(e,t)=>{let r=this.currentSceneId;if(r===null)return;let s=this.sceneBagFor(r,e);s&&s.set(e,t)}};evalCtx;ctxRevision=-1;registryQualities;flowLog=[];flowSeq=0;constructor(e,t,r){this.id=e,this.host=t,this.rngState=R(r),this.local=this.newLocal(),this.evalCtx={scopes:{},host:{nextRandom:this.rng,visits:s=>this.visitCounts.get(s)??0,patterVisits:s=>this.host.sharedVisits.get(s)??0},qualities:(s,i)=>this.stagesFor(s,i)}}context(){let e=this.host.registry;if(e.revision!==this.ctxRevision){let t=e.toEvalContext(),r=this.evalCtx.scopes;for(let s of Object.keys(r))delete r[s];Object.assign(r,t.scopes),r.patter=this.patterResolver,r.scene=this.sceneResolver,this.registryQualities=t.qualities,this.ctxRevision=e.revision}return this.evalCtx}stagesFor(e,t){let r=t.toLowerCase(),s=i=>i?.find(o=>o.name.toLowerCase()===r&&o.type==="quality")?.stages;if(e==="patter")return s(this.host.patterSharedDecls)??s(this.host.patterLocalDecls);if(e==="scene"){let i=this.currentSceneId!=null?this.host.bundle.scenes[this.currentSceneId]:void 0;return s(i?.sceneProps)}return this.registryQualities?.(e,t)??s(this.host.bundle.scopeRegistry?.scopes.find(i=>i.token===e)?.declarations)}start(e,t){if(this.host.journal&&!this.host.journal.opened.has(this))throw new Error("a flow can\'t be started or reset while a checkpoint is open");if(this.releaseBags(!1),this.host.registry.discardParked(y.flow(this.id)),this.mountLocal(),this.selectors.clear(),this.visitCounts.clear(),this.stack=[],this.currentSceneId=null,this.flowEnded=!1,this.activeSnippet=null,this.beatIndex=0,this.pendingChoice=null,this.started=!0,t){let r=this.host.blockIndex.get(t);if(!r)throw new Error(`unknown block: ${t}`);this.enterSceneSetup(r.sceneId),this.stack=[{sceneId:r.sceneId,containerId:t,index:0}],this.enter(t)}else{let r=e??Object.keys(this.host.bundle.scenes)[0],s=r?this.host.bundle.scenes[r]:void 0;if(!s)throw new Error(r?`unknown scene: ${r}`:"no scenes in bundle");this.enterSceneSetup(r);let i=s.blocks[0];i&&(this.stack=[{sceneId:r,containerId:i.id,index:0}],this.enter(i.id))}this.settle()}reset(e,t){this.start(e,t)}goto(e,t){if(this.closed)return!1;if(this.touch(),e==="END")return this.started=!0,this.pendingChoice=null,this.pendingPrompt=null,this.pendingPromptOwnerId=null,this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!0,this.stack=[],!0;let r=X(this.host,e);if(r===void 0)return!1;let s;return t!==void 0&&(s=Z(this.host,r,t),s===void 0)?!1:this.started?(this.pendingChoice=null,this.pendingPrompt=null,this.pendingPromptOwnerId=null,this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!1,this.enterTarget(s??r,"jump"),this.settle(),!0):(this.start(r,s),!0)}close(){this.releaseBags(!1),this.closed=!0,this.flowEnded=!0,this.stack=[],this.activeSnippet=null,this.beatIndex=0,this.pendingChoice=null,this.pendingPrompt=null,this.pendingPromptOwnerId=null}touch(){let e=this.host.journal;if(!e||e.flows.has(this))return;e.flows.add(this);let{rngState:t,started:r,flowEnded:s,currentSceneId:i,activeSnippet:o,beatIndex:a,pendingChoice:c,pendingPrompt:l,pendingPromptOwnerId:p}=this,f=this.stack.map(u=>({...u}));e.undo.push(()=>{Object.assign(this,{rngState:t,started:r,flowEnded:s,currentSceneId:i,activeSnippet:o,beatIndex:a,pendingChoice:c,pendingPrompt:l,pendingPromptOwnerId:p,stack:f})})}get isClosed(){return this.closed}get currentScene(){return this.currentSceneId}advance(){if(this.closed)return{type:"end"};if(!this.started)throw new Error("flow has not been started");if(this.touch(),this.pendingPrompt){let e=this.pendingPrompt;return this.pendingPrompt=null,this.pendingPromptOwnerId=null,e.shown?this.promptResult(e.beat,e.shown):this.beatResult(e.beat)}return this.settle(),this.flowEnded?{type:"end"}:this.pendingChoice?{type:"choice",groupId:this.pendingChoice.groupId,options:this.pendingChoice.options}:this.activeSnippet?this.beatResult(this.activeSnippet.beats[this.beatIndex++]):(this.flowEnded=!0,{type:"end"})}advanceToStop(){let e=[];for(;;){let t=this.advance();if(t.type==="choice"||t.type==="end")return{played:e,stop:t};e.push(t)}}settle(){let e=0;for(;;){if(++e>1e4)throw new Error("flow did not settle after 10000 transitions - likely a jump cycle with no deliverable content");if(this.flowEnded||this.pendingChoice)return;if(this.activeSnippet){if(this.beatIndex<(this.activeSnippet.beats?.length??0))return;this.runEffects(this.activeSnippet.onExit,this.activeSnippet.id);let i=this.activeSnippet.jump;this.activeSnippet=null,this.beatIndex=0,this.resolveJump(i);continue}let t=this.stack[this.stack.length-1];if(!t){this.flowEnded=!0;return}t.sceneId!==this.currentSceneId&&(this.currentSceneId=t.sceneId);let r=this.childrenOf(t.containerId);if(!r){this.stack.pop();continue}let s=t.index;for(;t.index<r.length&&!this.eligible(r[t.index]);)t.index++;if(this.host.logEnabled&&t.index!==s&&this.emit({type:"select",group:t.containerId,selector:"run",children:r.slice(s,t.index+1).map((i,o)=>({id:i.id,eligible:s+o===t.index})),picked:r[t.index]?.id??null}),t.index>=r.length){this.stack.pop();continue}this.enterChild(r[t.index++])}}listBags(){let e=[{bag:this.local,pathPrefix:`${this.id}/@patter.`}];for(let[t,r]of this.sceneBags)e.push({bag:r,pathPrefix:`${this.id}/@scene:${t}.`});return e}log(){return this.flowLog}clearLog(){this.flowLog.length=0}emit(e){let t=this.currentSceneId??void 0;this.host.emitEngine(this.id,e,t),this.host.logEnabled&&this.flowLog.push({...e,seq:this.flowSeq++,...t?{scene:t}:{}})}getChoices(){return this.pendingChoice?.options??[]}choose(e){let t=this.pendingChoice;if(!t)throw new Error("no choice is pending");let r=t.options.find(o=>o.id===e);if(!r)throw new Error(`unknown choice option: ${e}`);if(!r.eligible)throw new Error(`choice option is not eligible: ${e}`);this.touch();let s=t.byId.get(e);this.emit({type:"chose",group:t.groupId,option:e}),this.pendingChoice=null;let i=this.host.replayPromptOnChoose?this.authoredPromptOf(s):void 0;this.pendingPrompt=i&&r.prompt?{beat:i,shown:{...r.prompt}}:null,this.pendingPromptOwnerId=this.pendingPrompt?s.id:null,this.enterChild(s)}isEnded(){return this.flowEnded}getProperty(e){let{scope:t,name:r}=this.splitRef(e);return t==="patter"?this.patterResolver.get(r):t==="scene"?this.sceneResolver.get(r):this.host.registry.get(t,r)}setProperty(e,t){this.writeProperty(e,t,!0)}writeProperty(e,t,r){let{scope:s,name:i}=this.splitRef(e),o=this.host.journal;if(s==="patter"){if(o){let a=this.host.patterSharedNames.has(i),c=a?this.host.patterBag.get(i):this.local.get(i),l=this.local;c!==void 0&&o.undo.push(a?()=>this.host.registry.set("patter",i,c):()=>l.set(i,c))}this.patterResolver.set(i,t)}else if(s==="scene"){if(this.currentSceneId===null)throw new Error(`\'${e}\': the flow has not entered a scene yet`);if(o){let a=this.sceneBagFor(this.currentSceneId,i),c=a?.get(i);a&&c!==void 0&&o.undo.push(()=>a.set(i,c))}this.sceneResolver.set(i,t)}else{let a=o?this.host.registry.get(s,i):void 0;this.host.registry.set(s,i,t,r?{host:!0}:void 0),o&&a!==void 0&&o.undo.push(()=>this.host.registry.set(s,i,a,{host:!0}))}}snapshot(){return{rngState:this.rngState,visits:Object.fromEntries(this.visitCounts),cursor:{flowEnded:this.flowEnded,currentSceneId:this.currentSceneId,stack:this.stack.map(e=>{let t=this.childrenOf(e.containerId)?.[e.index];return t?{...e,nextId:t.id}:{...e}}),activeSnippetId:this.activeSnippet?.id??null,beatIndex:this.beatIndex,pendingChoice:this.pendingChoice?{groupId:this.pendingChoice.groupId,options:this.pendingChoice.options.map(e=>({...e}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,...this.pendingPrompt?.shown?{pendingPrompt:Xe(this.pendingPrompt.shown)}:{},selectors:Ie(this.selectors)}}}restore(e){if(this.host.journal)throw new Error("a flow can\'t be restored while a checkpoint is open");this.restoreCursor(e),this.releaseBags(!0),this.mountLocal();for(let t of new Set([this.currentSceneId,...this.stack.map(r=>r.sceneId)]))t!==null&&this.host.bundle.scenes[t]&&this.ensureSceneBags(t)}restoreCursor(e){this.rngState=R(e.rngState),this.visitCounts=new Map(Object.entries(e.visits??{}));let t=e.cursor;if(this.started=!0,this.flowEnded=t.flowEnded,this.beatIndex=t.beatIndex,this.currentSceneId=t.currentSceneId,this.stack=t.stack.map(r=>{let{nextId:s,...i}=r;if(s!==void 0){let o=this.childrenOf(i.containerId)?.findIndex(a=>a.id===s)??-1;if(o>=0)return{...i,index:o}}return{...i}}),this.activeSnippet=null,t.activeSnippetId!==null){let r=this.host.nodeIndex.get(t.activeSnippetId);r&&r.type==="snippet"&&(this.activeSnippet=r)}if(this.selectors=De(t.selectors),this.pendingChoice=null,t.pendingChoice!==null){let r=new Map,s=[];for(let i of t.pendingChoice.options){let o=this.host.nodeIndex.get(i.id);o&&(r.set(i.id,o),s.push({...i}))}s.length>0&&(this.pendingChoice={groupId:t.pendingChoice.groupId,options:s,byId:r})}if(this.pendingPrompt=null,this.pendingPromptOwnerId=t.pendingPromptOwnerId??null,this.pendingPromptOwnerId){let r=this.host.nodeIndex.get(this.pendingPromptOwnerId),s=r?this.authoredPromptOf(r):void 0;s?this.pendingPrompt={beat:s,...t.pendingPrompt?{shown:{...t.pendingPrompt}}:{}}:this.pendingPromptOwnerId=null}}enterSceneSetup(e){let t=this.host.bundle.scenes[e];if(!t)throw new Error(`unknown scene: ${e}`);this.currentSceneId=e,this.enter(e),this.seedScene(t),this.runEffects(t.onEntry,t.id)}enterChild(e){if(this.enter(e.id),e.type==="snippet"){this.beginSnippet(e);return}let t=e.selector??"run";if(t==="run"){this.stack.push({sceneId:this.currentSceneId,containerId:e.id,index:0});return}if(t==="choice"){this.setupChoice(e);return}let r=this.selectChild(e);r&&this.enterChild(r)}childrenOf(e){let t=this.host.blockById.get(e);if(t)return t.children;let r=this.host.nodeIndex.get(e);if(r&&r.type==="group")return r.children}beginSnippet(e){this.runEffects(e.onEnter,e.id),this.activeSnippet=e,this.beatIndex=0}setupChoice(e){let t=[],r=new Map,s=[];for(let o of e.children){if(o.fallback===!0){s.push(o);continue}if(o.sticky!==!0&&(this.visitCounts.get(o.id)??0)>=1)continue;let a=this.eligible(o),c=o.secretUntilEligible===!0;!a&&c||(t.push({id:o.id,prompt:this.promptFor(o),eligible:a,gameData:o.gameData}),r.set(o.id,o))}if(t.some(o=>o.eligible)){this.emit({type:"choice",group:e.id,options:t.map(o=>({id:o.id,eligible:o.eligible}))}),this.pendingChoice={groupId:e.id,options:t,byId:r};return}let i=s.find(o=>this.eligible(o));if(i){this.enterChild(i);return}this.emit({type:"dry",group:e.id}),this.host.onDryChoice?.(e.id)}resolveJump(e){e&&this.enterTarget(e.to,e.mode==="call"?"call":"jump")}enterTarget(e,t){if(this.emit({type:"jump",to:e,mode:t}),e==="END"){this.flowEnded=!0,this.stack=[];return}let r,s,i=this.host.bundle.scenes[e];if(i){this.enterSceneSetup(e);let a=i.blocks[0];if(!a){t==="jump"&&(this.stack=[]);return}r=e,s=a.id}else{let a=this.host.blockIndex.get(e);if(!a)throw new Error(`jump target not found: ${e}`);a.sceneId!==this.currentSceneId&&this.enterSceneSetup(a.sceneId),r=a.sceneId,s=e}this.enter(s);let o={sceneId:r,containerId:s,index:0};t==="call"?this.stack.push(o):this.stack=[o]}selectChild(e){let t=e.children.map(c=>({id:c.id,eligible:this.eligible(c)})),r=e.children.filter((c,l)=>t[l].eligible),s=e.options?.order??"sequential",i=e.options?.exhaust??"once",o=c=>(this.emit({type:"select",group:e.id,selector:e.selector??"default",...e.selector==="sequence"?{order:s,exhaust:i}:{},children:t,picked:c?.id??null}),c);if(r.length===0)return o(null);let a=this.selectorState(e);switch(e.selector){case"branch":return o(r[0]);case"sequence":return o(s==="shuffle"?this.pickShuffle(r,i,a):s==="specificity"?this.pickSpecificity(r,i,a):this.pickSequential(r,i,a));default:return null}}pickSequential(e,t,r){let s=e.length,i=r.seq??0;return r.seq=i+1,t==="repeat"?e[i%s]:i<s?e[i]:t==="stick"?e[s-1]:null}pickShuffle(e,t,r){let s=e.length,i=t==="stick",o=()=>(i?e.slice(0,s-1):e).map(u=>u.id),a=new Set(e.map(u=>u.id));if(r.bag===void 0&&(r.bag=o()),!r.bag.some(u=>a.has(u))){if(t==="once")return null;if(i){let u=e[s-1];return r.last=u.id,u}if(r.bag=o(),r.bag.length===0)return null}let c=r.bag.filter(u=>a.has(u)),l=r.last!==void 0&&c.length>1?c.indexOf(r.last):-1,p=Math.floor(this.rng()*(l>=0?c.length-1:c.length));l>=0&&p>=l&&p++;let f=c[p];return r.bag.splice(r.bag.indexOf(f),1),r.last=f,e.find(u=>u.id===f)}pickSpecificity(e,t,r){let s=e;if(t!=="repeat"){r.bag===void 0&&(r.bag=e.map(p=>p.id));let l=new Set(r.bag);if(s=e.filter(p=>l.has(p.id)),s.length===0)return t==="stick"&&r.last!==void 0?e.find(p=>p.id===r.last)??null:null}let i=-1,a=s.map(l=>{let p=this.specScore(l);return p>i&&(i=p),{c:l,s:p}}).filter(l=>l.s===i).map(l=>l.c),c;if(a.length===1)c=a[0];else{let l=r.last!==void 0?a.findIndex(f=>f.id===r.last):-1,p=Math.floor(this.rng()*(l>=0?a.length-1:a.length));l>=0&&p>=l&&p++,c=a[p]}return t!=="repeat"&&(r.bag=r.bag.filter(l=>l!==c.id)),r.last=c.id,c}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0,e):0}matchedSpec(e,t,r){return le(e,i=>{try{return Ce(G(i,this.context(),K))}catch(o){return this.reportError("best-match",r.id,r.condition,o),!1}},{want:t})}selectorState(e){let t=e.shared?this.host.sharedSelectors:this.selectors,r=this.host.journal,s;if(r&&(s=e.shared?r.selectors:r.flowSelectors.get(this),s||(s=new Set,r.flowSelectors.set(this,s))),r&&s&&!s.has(e.id)){s.add(e.id);let o=t.get(e.id),a=o?{...o,...o.bag?{bag:[...o.bag]}:{}}:void 0;r.undo.push(()=>{a?t.set(e.id,a):t.delete(e.id)})}let i=t.get(e.id);return i||(i={},t.set(e.id,i)),i}runEffects(e,t){for(let r of e??[]){let s;try{s=this.evalExpr(r.value);let i=this.host.logEnabled?this.getProperty(r.target):void 0;this.writeProperty(r.target,s,!1),this.emit({type:"write",target:r.target,value:s,...i!==void 0?{prev:i}:{}})}catch(i){this.reportError("effect",t,r.value,i)}}}eligible(e){if(!e.condition)return!0;try{return Ce(this.evalExpr(e.condition))}catch(t){return this.reportError("condition",e.id,e.condition,t),!1}}reportError(e,t,r,s){let i=s instanceof Error?s.message:String(s),o=r?.src;this.host.onError({flow:this.id,kind:e,node:t,...o?{source:o}:{},message:i}),this.emit({type:"diagnostic",kind:e,node:t,...o?{source:o}:{},message:i})}evalExpr(e){return G(this.conditionAst(e),this.context(),K)}conditionAst(e){let t=ve.get(e);return t||(t=k(e.ast),ve.set(e,t)),t}enter(e){let t=this.visitCounts,r=t.get(e);t.set(e,(r??0)+1);let s=this.host.sharedVisits,i=s.get(e);s.set(e,(i??0)+1),this.host.journal&&this.host.journal.undo.push(()=>{r===void 0?t.delete(e):t.set(e,r),i===void 0?s.delete(e):s.set(e,i)})}rng=()=>{if(this.host.customRng)return this.host.customRng();let e=W(this.rngState),t=e.next();return this.rngState=e.state(),t};beatResult(e){let t=this.host.tagIndex.get(e.id),r=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:e.gameData,...r};case"text":return{type:"text",id:e.id,text:this.interpolate(this.resolveString(e.id)),gameData:e.gameData,...r};case"line":{let s=this.resolveString(e.id),i=!this.host.captionsOn,a=i&&e.character===this.host.captionCharacter?"":this.captionLine(this.host.bundle.voiced?s:this.interpolate(s)),c=i&&a.length===0;return{type:"line",id:e.id,text:a,character:c?void 0:e.character,characterName:c?void 0:this.resolveCharacterName(e.character),direction:c?void 0:e.direction,gameData:e.gameData,...r}}}}interpolate(e){return Se(e,t=>this.getProperty(t))}stripCaptions(e){return me(e,this.host.captionOpen,this.host.captionClose)}captionLine(e){return this.host.captionsOn?e:this.stripCaptions(e)}promptFor(e){let t=this.promptBeatOf(e);if(!t)return;let r=this.interpolate(this.resolveString(t.id));return t.kind==="line"?{kind:"line",text:this.captionLine(r),character:t.character,characterName:this.resolveCharacterName(t.character),direction:t.direction}:{kind:"text",text:r}}authoredPromptOf(e){return e.type==="group"?e.prompt:void 0}promptResult(e,t){let r=this.host.tagIndex.get(e.id),s=r&&r.length?{tags:r}:{};return t.kind==="text"?{type:"text",id:e.id,text:t.text,gameData:e.gameData,...s}:{type:"line",id:e.id,text:t.text,character:t.character,characterName:t.characterName,direction:t.direction,gameData:e.gameData,...s}}promptBeatOf(e){return e.type==="group"&&e.prompt?e.prompt:((e.type==="snippet"?e:this.firstTextSnippetIn(e.children))?.beats??[]).find(r=>r.kind==="line"||r.kind==="text")}firstTextSnippetIn(e){let t;return C(e,r=>{!t&&r.type==="snippet"&&(r.beats??[]).some(s=>s.kind==="line"||s.kind==="text")&&(t=r)}),t}resolveString(e){if(this.host.emitIds)return e;let t=this.host.strings[e];if(t!==void 0)return t;let r=this.host.defaultStrings[e];return r!==void 0?`<Untranslated: ${e}> ${r}`:e}resolveCharacterName(e){if(e===void 0||this.host.emitIds)return;let t=z(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}splitRef(e){return Pe(this.host,e)}newLocal(){return new b(this.host.patterLocalDecls,{pathPrefix:"@patter."})}mountLocal(){this.local=this.newLocal();let e=y.flowGlobals(this.id);this.host.registry.mountOwned(e,this.local,{owner:F}),this.registered.add(e)}releaseBags(e){for(let t of this.registered)this.host.registry.remove(t,{keep:e});this.registered.clear(),this.sceneBags.clear()}sceneBagFor(e,t){if(this.host.bundle.scenes[e])return this.ensureSceneBags(e),this.host.sceneSharedNames.get(e)?.has(t.toLowerCase())?this.host.stageBags.get(e):this.sceneBags.get(e)}ensureSceneBags(e){let t=this.host.sceneSharedNames.get(e)??new Set,r=this.host.bundle.scenes[e]?.sceneProps??[],s=this.host.journal;if(!this.sceneBags.has(e)){let i=new b(r.filter(c=>!t.has(c.name.toLowerCase())),{pathPrefix:"@scene."}),o=y.flowScene(this.id,e),a=ke(this.host.registry,o,i,s!==null);this.registered.add(o),this.sceneBags.set(e,i),s&&s.undo.push(()=>{this.sceneBags.get(e)===i&&(this.host.registry.remove(o,a?{keep:!0}:void 0),this.registered.delete(o),this.sceneBags.delete(e))})}if(!this.host.stageBags.has(e)){let i=new b(r.filter(a=>t.has(a.name.toLowerCase())),{pathPrefix:"@scene."}),o=ke(this.host.registry,y.stage(e),i,s!==null);this.host.stageBags.set(e,i),s&&s.undo.push(()=>{this.host.stageBags.get(e)===i&&(this.host.registry.remove(y.stage(e),o?{keep:!0}:void 0),this.host.stageBags.delete(e))})}}seedScene(e){let t=this.host.sceneSharedNames.get(e.id)??new Set;this.ensureSceneBags(e.id);for(let r of e.sceneProps??[]){if(!r.temporary)continue;let s=r.name.toLowerCase(),i=t.has(s)?this.host.stageBags.get(e.id):this.sceneBags.get(e.id);if(!i)continue;let o=this.host.journal?i.get(s):void 0;o!==void 0&&this.host.journal.undo.push(()=>i.set(s,o)),i.set(s,P(r))}}};function be(n,e){C(n,t=>{if(t.type==="group"){t.prompt?.kind==="line"&&t.prompt.character&&e.add(t.prompt.character);return}for(let r of t.beats??[])r.kind==="line"&&r.character&&e.add(r.character)})}function xe(n){return n&&Object.keys(n).length?{gameData:n}:{}}function Xe(n){let e={kind:n.kind,text:n.text};return n.character!==void 0&&(e.character=n.character),n.characterName!==void 0&&(e.characterName=n.characterName),n.direction!==void 0&&(e.direction=n.direction),e}function Ie(n){let e={};for(let[t,r]of n){let s={};r.seq!==void 0&&(s.seq=r.seq),r.bag&&(s.bag=[...r.bag]),r.last!==void 0&&(s.last=r.last),e[t]=s}return e}function De(n){let e=new Map;for(let[t,r]of Object.entries(n??{})){let s={};r.seq!==void 0&&(s.seq=r.seq),r.bag&&(s.bag=[...r.bag]),r.last!==void 0&&(s.last=r.last),e.set(t,s)}return e}function ke(n,e,t,r){let s=r?JSON.stringify(t.save()):"";return n.mountOwned(e,t,{owner:F}),r&&JSON.stringify(t.save())!==s}function Ee(n){return{name:n.name,type:n.type,values:n.values,stages:n.stages,default:n.default}}function Re(n){return{name:n.name,type:n.type,values:n.values,stages:n.stages,default:n.default,writable:n.writable}}function Ze(n,e){let t=Re(n),r=n.writable??e;return r===void 0?t:{...t,writable:r}}function X(n,e){return n.sceneGameIdToId.get(e)??(n.bundle.scenes[e]?e:void 0)}function Z(n,e,t){return n.blockGameIdToId.get(e)?.get(t)??(n.blockIndex.get(t)?.sceneId===e?t:void 0)}function Pe(n,e){n.refSplitRevision!==n.registry.revision&&(n.refSplitCache.clear(),n.refSplitRevision=n.registry.revision);let t=n.refSplitCache.get(e);return t||(t=fe(e,r=>r==="scene"||n.registry.has(r)||(n.bundle.externalScopes?.includes(r)??!1)),n.refSplitCache.set(e,t)),t}function et(n){let e={};n.shared?.patter&&(e.patter=n.shared.patter);for(let[t,r]of Object.entries(n.stageBags??{}))e[y.stage(t)]=r;for(let[t,r]of Object.entries(n.flows??{})){r.scopes?.patter&&(e[y.flowGlobals(t)]=r.scopes.patter);for(let[s,i]of Object.entries(r.sceneBags??{}))e[y.flowScene(t,s)]=i}return e}function Ce(n){return typeof n=="boolean"?n:typeof n=="number"?n!==0:typeof n=="string"?n!=="":n.length>0}var tt=(n,e)=>n.shared??e;function ee(n,e){return{name:n.name,type:n.type,hasDefault:n.default!==void 0,...n.default!==void 0?{default:n.default}:{},shared:tt(n,e)}}function rt(n){return{name:n.name,type:n.type,hasDefault:n.default!==void 0,...n.values?{values:[...n.values]}:{},...n.purpose?{purpose:n.purpose}:{}}}function nt(n,e){e.blocks++;let t=[...n.children];for(;t.length;){let r=t.pop();if(r.type==="group"){e.groups++,r.prompt&&e.prompts++,t.push(...r.children);continue}e.snippets++;for(let s of r.beats??[])e.beats++,s.kind==="gameEvent"&&e.gameEvents++}}function Oe(n){let e={scenes:0,blocks:0,groups:0,snippets:0,beats:0,prompts:0,gameEvents:0,cast:n.cast?.length??0},t=[],r=[];for(let o of Object.values(n.scenes)){e.scenes++;let a=S(o);t.push({gameId:a,name:o.name,blocks:o.blocks.map(c=>({gameId:S(c),name:c.name}))});for(let c of o.blocks)nt(c,e);o.sceneProps?.length&&r.push({gameId:a,properties:o.sceneProps.map(c=>ee(c,!1))})}let s=(n.scopeRegistry?.scopes??[]).map(o=>({token:o.token,writable:o.writable??!0,opaque:o.declarations===void 0,properties:(o.declarations??[]).map(a=>ee(a,!0))})),i=Object.entries(n.gameDataFields??{}).filter(([,o])=>(o?.length??0)>0).map(([o,a])=>({kind:o,fields:(a??[]).map(rt)}));return{identity:{schema:n.schema,project:n.content.project,...n.content.version!==void 0?{version:n.content.version}:{},...n.content.hash!==void 0?{hash:n.content.hash}:{},...n.content.structureHash!==void 0?{structureHash:n.content.structureHash}:{},voiced:n.voiced,defaultLocale:n.locales.default,locales:[...n.locales.included],localisation:n.localisation?.mode??"embedded",sourceDebug:n.localisation?.sourceDebug??!1},addresses:t,hostScopes:s,properties:{patter:(n.properties??[]).map(o=>ee(o,!0)),scene:r},gameData:i,counts:e}}function Be(n,e){return n.gameDataFields?.[e]??[]}function te(n,e,t){return e&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:n.find(r=>r.name===t)?.default}function Ne(n,e){let t={};for(let r of n){let s=te(n,e,r.name);s!==void 0&&(t[r.name]=s)}for(let[r,s]of Object.entries(e??{}))r in t||(t[r]=s);return t}return Me(st);})();\n';
|
|
200807
|
+
var PLAYABLE_RUNTIME_JS = 'var Patterplay=(()=>{var U=Object.defineProperty;var Ve=Object.getOwnPropertyDescriptor;var Le=Object.getOwnPropertyNames;var Me=Object.prototype.hasOwnProperty;var $e=(n,e)=>{for(var t in e)U(n,t,{get:e[t],enumerable:!0})},He=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Le(e))!Me.call(n,s)&&s!==t&&U(n,s,{get:()=>e[s],enumerable:!(r=Ve(e,s))||r.enumerable});return n};var qe=n=>He(U({},"__esModule",{value:!0}),n);var at={};$e(at,{Checkpoint:()=>A,Engine:()=>q,Flow:()=>I,buildTagIndex:()=>H,describeBundle:()=>Ne,effectiveGameData:()=>Ae,gameDataFields:()=>Fe,gameDataValue:()=>ne});function D(n,e){return n!==void 0&&Object.prototype.hasOwnProperty.call(n,e)?n[e]:void 0}function k(n){switch(n[0]){case"b":return{kind:"bool",value:n[1]};case"n":return{kind:"number",value:n[1]};case"s":return{kind:"string",value:n[1]};case"sv":return{kind:"scopedvar",scope:n[1],name:n[2]};case"u":return{kind:"unary",op:n[1],operand:k(n[2])};case"bin":return{kind:"binary",op:n[1],left:k(n[2]),right:k(n[3])};case"call":{let e=n.slice(2).map(k);return{kind:"call",name:n[1],args:e}}case"fd":return{kind:"flagdelta",sign:n[1],name:n[2]}}}var d=class extends Error{constructor(e){super(e),this.name="EvalError"}};function j(n,e,t){let r=new Map(t.scopes.map(i=>[i.token,i.missing??"false"])),s=i=>{switch(i.kind){case"bool":return i.value;case"number":return i.value;case"string":return i.value;case"scopedvar":{let o=D(e.scopes,i.scope);if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):D(o,i.name);if(a===void 0){if(r.get(i.scope)==="throw")throw new d(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{if(i.name==="advance"&&!D(t.functions,i.name)){let a=i.args[0];if(i.args.length!==1||a===void 0)throw new d(`advance() takes exactly 1 argument, got ${i.args.length}`);let c=W(a,e);if(c===void 0)throw new d("advance() needs a quality reference (@scope.name of a quality property)");let l=w(s(a),c,"advance");return c[Math.min(l+1,c.length-1)]}let o=D(t.functions,i.name);if(!o)throw new d(`unknown function \'${i.name}\'`);return o.eval(i.args,{evaluate:s,ctx:e})}case"flagdelta":throw new d("flagdelta node is only valid as an argument to a flag-delta function");case"unary":{if(i.op==="not"){let a=s(i.operand);if(typeof a!="boolean")throw new d(`\'not\' requires a boolean operand, got ${typeof a}`);return!a}let o=s(i.operand);if(typeof o!="number")throw new d(`unary \'-\' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let f=s(i.left);if(typeof f!="boolean")throw new d(`\'and\' requires boolean operands, left is ${typeof f}`);if(!f)return!1;let u=s(i.right);if(typeof u!="boolean")throw new d(`\'and\' requires boolean operands, right is ${typeof u}`);return u}if(i.op==="or"){let f=s(i.left);if(typeof f!="boolean")throw new d(`\'or\' requires boolean operands, left is ${typeof f}`);if(f)return!0;let u=s(i.right);if(typeof u!="boolean")throw new d(`\'or\' requires boolean operands, right is ${typeof u}`);return u}let o=s(i.left),a=s(i.right),c=W(i.left,e),l=W(i.right,e),p=c??l;if(p!==void 0){if(c&&l&&!_e(c,l)&&(i.op===">"||i.op===">="||i.op==="<"||i.op==="<="))throw new d(`\'${i.op}\' compares two different qualities, whose stage orders are unrelated`);switch(i.op){case">":return w(o,p,">")>w(a,p,">");case">=":return w(o,p,">=")>=w(a,p,">=");case"<":return w(o,p,"<")<w(a,p,"<");case"<=":return w(o,p,"<=")<=w(a,p,"<=");case"+":case"-":case"*":case"/":throw new d(`\'${i.op}\' cannot be applied to a quality - a stage is a position, not a number; use advance() to move it`);default:break}}switch(i.op){case"==":return le(o,a);case"!=":return!le(o,a);case">":return E(o,a,">"),o>a;case">=":return E(o,a,">="),o>=a;case"<":return E(o,a,"<"),o<a;case"<=":return E(o,a,"<="),o<=a;case"+":if(typeof o=="number"&&typeof a=="number"||typeof o=="string"&&typeof a=="string")return o+a;throw new d(`\'+\' requires two numbers or two strings, got ${typeof o} and ${typeof a}`);case"-":return E(o,a,"-"),o-a;case"*":return E(o,a,"*"),o*a;case"/":if(E(o,a,"/"),a===0)throw new d("division by zero");return o/a}}}};return s(n)}function le(n,e){if(Array.isArray(n)||Array.isArray(e)){if(!Array.isArray(n)||!Array.isArray(e)||n.length!==e.length)return!1;let t=[...n].sort(),r=[...e].sort();for(let s=0;s<t.length;s++)if(t[s]!==r[s])return!1;return!0}return n===e}function E(n,e,t){if(typeof n!="number"||typeof e!="number")throw new d(`\'${t}\' requires numeric operands, got ${typeof n} and ${typeof e}`)}function W(n,e){if(!(n.kind!=="scopedvar"||e.qualities===void 0))return e.qualities(n.scope,n.name)}function w(n,e,t){if(typeof n!="string")throw new d(`\'${t}\' on a quality compares stages, got ${typeof n}`);let r=e.indexOf(n);if(r<0)throw new d(`"${n}" is not a stage of this quality (stages: ${e.join(", ")})`);return r}var _e=(n,e)=>n.length===e.length&&n.every((t,r)=>t===e[r]);function R(n){if(Number.isNaN(n)||!Number.isFinite(n))return 0;let e=Math.trunc(n)%4294967296;return e<0?e+4294967296:e}function J(n){let e=R(n);return{next(){e=e+1831565813>>>0;let t=Math.imul(e^e>>>15,1|e);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296},state(){return e}}}var Ue={name:"check_flags",count:n=>Math.max(1,n.args.length-1)},We=[Ue];function pe(n,e,t){let r=t?.countingCalls??We;return V(n,t?.want??!0,e,r)}function V(n,e,t,r){if(n.kind==="binary"&&(n.op==="and"||n.op==="or")){let s=V(n.left,e,t,r),i=V(n.right,e,t,r);return n.op==="and"===e?s>0&&i>0?s+i:0:Math.max(s,i)}if(n.kind==="unary"&&n.op==="not")return V(n.operand,!e,t,r);if(n.kind==="call"){let s=r.find(i=>i.name===n.name);if(s){let i=s.count(n),o=t(n);return e?o?i:0:o?0:1}}return t(n)===e?1:0}var b=class n{values=Object.create(null);decls=new Map;subscribers=new Set;auditors=new Set;norm;pathPrefix;constructor(e=[],t){this.norm=t?.normalise??(r=>r.toLowerCase()),this.pathPrefix=t?.pathPrefix??"",this.seed(e)}seed(e){for(let t of e){let r=this.norm(t.name);this.decls.set(r,t),this.values[r]=structuredClone(t.default??P(t))}}get(e){return this.values[this.norm(e)]}normalise(e){return this.norm(e)}writable(e){return this.decls.get(this.norm(e))?.writable!==!1}set(e,t,r){let s=this.norm(e);if(!r?.host&&!this.writable(s))throw new Error(`\'${e}\' is read-only`);let i={name:s,prev:this.values[s],next:t,silent:r?.silent??!1,reason:r?.reason};this.values[s]=t;for(let o of[...this.auditors])o(i);if(!i.silent)for(let o of[...this.subscribers])o(i);return i}subscribe(e){return this.subscribers.add(e),()=>this.subscribers.delete(e)}onAudit(e){return this.auditors.add(e),()=>this.auditors.delete(e)}rows(){return[...this.decls.entries()].map(([e,t])=>ge(t,this.get(e),void 0,e,this.pathPrefix))}declarations(){return[...this.decls.values()]}clone(){let e=new n([],{normalise:this.norm,pathPrefix:this.pathPrefix});return e.decls=new Map(this.decls),Object.assign(e.values,structuredClone(this.values)),e}reseed(e){for(let t of Object.keys(this.values))delete this.values[t];this.decls.clear(),this.seed(e)}save(){return structuredClone(this.values)}load(e){for(let[t,r]of Object.entries(e))this.values[this.norm(t)]=r}};function ge(n,e,t,r,s=""){let i=r??n.name.toLowerCase();return{name:i,path:s+i,type:n.type,value:e,default:n.default??P(n),...n.values!==void 0?{values:n.values}:{},...n.stages!==void 0?{stages:n.stages}:{},writable:t??n.writable??!0}}var Je=n=>n.toLowerCase(),K=1,L=class{scopes=new Map;parked=new Map;rev=0;get revision(){return this.rev}defineOwned(e,t,r){let s=typeof r=="string"?{pathPrefix:r}:r??{},i=new b(t,{pathPrefix:s.pathPrefix??`${e}.`,...s.normalise?{normalise:s.normalise}:{}});return this.mountOwned(e,i,s.owner!==void 0?{owner:s.owner}:void 0)}mountOwned(e,t,r){this.assertFree(e,r?.owner),this.scopes.set(e,{kind:"owned",bag:t,...r?.owner!==void 0?{owner:r.owner}:{}}),this.rev++;let s=this.parked.get(e);return s&&(t.load(s),this.parked.delete(e)),this}remove(e,t){let r=this.scopes.get(e);if(!r)throw new Error(`unknown scope \'@${e}\'`);return t?.keep&&r.kind==="owned"&&this.parked.set(e,r.bag.save()),this.scopes.delete(e),this.rev++,this}discardParked(e){if(e===void 0)this.parked.clear();else for(let t of[...this.parked.keys()])t.startsWith(e)&&this.parked.delete(t);return this}ownedBag(e){let t=this.scopes.get(e);if(!t||t.kind!=="owned")throw new Error(`\'@${e}\' is not an owned scope`);return t.bag}reseedOwned(e,t){return this.ownedBag(e).reseed(t),this}defineForeign(e,t,r=[],s=!0){let i=typeof s=="boolean"?{writable:s}:s;this.assertFree(e,i.owner);let o=i.normalise??Je,a=new Map;for(let c of r)a.set(o(c.name),c);return this.scopes.set(e,{kind:"foreign",resolver:t,decls:a,scopeWritable:i.writable??!0,norm:o,...i.owner!==void 0?{owner:i.owner}:{}}),this.rev++,this}has(e){return this.scopes.has(e)}get(e,t){let r=this.scopes.get(e);if(r)return r.kind==="owned"?r.bag.get(t):r.resolver.get(r.norm(t))}set(e,t,r,s){let i=this.scopes.get(e);if(!i)throw new Error(`unknown scope \'@${e}\'`);if(i.kind==="owned"){if(!s?.host&&!i.bag.writable(t))throw new Error(`\'@${e}.${t}\' is read-only`);i.bag.set(t,r,s?.host?{host:!0}:void 0);return}let o=i.norm(t);if(!i.resolver.set)throw new Error(`\'@${e}.${t}\' is read-only`);if(!s?.host&&!this.foreignWritable(i,o))throw new Error(`\'@${e}.${t}\' is read-only`);i.resolver.set(o,r)}foreignWritable(e,t){return e.resolver.set?e.decls.get(t)?.writable??e.scopeWritable:!1}listProperties(){let e=[];for(let[t,r]of this.scopes){let s=r.owner!==void 0?{owner:r.owner}:{};if(r.kind==="owned")for(let i of r.bag.rows())e.push({scope:t,...s,...i});else for(let[i,o]of r.decls)e.push({scope:t,...s,...ge(o,r.resolver.get(i),this.foreignWritable(r,i),i,`${t}.`)})}return e}toEvalContext(e,t){let r=this.view(t?.aliases),s={};for(let[o,a]of r)s[o]=a.kind==="owned"?a.bag.values:a.resolver;let i=this.qualityLadders(r);return i.size===0?{scopes:s,host:e}:{scopes:s,host:e,qualities:(o,a)=>{let c=r.get(o);return c?i.get(o)?.get(Ke(c)(a)):void 0}}}view(e){let t=new Map(this.scopes);for(let[r,s]of Object.entries(e??{})){let i=this.scopes.get(s);if(!i)throw new Error(`alias \'@${r}\' names \'${s}\', which is not registered`);t.set(r,i)}return t}qualityLadders(e){let t=new Map;for(let[r,s]of e)for(let[i,o]of de(s)){if(o.type!=="quality"||o.stages===void 0)continue;let a=t.get(r);a||(a=new Map,t.set(r,a)),a.set(i,o.stages)}return t}toSchema(e){let t=new Map;for(let[r,s]of this.view(e?.aliases)){let i=de(s);if(i.length===0)continue;let o=new Map;for(let[a,c]of i)o.set(a,{type:c.type,enumValues:c.values,...c.stages!==void 0?{stages:c.stages}:{}});t.set(r,o)}return{properties:t}}save(){let e={};for(let[t,r]of this.scopes)r.kind==="owned"&&(e[t]=r.bag.save());for(let[t,r]of this.parked)e[t]=structuredClone(r);return e}load(e,t){t?.keepParked||this.parked.clear();for(let[r,s]of Object.entries(e)){let i=this.scopes.get(r);i?.kind==="owned"?i.bag.load(s):i||this.parked.set(r,structuredClone(s))}}saveFragment(){return{version:K,scopes:this.save()}}loadFragment(e){if(e.version!==K)throw new Error(`unsupported owned-state fragment version ${e.version} (supported: ${K})`);this.load(e.scopes)}assertFree(e,t){let r=this.scopes.get(e);if(!r)return;let s=r.owner!==void 0?` by ${r.owner}`:"",i=t!==void 0?` (wanted by ${t})`:"";throw new Error(`scope \'@${e}\' is already registered${s}${i}`)}};function de(n){return n.kind==="foreign"?[...n.decls.entries()]:n.bag.declarations().map(e=>[n.bag.normalise(e.name),e])}function Ke(n){return n.kind==="foreign"?n.norm:e=>n.bag.normalise(e)}function P(n){if(n.default!==void 0)return n.default;switch(n.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"enum":return n.values?.[0]??"";case"flags":return[];case"quality":return n.stages?.[0]??"";default:return!1}}var ue=[{token:"patter",engine:"Patterplay",means:"Patter\'s shared globals"},{token:"story",engine:"Storylet Engine",means:"the Storylet Engine\'s shared @story properties"}];function O(n){return n.ctx.host??{}}var z={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(n,e){if(n.length!==2)throw new d("random(a, b) requires exactly 2 arguments");let t=O(e).nextRandom;if(!t)throw new d("random() called without a PRNG in context");let r=e.evaluate(n[0]),s=e.evaluate(n[1]);if(typeof r!="number"||typeof s!="number")throw new d("random(a, b) arguments must be numbers");if(!Number.isInteger(r)||!Number.isInteger(s))throw new d("random(a, b) arguments must be integers");let i=Math.min(r,s),o=Math.max(r,s);return Math.floor(t()*(o-i+1))+i}},check_flags:{minArgs:1,returnType:"boolean",flagDeltaArgs:!0,validate:fe("check_flags"),eval(n,e){let t=he(n[0],e,"check_flags");for(let r=1;r<n.length;r++){let s=n[r];if(s.kind!=="flagdelta")throw new d("check_flags() flag args must be +flagName or -flagName");if(s.sign==="+"?!t.includes(s.name):t.includes(s.name))return!1}return!0}},set_flags:{minArgs:1,returnType:"flags",flagDeltaArgs:!0,validate:fe("set_flags"),eval(n,e){let t=[...he(n[0],e,"set_flags")];for(let r=1;r<n.length;r++){let s=n[r];if(s.kind!=="flagdelta")throw new d("set_flags() flag args must be +flagName or -flagName");if(s.sign==="+")t.includes(s.name)||t.push(s.name);else{let i=t.indexOf(s.name);i>=0&&t.splice(i,1)}}return t}},visits:{minArgs:1,maxArgs:1,returnType:"number",validate:$("visits"),eval:(n,e)=>O(e).visits?.(M(n,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:$("seen"),eval:(n,e)=>(O(e).visits?.(M(n,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:$("patter_visits"),eval:(n,e)=>O(e).patterVisits?.(M(n,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:$("patter_seen"),eval:(n,e)=>(O(e).patterVisits?.(M(n,e,"patter_seen"))??0)>0}}},Ct=ue.map(n=>n.token).filter(n=>n!=="patter"&&n!=="scene");function me(n,e){let t=n.replace(/^@/,"").split(".");return t.length===2&&e(t[0])?{scope:t[0],name:t[1].toLowerCase()}:{scope:"patter",name:t.join(".").toLowerCase()}}function M(n,e,t){let r=e.evaluate(n[0]);if(typeof r!="string")throw new d(`${t}(id) requires a string node id`);return r}function $(n){return(e,t)=>{let r=e[0];r&&r.kind!=="string"&&t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(id): the argument must be a string id literal (a scene / block / node id)`})}}function he(n,e,t){if(!n)throw new d(`${t}() requires at least one argument (the flags variable)`);let r=e.evaluate(n);if(Array.isArray(r))return r;if(r===!1||r===null||r===void 0)return[];throw new d(`${t}() first argument must be a flags property`)}function fe(n){return(e,t)=>{if(e.length===0)return;let r=e[0];if(r.kind!=="scopedvar"){t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(): first argument must be a flags property reference (@name or @scope.name)`});return}let s=t.schema.properties.get(r.scope)?.get(r.name);if(s&&s.type!=="flags"){let i=r.scope===t.defaultScope?r.name:`${r.scope}.${r.name}`;t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(): \'@${i}\' is not a flags property (got ${s.type})`});return}for(let i=1;i<e.length;i++){let o=e[i];o.kind!=="flagdelta"?t.report({path:[...t.path,"args",i],kind:"wrong-arg-type",severity:"error",message:`${n}(): argument ${i+1} must be +flagName or -flagName`}):s?.type==="flags"&&s.enumValues&&!s.enumValues.includes(o.name)&&t.report({path:[...t.path,"args",i],kind:"unknown-flag-name",severity:"error",message:`${n}(): unknown flag \'${o.name}\'`,reference:o.name})}}}var ze=/^@[A-Za-z0-9_.]+$/;function*Ye(n){let e="",t=0;for(;t<n.length;){let r=n[t];if(r==="{"&&n[t+1]==="{"){e+="{",t+=2;continue}if(r==="}"&&n[t+1]==="}"){e+="}",t+=2;continue}if(r==="{"){let s=n.indexOf("}",t+1);if(s!==-1){let i=n.slice(t,s+1),o=n.slice(t+1,s).trim();if(o.startsWith("@")){e&&(yield{kind:"text",value:e},e=""),yield{kind:"slot",raw:i,inner:o,ref:ze.test(o)?o:void 0},t=s+1;continue}e+=i,t=s+1;continue}}e+=r,t+=1}e&&(yield{kind:"text",value:e})}function Qe(n){return Array.isArray(n)?n.join(", "):typeof n=="boolean"?n?"true":"false":String(n)}function Xe(n){return n===" "||n===" "||n===`\n`||n==="\\r"||n==="\\f"||n==="\\v"}function Ze(n){let e="",t=!1;for(let r of n){if(Xe(r)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=r}return e}function Se(n,e,t){if(e.length===0||n.indexOf(e)<0)return n;let r="",s=0,i=!1;for(;s<n.length;){if(n.startsWith(e,s)){let o=n.indexOf(t,s+e.length);if(o>=0){s=o+t.length,i=!0;continue}r+=n.slice(s);break}r+=n[s],s+=1}return i?Ze(r):n}function ye(n,e){if(n.indexOf("{")<0)return n;let t="";for(let r of Ye(n)){if(r.kind==="text"){t+=r.value;continue}if(!r.ref){t+=r.raw;continue}let s=e(r.ref);t+=s===void 0?"":Qe(s)}return t}function C(n,e){for(let t of n){e(t);let r=t.children;r&&C(r,e)}}function et(n){return n.toLowerCase().replace(/[\'\u2019]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function S(n){let e=n.gameId?.trim();return e||et(n.name)}function Y(n){return`cast:${n}`}var Q={open:"[",close:"]"},ve="SFX";var X=3;function B(n){let e=new Set,t=[];for(let r of n)e.has(r)||(e.add(r),t.push(r));return t}function H(n){let e=new Map,t=(r,s)=>{let i=B([...s,...r.tags??[]]);if(e.set(r.id,i),r.type==="group"&&r.prompt&&e.set(r.prompt.id,B([...i,...r.prompt.tags??[]])),r.type==="group")for(let o of r.children)t(o,i);else for(let o of r.beats??[])e.set(o.id,B([...i,...o.tags??[]]))};for(let r of Object.values(n.scenes)){let s=B(r.tags??[]);e.set(r.id,s);for(let i of r.blocks){let o=B([...s,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var we=new WeakMap,F="Patter",N=n=>n.replace(/%/g,"%25").replace(/\\//g,"%2F"),be=Symbol("ownsRegistry"),y={stage:n=>`patter/scene/${N(n)}`,flow:n=>`patter/flow/${N(n)}/`,flowGlobals:n=>`patter/flow/${N(n)}/patter`,flowScene:(n,e)=>`patter/flow/${N(n)}/scene/${N(e)}`},A=class{constructor(e){this.journal=e}journal},q=class n{host;defaultSeed;flowsById=new Map;allStrings;currentLocale;sourceDebug;sceneGameIdToId=new Map;blockGameIdToId=new Map;creationOptions;engineLog=[];engineSeq=0;engineTraceHandlers=new Set;constructor(e,t={}){this.creationOptions=t;let r=t.locale??e.locales.default,s=e.strings;this.allStrings=s,this.currentLocale=r;let i=s[r]??{},o=s[e.locales.default]??{},a=e.localisation,c=a?.mode==="ids"&&!a.sourceDebug;this.sourceDebug=a?.mode==="ids"&&!!a.sourceDebug,this.sourceDebug&&typeof console<"u"&&console.warn("[Patterplay] source-only DEBUG build: strings are the source language for debugging, not a shippable localised build.");let l=new Map;for(let g of e.cast??[])g.displayName&&l.set(g.name,g.displayName);this.defaultSeed=(t.seed??2654435769)>>>0;let p=new Map,f=new Map,u=new Map;for(let[g,h]of Object.entries(e.scenes)){this.sceneGameIdToId.set(S(h),g);let v=new Map;for(let m of h.blocks)f.set(m.id,{sceneId:g}),u.set(m.id,m),v.set(S(m),m.id),C(m.children,G=>p.set(G.id,G));this.blockGameIdToId.set(g,v)}let se=e.properties??[],_=se.filter(g=>g.shared??!0).map(Ce),Te=se.filter(g=>!(g.shared??!0)).map(Ce),Ge=new Set(_.map(g=>g.name.toLowerCase())),x=t.registry??new L,ie=!t.registry||t[be]===!0,oe=new b(_,{pathPrefix:"@patter."}),ae=[],T=[];try{x.mountOwned("patter",oe,{owner:F}),T.push("patter");let g=new Set;for(let[h,v]of Object.entries(Ie(t))){let m=e.scopeRegistry?.scopes.find(je=>je.token===h),G=(m?.declarations??[]).map(Oe);x.defineForeign(h,v,G,{writable:m?.writable??!0,owner:F}),T.push(h),g.add(h)}for(let h of ie?e.scopeRegistry?.scopes??[]:[]){if(g.has(h.token)||x.has(h.token))continue;let v=(h.declarations??[]).map(m=>rt(m,h.writable));x.defineOwned(h.token,v,{owner:F}),T.push(h.token),ae.push(h.token)}}catch(g){for(let h of T)x.remove(h,{keep:!0});throw g}let ce=new Map;for(let[g,h]of Object.entries(e.scenes)){let v=new Set((h.sceneProps??[]).filter(m=>m.shared??!1).map(m=>m.name.toLowerCase()));ce.set(g,v)}this.host={logEnabled:t.log??!1,tracing:t.log??!1,emitEngine:(g,h,v)=>this.emitEngine(g,h,v),bundle:e,emitIds:c,strings:i,defaultStrings:o,castDisplay:l,nodeIndex:p,blockIndex:f,blockById:u,sceneGameIdToId:this.sceneGameIdToId,blockGameIdToId:this.blockGameIdToId,tagIndex:H(e),registry:x,ownsRegistry:ie,patterBag:oe,hostScopes:ae,patterSharedDecls:_,patterLocalDecls:Te,patterSharedNames:Ge,sceneSharedNames:ce,sharedVisits:new Map,qualityLadders:new Map,sharedSelectors:new Map,stageBags:new Map,journal:null,customRng:t.rng,onDryChoice:t.onDryChoice,onError:t.onError??(g=>console.warn(`Patterplay: ${g.kind} on ${g.node} in flow \'${g.flow}\' failed, played through: ${g.message}`)),replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??Q).open,captionClose:(e.closedCaptions??Q).close,captionCharacter:e.closedCaptions?.character||ve,refSplitCache:new Map,refSplitRevision:x.revision}}get locale(){return this.currentLocale}get isSourceDebug(){return this.sourceDebug}get buildId(){return this.host.bundle.content?.hash??""}setLocale(e){this.currentLocale=e,this.host.strings=this.allStrings[e]??{}}replaceStrings(e){this.allStrings=e.strings,this.host.strings=this.allStrings[this.currentLocale]??{},this.host.defaultStrings=this.allStrings[this.host.bundle.locales.default]??{}}hotSwap(e){this.refuseInCheckpoint("hotSwap");let t=this.saveGame(),r=o=>(o.setLocale(this.currentLocale),o.setClosedCaptions(this.host.captionsOn),o),s=()=>new n(e,{...this.creationOptions,registry:this.host.registry,[be]:this.host.ownsRegistry});this.release(!0);let i=s();try{return i.loadGame(t),r(i)}catch{i.release(!0);let o=s();for(let[a,c]of Object.entries(t.flows)){let l=c.cursor.currentSceneId;try{o.openFlow(a,l!==null?{scene:l}:{})}catch{}}return r(o)}}get closedCaptions(){return this.host.captionsOn}setClosedCaptions(e){this.host.captionsOn=e}openFlow(e,t={}){this.assertExternalScopes();let{sceneId:r,blockId:s}=this.resolveOpenAddress(t.scene,t.block),i=this.flowsById.get(e),o=this.host.journal;if(o&&i&&!i.isClosed)throw new Error(`openFlow would replace the open flow \'${e}\', which can\'t be undone while a checkpoint is open`);i?.close();let a=new I(e,this.host,t.seed??this.defaultSeed);return o&&(o.flows.add(a),o.opened.add(a),o.undo.push(()=>{a.close(),i?this.flowsById.set(e,i):this.flowsById.delete(e)})),this.flowsById.set(e,a),a.begin(r,s),a}runFlow(e,t,r){let s=this.flowsById.get(e);if(!s)return this.openFlow(e,{scene:t,block:r}).advanceToStop().played;if(!s.goto(t,r))throw new Error(`runFlow: address not found: ${t}${r===void 0?"":` / ${r}`}`);return s.advanceToStop().played}assertExternalScopes(){for(let e of this.host.bundle.externalScopes??[])if(!this.host.registry.has(e))throw new Error(`this content names @${e}, which no engine on this registry registered: give every engine the game\'s one registry`)}resolveOpenAddress(e,t){if(e!==void 0){let r=ee(this.host,e);if(r===void 0)throw new Error(`unknown scene: ${e}`);if(t===void 0)return{sceneId:r};let s=te(this.host,r,t);if(s===void 0)throw new Error(`unknown block: ${t}`);return{sceneId:r,blockId:s}}if(t!==void 0){if(!this.host.blockIndex.has(t))throw new Error(`unknown block: ${t}`);return{blockId:t}}if(Object.keys(this.host.bundle.scenes).length===0)throw new Error("no scenes in bundle");return{}}resolveSceneRef(e){if(e!=null)return ee(this.host,e)??e}resolveBlockRef(e,t){if(t!=null)return e==null?t:te(this.host,e,t)}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?S(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?S(t):void 0}tagsForBeat(e){return this.host.tagIndex.get(e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?this.host.tagIndex.get(t):void 0)??[]}tagsForBlock(e,t){let r=this.resolveSceneRef(e),s=this.resolveBlockRef(r,t);return(s!=null?this.host.tagIndex.get(s):void 0)??[]}gameDataForScene(e){let t=this.resolveSceneRef(e);return{...(t!=null?this.host.bundle.scenes[t]:void 0)?.gameData}}gameDataForBlock(e,t){let r=this.resolveBlockRef(this.resolveSceneRef(e),t);return{...(r!=null?this.host.blockById.get(r):void 0)?.gameData}}getCast(){let e=[];for(let t of this.host.bundle.cast??[])t?.name&&e.push(t.name);return e}castForScene(e){let t=this.resolveSceneRef(e),r=t!=null?this.host.bundle.scenes[t]:void 0;if(!r)return[];let s=new Set;for(let i of r.blocks)xe(i.children,s);return[...s]}castForBlock(e,t){let r=this.resolveSceneRef(e),s=this.resolveBlockRef(r,t),i=s!=null?this.host.blockById.get(s):void 0;if(!i)return[];let o=new Set;return xe(i.children,o),[...o]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...S(e)?{gameId:S(e)}:{},name:e.name,...ke(e.gameData),...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...S(t)?{gameId:S(t)}:{},name:t.name,...ke(t.gameData),...this.tagsField(t.id),children:t.children.map(r=>this.outlineNode(r))}))}))}getBeatSequence(){let e=[];for(let t of Object.values(this.host.bundle.scenes))for(let r of t.blocks)C(r.children,s=>{if(s.type==="snippet")for(let i of s.beats??[])e.push({sceneId:t.id,blockId:r.id,snippetId:s.id,beat:this.beatInfo(i)})});return e}outlineNode(e){return e.type==="group"?{type:"group",id:e.id,...this.tagsField(e.id),...e.selector?{selector:e.selector}:{},...e.prompt?{prompt:this.beatInfo(e.prompt)}:{},children:e.children.map(t=>this.outlineNode(t))}:{type:"snippet",id:e.id,...this.tagsField(e.id),beats:(e.beats??[]).map(t=>this.beatInfo(t)),...e.jump?{jumpTo:e.jump.to,...e.jump.mode?{jumpMode:e.jump.mode}:{}}:{}}}beatInfo(e){let t=this.host.tagIndex.get(e.id),r={id:e.id,kind:e.kind};if(e.kind==="line"){if(e.character!==void 0){r.character=e.character;let s=this.host.defaultStrings[Y(e.character)]??this.host.castDisplay.get(e.character);s!==void 0&&(r.characterName=s)}e.direction!==void 0&&(r.direction=e.direction)}if(e.kind==="line"||e.kind==="text"){let s=this.host.defaultStrings[e.id];s!==void 0&&(r.text=s)}return e.gameData&&Object.keys(e.gameData).length&&(r.gameData=e.gameData),t&&t.length&&(r.tags=t),r}tagsField(e){let t=this.host.tagIndex.get(e);return t&&t.length?{tags:t}:{}}getFlow(e){return this.flowsById.get(e)}flows(){return[...this.flowsById.values()]}listBags(){let e=[{bag:this.host.patterBag}];for(let[t,r]of this.host.stageBags)e.push({bag:r,pathPrefix:`@scene:${t}.`});return e}checkpoint(){if(this.host.journal)throw new Error("a checkpoint is already open: roll it back or commit it first");let e={undo:[],flows:new Set,opened:new Set,selectors:new Set,flowSelectors:new Map};return this.host.journal=e,new A(e)}rollback(e){this.endCheckpoint(e);let t=e.journal.undo;for(let r=t.length-1;r>=0;r--)t[r]();n.forget(e.journal)}commit(e){this.endCheckpoint(e),n.forget(e.journal)}get inCheckpoint(){return this.host.journal!==null}endCheckpoint(e){if(this.host.journal!==e.journal)throw new Error("that checkpoint is not the open one");this.host.journal=null}static forget(e){e.undo=[],e.flows.clear(),e.opened.clear(),e.selectors.clear(),e.flowSelectors.clear()}refuseInCheckpoint(e){if(this.host.journal)throw new Error(`${e} can\'t be undone, so it isn\'t allowed while a checkpoint is open`)}closeFlow(e){this.refuseInCheckpoint("closeFlow"),this.flowsById.get(e)?.close(),this.flowsById.delete(e)}reset(){this.refuseInCheckpoint("reset");for(let e of this.flowsById.values())e.close();this.flowsById.clear(),this.host.patterBag.reseed(this.host.patterSharedDecls),this.host.sharedVisits.clear(),this.host.sharedSelectors.clear();for(let e of this.host.stageBags.keys())this.host.registry.remove(y.stage(e));this.host.stageBags.clear(),this.host.registry.discardParked("patter/")}release(e){for(let r of this.flowsById.values())r.releaseBags(e),r.close();this.flowsById.clear();let t=this.host.registry;for(let r of this.host.stageBags.keys())t.remove(y.stage(r),{keep:e});this.host.stageBags.clear();for(let r of["patter",...this.host.hostScopes])t.has(r)&&t.remove(r,{keep:e});for(let r of Object.keys(Ie(this.creationOptions)))t.has(r)&&t.remove(r)}getProperty(e){let{scope:t,name:r}=this.splitShared(e);return this.host.registry.get(t,r)}setProperty(e,t){let{scope:r,name:s}=this.splitShared(e),i=this.host.journal?this.host.registry.get(r,s):void 0;this.host.registry.set(r,s,t,{host:!0}),this.host.journal&&i!==void 0&&this.host.journal.undo.push(()=>this.host.registry.set(r,s,i,{host:!0}))}log(){return this.engineLog}clearLog(){this.engineLog.length=0}onTrace(e){return this.engineTraceHandlers.add(e),this.host.tracing=!0,()=>{this.engineTraceHandlers.delete(e),this.host.tracing=this.host.logEnabled||this.engineTraceHandlers.size>0}}emitEngine(e,t,r){for(let s of this.engineTraceHandlers)s(e,t);this.host.logEnabled&&this.engineLog.push({...t,flow:e,seq:this.engineSeq++,...r?{scene:r}:{}})}getVisitCounts(){return Object.fromEntries(this.host.sharedVisits)}listProperties(){return this.host.patterSharedDecls.map(e=>({name:e.name,path:`@patter.${e.name}`,type:e.type,values:e.values,stages:e.stages,value:this.getProperty(`@${e.name}`),default:P(e),writable:e.writable??!0}))}splitShared(e){let t=Be(this.host,e);if(t.scope==="scene")throw new Error(`\'${e}\': @scene properties are scene-scoped - read/write them on a Flow, not the Engine`);return t}save(){return{patter:this.host.patterBag.save()}}load(e){e.patter&&this.host.patterBag.load(e.patter)}saveGame(){let e={};for(let[t,r]of this.flowsById)e[t]=r.snapshot();return{version:X,...this.host.ownsRegistry?{registry:this.host.registry.save()}:{},sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:Re(this.host.sharedSelectors),flows:e}}loadGame(e){this.refuseInCheckpoint("loadGame");let t=e.version;if(t!==2&&t!==X)throw new Error(`unsupported save version: ${String(t)}`);let r=e.flows;if(typeof r!="object"||r===null||Array.isArray(r))throw new Error("malformed save: no flows");this.assertExternalScopes();let s=this.host.registry;for(let[o,a]of this.flowsById)a.releaseBags(o in e.flows),a.close();this.flowsById.clear();for(let o of this.host.stageBags.keys())s.remove(y.stage(o),{keep:!0});this.host.stageBags.clear();let i=e.version===2?nt(e):e.registry;i&&(this.host.ownsRegistry?s.load(i):s.load(i,{keepParked:!0})),this.host.sharedVisits.clear();for(let[o,a]of Object.entries(e.sharedVisits??{}))this.host.sharedVisits.set(o,a);this.host.sharedSelectors.clear();for(let[o,a]of Pe(e.sharedSelectors))this.host.sharedSelectors.set(o,a);for(let[o,a]of Object.entries(e.flows)){let c=new I(o,this.host,this.defaultSeed);c.restore(a),this.flowsById.set(o,c)}}},I=class{id;host;local;registered=new Set;rngState;started=!1;flowEnded=!1;closed=!1;currentSceneId=null;stack=[];activeSnippet=null;beatIndex=0;pendingChoice=null;pendingPrompt=null;pendingPromptOwnerId=null;selectors=new Map;visitCounts=new Map;sceneBags=new Map;patterResolver={get:e=>this.host.patterSharedNames.has(e)?this.host.patterBag.get(e):this.local.get(e),set:(e,t)=>{this.host.patterSharedNames.has(e)?this.host.registry.set("patter",e,t):this.local.set(e,t)}};sceneResolver={get:e=>{let t=this.currentSceneId;if(t!==null)return this.sceneBagFor(t,e)?.get(e)},set:(e,t)=>{let r=this.currentSceneId;if(r===null)return;let s=this.sceneBagFor(r,e);s&&s.set(e,t)}};evalCtx;ctxRevision=-1;registryQualities;flowLog=[];flowSeq=0;constructor(e,t,r){this.id=e,this.host=t,this.rngState=R(r),this.local=this.newLocal(),this.evalCtx={scopes:{},host:{nextRandom:this.rng,visits:s=>this.visitCounts.get(s)??0,patterVisits:s=>this.host.sharedVisits.get(s)??0},qualities:(s,i)=>this.stagesFor(s,i)}}context(){let e=this.host.registry;if(e.revision!==this.ctxRevision){let t=e.toEvalContext(),r=this.evalCtx.scopes;for(let s of Object.keys(r))delete r[s];Object.assign(r,t.scopes),r.patter=this.patterResolver,r.scene=this.sceneResolver,this.registryQualities=t.qualities,this.ctxRevision=e.revision}return this.evalCtx}stagesFor(e,t){let r=t.toLowerCase();if(e==="patter")return Z(this.host,"patter",()=>[...this.host.patterSharedDecls,...this.host.patterLocalDecls]).get(r);if(e==="scene"){let s=this.currentSceneId;return s==null?void 0:Z(this.host,`scene/${s}`,()=>this.host.bundle.scenes[s]?.sceneProps).get(r)}return this.registryQualities?.(e,t)??Z(this.host,`host/${e}`,()=>this.host.bundle.scopeRegistry?.scopes.find(s=>s.token===e)?.declarations).get(r)}begin(e,t){if(this.host.journal&&!this.host.journal.opened.has(this))throw new Error("a flow can\'t be started or reset while a checkpoint is open");if(this.releaseBags(!1),this.host.registry.discardParked(y.flow(this.id)),this.mountLocal(),this.selectors.clear(),this.visitCounts.clear(),this.stack=[],this.currentSceneId=null,this.flowEnded=!1,this.activeSnippet=null,this.beatIndex=0,this.clearPending(),this.started=!0,t){let r=this.host.blockIndex.get(t);if(!r)throw new Error(`unknown block: ${t}`);this.enterSceneSetup(r.sceneId),this.stack=[{sceneId:r.sceneId,containerId:t,index:0}],this.enter(t)}else{let r=e??Object.keys(this.host.bundle.scenes)[0],s=r?this.host.bundle.scenes[r]:void 0;if(!s)throw new Error(r?`unknown scene: ${r}`:"no scenes in bundle");this.enterSceneSetup(r);let i=s.blocks[0];i&&(this.stack=[{sceneId:r,containerId:i.id,index:0}],this.enter(i.id))}this.settle()}reset(e,t){this.begin(e,t)}start(e,t){this.reset(e,t)}goto(e,t){if(this.closed)return!1;if(this.touch(),e==="END")return this.started=!0,this.clearPending(),this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!0,this.stack=[],!0;let r=ee(this.host,e);if(r===void 0)return!1;let s;return t!==void 0&&(s=te(this.host,r,t),s===void 0)?!1:this.started?(this.clearPending(),this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!1,this.enterTarget(s??r,"jump"),this.settle(),!0):(this.begin(r,s),!0)}close(){this.releaseBags(!1),this.closed=!0,this.flowEnded=!0,this.stack=[],this.activeSnippet=null,this.beatIndex=0,this.clearPending()}clearPending(){this.pendingChoice=null,this.pendingPrompt=null,this.pendingPromptOwnerId=null}touch(){let e=this.host.journal;if(!e||e.flows.has(this))return;e.flows.add(this);let{rngState:t,started:r,flowEnded:s,currentSceneId:i,activeSnippet:o,beatIndex:a,pendingChoice:c,pendingPrompt:l,pendingPromptOwnerId:p}=this,f=this.stack.map(u=>({...u}));e.undo.push(()=>{Object.assign(this,{rngState:t,started:r,flowEnded:s,currentSceneId:i,activeSnippet:o,beatIndex:a,pendingChoice:c,pendingPrompt:l,pendingPromptOwnerId:p,stack:f})})}get isClosed(){return this.closed}get currentScene(){return this.currentSceneId}advance(){if(this.closed)return{type:"end"};if(!this.started)throw new Error("flow has not been started");if(this.touch(),this.pendingPrompt){let e=this.pendingPrompt;return this.pendingPrompt=null,this.pendingPromptOwnerId=null,e.shown?this.promptResult(e.beat,e.shown):this.beatResult(e.beat)}return this.settle(),this.flowEnded?{type:"end"}:this.pendingChoice?{type:"choice",groupId:this.pendingChoice.groupId,options:this.pendingChoice.options}:this.activeSnippet?this.beatResult(this.activeSnippet.beats[this.beatIndex++]):(this.flowEnded=!0,{type:"end"})}advanceToStop(){let e=[];for(;;){let t=this.advance();if(t.type==="choice"||t.type==="end")return{played:e,stop:t};e.push(t)}}settle(){let e=0;for(;;){if(++e>1e4)throw new Error("flow did not settle after 10000 transitions - likely a jump cycle with no deliverable content");if(this.flowEnded||this.pendingChoice)return;if(this.activeSnippet){if(this.beatIndex<(this.activeSnippet.beats?.length??0))return;this.runEffects(this.activeSnippet.onExit,this.activeSnippet.id);let i=this.activeSnippet.jump;this.activeSnippet=null,this.beatIndex=0,this.resolveJump(i);continue}let t=this.stack[this.stack.length-1];if(!t){this.flowEnded=!0;return}t.sceneId!==this.currentSceneId&&(this.currentSceneId=t.sceneId);let r=this.childrenOf(t.containerId);if(!r){this.stack.pop();continue}let s=t.index;for(;t.index<r.length&&!this.eligible(r[t.index]);)t.index++;if(this.host.tracing&&t.index!==s&&this.emit({type:"select",group:t.containerId,selector:"run",children:r.slice(s,t.index+1).map((i,o)=>({id:i.id,eligible:s+o===t.index})),picked:r[t.index]?.id??null}),t.index>=r.length){this.stack.pop();continue}this.enterChild(r[t.index++])}}listBags(){let e=[{bag:this.local,pathPrefix:`${this.id}/@patter.`}];for(let[t,r]of this.sceneBags)e.push({bag:r,pathPrefix:`${this.id}/@scene:${t}.`});return e}log(){return this.flowLog}clearLog(){this.flowLog.length=0}emit(e){let t=this.currentSceneId??void 0;this.host.emitEngine(this.id,e,t),this.host.logEnabled&&this.flowLog.push({...e,seq:this.flowSeq++,...t?{scene:t}:{}})}getVisitCounts(){return Object.fromEntries(this.visitCounts)}getChoices(){return this.pendingChoice?.options??[]}choose(e){let t=this.pendingChoice;if(!t)throw new Error("no choice is pending");let r=t.options.find(o=>o.id===e);if(!r)throw new Error(`unknown choice option: ${e}`);if(!r.eligible)throw new Error(`choice option is not eligible: ${e}`);this.touch();let s=t.byId.get(e);this.host.tracing&&this.emit({type:"chose",group:t.groupId,option:e}),this.pendingChoice=null;let i=this.host.replayPromptOnChoose?this.authoredPromptOf(s):void 0;this.pendingPrompt=i&&r.prompt?{beat:i,shown:{...r.prompt}}:null,this.pendingPromptOwnerId=this.pendingPrompt?s.id:null,this.enterChild(s)}isEnded(){return this.flowEnded}getProperty(e){let{scope:t,name:r}=this.splitRef(e);return t==="patter"?this.patterResolver.get(r):t==="scene"?this.sceneResolver.get(r):this.host.registry.get(t,r)}setProperty(e,t){this.writeProperty(e,t,!0)}writeProperty(e,t,r){let{scope:s,name:i}=this.splitRef(e),o=this.host.journal;if(s==="patter"){if(o){let a=this.host.patterSharedNames.has(i),c=a?this.host.patterBag.get(i):this.local.get(i),l=this.local;c!==void 0&&o.undo.push(a?()=>this.host.registry.set("patter",i,c):()=>l.set(i,c))}this.patterResolver.set(i,t)}else if(s==="scene"){if(this.currentSceneId===null)throw new Error(`\'${e}\': the flow has not entered a scene yet`);if(o){let a=this.sceneBagFor(this.currentSceneId,i),c=a?.get(i);a&&c!==void 0&&o.undo.push(()=>a.set(i,c))}this.sceneResolver.set(i,t)}else{let a=o?this.host.registry.get(s,i):void 0;this.host.registry.set(s,i,t,r?{host:!0}:void 0),o&&a!==void 0&&o.undo.push(()=>this.host.registry.set(s,i,a,{host:!0}))}}snapshot(){return{rngState:this.rngState,visits:Object.fromEntries(this.visitCounts),cursor:{flowEnded:this.flowEnded,currentSceneId:this.currentSceneId,stack:this.stack.map(e=>{let t=this.childrenOf(e.containerId)?.[e.index];return t?{...e,nextId:t.id}:{...e}}),activeSnippetId:this.activeSnippet?.id??null,beatIndex:this.beatIndex,pendingChoice:this.pendingChoice?{groupId:this.pendingChoice.groupId,options:this.pendingChoice.options.map(e=>({...e}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,...this.pendingPrompt?.shown?{pendingPrompt:tt(this.pendingPrompt.shown)}:{},selectors:Re(this.selectors)}}}restore(e){if(this.host.journal)throw new Error("a flow can\'t be restored while a checkpoint is open");this.restoreCursor(e),this.releaseBags(!0),this.mountLocal();for(let t of new Set([this.currentSceneId,...this.stack.map(r=>r.sceneId)]))t!==null&&this.host.bundle.scenes[t]&&this.ensureSceneBags(t)}restoreCursor(e){this.rngState=R(e.rngState),this.visitCounts=new Map(Object.entries(e.visits??{}));let t=e.cursor;if(this.started=!0,this.flowEnded=t.flowEnded,this.beatIndex=t.beatIndex,this.currentSceneId=t.currentSceneId,this.stack=t.stack.map(r=>{let{nextId:s,...i}=r;if(s!==void 0){let o=this.childrenOf(i.containerId)?.findIndex(a=>a.id===s)??-1;if(o>=0)return{...i,index:o}}return{...i}}),this.activeSnippet=null,t.activeSnippetId!==null){let r=this.host.nodeIndex.get(t.activeSnippetId);r&&r.type==="snippet"&&(this.activeSnippet=r)}if(this.selectors=Pe(t.selectors),this.pendingChoice=null,t.pendingChoice!==null){let r=new Map,s=[];for(let i of t.pendingChoice.options){let o=this.host.nodeIndex.get(i.id);o&&(r.set(i.id,o),s.push({...i}))}s.length>0&&(this.pendingChoice={groupId:t.pendingChoice.groupId,options:s,byId:r})}if(this.pendingPrompt=null,this.pendingPromptOwnerId=t.pendingPromptOwnerId??null,this.pendingPromptOwnerId){let r=this.host.nodeIndex.get(this.pendingPromptOwnerId),s=r?this.authoredPromptOf(r):void 0;s?this.pendingPrompt={beat:s,...t.pendingPrompt?{shown:{...t.pendingPrompt}}:{}}:this.pendingPromptOwnerId=null}}enterSceneSetup(e){let t=this.host.bundle.scenes[e];if(!t)throw new Error(`unknown scene: ${e}`);this.currentSceneId=e,this.enter(e),this.seedScene(t),this.runEffects(t.onEntry,t.id)}enterChild(e){if(this.enter(e.id),e.type==="snippet"){this.beginSnippet(e);return}let t=e.selector??"run";if(t==="run"){this.stack.push({sceneId:this.currentSceneId,containerId:e.id,index:0});return}if(t==="choice"){this.setupChoice(e);return}let r=this.selectChild(e);r&&this.enterChild(r)}childrenOf(e){let t=this.host.blockById.get(e);if(t)return t.children;let r=this.host.nodeIndex.get(e);if(r&&r.type==="group")return r.children}beginSnippet(e){this.runEffects(e.onEnter,e.id),this.activeSnippet=e,this.beatIndex=0}setupChoice(e){let t=[],r=new Map,s=[];for(let o of e.children){if(o.fallback===!0){s.push(o);continue}if(o.sticky!==!0&&(this.visitCounts.get(o.id)??0)>=1)continue;let a=this.eligible(o),c=o.secretUntilEligible===!0;!a&&c||(t.push({id:o.id,prompt:this.promptFor(o),eligible:a,gameData:o.gameData}),r.set(o.id,o))}if(t.some(o=>o.eligible)){this.host.tracing&&this.emit({type:"choice",group:e.id,options:t.map(o=>({id:o.id,eligible:o.eligible}))}),this.pendingChoice={groupId:e.id,options:t,byId:r};return}let i=s.find(o=>this.eligible(o));if(i){this.enterChild(i);return}this.host.tracing&&this.emit({type:"dry",group:e.id}),this.host.onDryChoice?.(e.id)}resolveJump(e){e&&this.enterTarget(e.to,e.mode==="call"?"call":"jump")}enterTarget(e,t){if(this.host.tracing&&this.emit({type:"jump",to:e,mode:t}),e==="END"){this.flowEnded=!0,this.stack=[];return}let r,s,i=this.host.bundle.scenes[e];if(i){this.enterSceneSetup(e);let a=i.blocks[0];if(!a){t==="jump"&&(this.stack=[]);return}r=e,s=a.id}else{let a=this.host.blockIndex.get(e);if(!a)throw new Error(`jump target not found: ${e}`);a.sceneId!==this.currentSceneId&&this.enterSceneSetup(a.sceneId),r=a.sceneId,s=e}this.enter(s);let o={sceneId:r,containerId:s,index:0};t==="call"?this.stack.push(o):this.stack=[o]}selectChild(e){let t=e.children.map(c=>({id:c.id,eligible:this.eligible(c)})),r=e.children.filter((c,l)=>t[l].eligible),s=e.options?.order??"sequential",i=e.options?.exhaust??"once",o=c=>(this.host.tracing&&this.emit({type:"select",group:e.id,selector:e.selector??"default",...e.selector==="sequence"?{order:s,exhaust:i}:{},children:t,picked:c?.id??null}),c);if(r.length===0)return o(null);let a=this.selectorState(e);switch(e.selector){case"branch":return o(r[0]);case"sequence":return o(s==="shuffle"?this.pickShuffle(r,i,a):s==="specificity"?this.pickSpecificity(r,i,a):this.pickSequential(r,i,a));default:return null}}pickSequential(e,t,r){let s=e.length,i=r.seq??0;return r.seq=i+1,t==="repeat"?e[i%s]:i<s?e[i]:t==="stick"?e[s-1]:null}pickShuffle(e,t,r){let s=e.length,i=t==="stick",o=()=>(i?e.slice(0,s-1):e).map(u=>u.id),a=new Set(e.map(u=>u.id));if(r.bag===void 0&&(r.bag=o()),!r.bag.some(u=>a.has(u))){if(t==="once")return null;if(i){let u=e[s-1];return r.last=u.id,u}if(r.bag=o(),r.bag.length===0)return null}let c=r.bag.filter(u=>a.has(u)),l=r.last!==void 0&&c.length>1?c.indexOf(r.last):-1,p=Math.floor(this.rng()*(l>=0?c.length-1:c.length));l>=0&&p>=l&&p++;let f=c[p];return r.bag.splice(r.bag.indexOf(f),1),r.last=f,e.find(u=>u.id===f)}pickSpecificity(e,t,r){let s=e;if(t!=="repeat"){r.bag===void 0&&(r.bag=e.map(p=>p.id));let l=new Set(r.bag);if(s=e.filter(p=>l.has(p.id)),s.length===0)return t==="stick"&&r.last!==void 0?e.find(p=>p.id===r.last)??null:null}let i=-1,a=s.map(l=>{let p=this.specScore(l);return p>i&&(i=p),{c:l,s:p}}).filter(l=>l.s===i).map(l=>l.c),c;if(a.length===1)c=a[0];else{let l=r.last!==void 0?a.findIndex(f=>f.id===r.last):-1,p=Math.floor(this.rng()*(l>=0?a.length-1:a.length));l>=0&&p>=l&&p++,c=a[p]}return t!=="repeat"&&(r.bag=r.bag.filter(l=>l!==c.id)),r.last=c.id,c}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0,e):0}matchedSpec(e,t,r){return pe(e,i=>{try{return De(j(i,this.context(),z))}catch(o){return this.reportError("best-match",r.id,r.condition,o),!1}},{want:t})}selectorState(e){let t=e.shared?this.host.sharedSelectors:this.selectors,r=this.host.journal,s;if(r&&(s=e.shared?r.selectors:r.flowSelectors.get(this),s||(s=new Set,r.flowSelectors.set(this,s))),r&&s&&!s.has(e.id)){s.add(e.id);let o=t.get(e.id),a=o?{...o,...o.bag?{bag:[...o.bag]}:{}}:void 0;r.undo.push(()=>{a?t.set(e.id,a):t.delete(e.id)})}let i=t.get(e.id);return i||(i={},t.set(e.id,i)),i}runEffects(e,t){for(let r of e??[]){let s;try{s=this.evalExpr(r.value);let i=this.host.tracing?this.getProperty(r.target):void 0;this.writeProperty(r.target,s,!1),this.host.tracing&&this.emit({type:"write",target:r.target,value:s,...i!==void 0?{prev:i}:{}})}catch(i){this.reportError("effect",t,r.value,i)}}}eligible(e){if(!e.condition)return!0;try{return De(this.evalExpr(e.condition))}catch(t){return this.reportError("condition",e.id,e.condition,t),!1}}reportError(e,t,r,s){let i=s instanceof Error?s.message:String(s),o=r?.src;this.host.onError({flow:this.id,kind:e,node:t,...o?{source:o}:{},message:i}),this.host.tracing&&this.emit({type:"diagnostic",kind:e,node:t,...o?{source:o}:{},message:i})}evalExpr(e){return j(this.conditionAst(e),this.context(),z)}conditionAst(e){let t=we.get(e);return t||(t=k(e.ast),we.set(e,t)),t}enter(e){let t=this.visitCounts,r=t.get(e);t.set(e,(r??0)+1);let s=this.host.sharedVisits,i=s.get(e);s.set(e,(i??0)+1),this.host.journal&&this.host.journal.undo.push(()=>{r===void 0?t.delete(e):t.set(e,r),i===void 0?s.delete(e):s.set(e,i)})}rng=()=>{if(this.host.customRng)return this.host.customRng();let e=J(this.rngState),t=e.next();return this.rngState=e.state(),t};beatResult(e){let t=this.host.tagIndex.get(e.id),r=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:e.gameData,...r};case"text":return{type:"text",id:e.id,text:this.interpolate(this.resolveString(e.id)),gameData:e.gameData,...r};case"line":{let s=this.resolveString(e.id),i=!this.host.captionsOn,a=i&&e.character===this.host.captionCharacter?"":this.captionLine(this.host.bundle.voiced?s:this.interpolate(s)),c=i&&a.length===0;return{type:"line",id:e.id,text:a,character:c?void 0:e.character,characterName:c?void 0:this.resolveCharacterName(e.character),direction:c?void 0:e.direction,gameData:e.gameData,...r}}}}interpolate(e){return ye(e,t=>this.getProperty(t))}stripCaptions(e){return Se(e,this.host.captionOpen,this.host.captionClose)}captionLine(e){return this.host.captionsOn?e:this.stripCaptions(e)}promptFor(e){let t=this.promptBeatOf(e);if(!t)return;let r=this.interpolate(this.resolveString(t.id));return t.kind==="line"?{kind:"line",text:this.captionLine(r),character:t.character,characterName:this.resolveCharacterName(t.character),direction:t.direction}:{kind:"text",text:r}}authoredPromptOf(e){return e.type==="group"?e.prompt:void 0}promptResult(e,t){let r=this.host.tagIndex.get(e.id),s=r&&r.length?{tags:r}:{};return t.kind==="text"?{type:"text",id:e.id,text:t.text,gameData:e.gameData,...s}:{type:"line",id:e.id,text:t.text,character:t.character,characterName:t.characterName,direction:t.direction,gameData:e.gameData,...s}}promptBeatOf(e){return e.type==="group"&&e.prompt?e.prompt:((e.type==="snippet"?e:this.firstTextSnippetIn(e.children))?.beats??[]).find(r=>r.kind==="line"||r.kind==="text")}firstTextSnippetIn(e){let t;return C(e,r=>{!t&&r.type==="snippet"&&(r.beats??[]).some(s=>s.kind==="line"||s.kind==="text")&&(t=r)}),t}resolveString(e){if(this.host.emitIds)return e;let t=this.host.strings[e];if(t!==void 0)return t;let r=this.host.defaultStrings[e];return r!==void 0?`<Untranslated: ${e}> ${r}`:e}resolveCharacterName(e){if(e===void 0||this.host.emitIds)return;let t=Y(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}splitRef(e){return Be(this.host,e)}newLocal(){return new b(this.host.patterLocalDecls,{pathPrefix:"@patter."})}mountLocal(){this.local=this.newLocal();let e=y.flowGlobals(this.id);this.host.registry.mountOwned(e,this.local,{owner:F}),this.registered.add(e)}releaseBags(e){for(let t of this.registered)this.host.registry.remove(t,{keep:e});this.registered.clear(),this.sceneBags.clear()}sceneBagFor(e,t){if(this.host.bundle.scenes[e])return this.ensureSceneBags(e),this.host.sceneSharedNames.get(e)?.has(t.toLowerCase())?this.host.stageBags.get(e):this.sceneBags.get(e)}ensureSceneBags(e){let t=this.host.sceneSharedNames.get(e)??new Set,r=this.host.bundle.scenes[e]?.sceneProps??[],s=this.host.journal;if(!this.sceneBags.has(e)){let i=new b(r.filter(c=>!t.has(c.name.toLowerCase())),{pathPrefix:"@scene."}),o=y.flowScene(this.id,e),a=Ee(this.host.registry,o,i,s!==null);this.registered.add(o),this.sceneBags.set(e,i),s&&s.undo.push(()=>{this.sceneBags.get(e)===i&&(this.host.registry.remove(o,a?{keep:!0}:void 0),this.registered.delete(o),this.sceneBags.delete(e))})}if(!this.host.stageBags.has(e)){let i=new b(r.filter(a=>t.has(a.name.toLowerCase())),{pathPrefix:"@scene."}),o=Ee(this.host.registry,y.stage(e),i,s!==null);this.host.stageBags.set(e,i),s&&s.undo.push(()=>{this.host.stageBags.get(e)===i&&(this.host.registry.remove(y.stage(e),o?{keep:!0}:void 0),this.host.stageBags.delete(e))})}}seedScene(e){let t=this.host.sceneSharedNames.get(e.id)??new Set;this.ensureSceneBags(e.id);for(let r of e.sceneProps??[]){if(!r.temporary)continue;let s=r.name.toLowerCase(),i=t.has(s)?this.host.stageBags.get(e.id):this.sceneBags.get(e.id);if(!i)continue;let o=this.host.journal?i.get(s):void 0;o!==void 0&&this.host.journal.undo.push(()=>i.set(s,o)),i.set(s,P(r))}}};function xe(n,e){C(n,t=>{if(t.type==="group"){t.prompt?.kind==="line"&&t.prompt.character&&e.add(t.prompt.character);return}for(let r of t.beats??[])r.kind==="line"&&r.character&&e.add(r.character)})}function ke(n){return n&&Object.keys(n).length?{gameData:n}:{}}function tt(n){let e={kind:n.kind,text:n.text};return n.character!==void 0&&(e.character=n.character),n.characterName!==void 0&&(e.characterName=n.characterName),n.direction!==void 0&&(e.direction=n.direction),e}function Re(n){let e={};for(let[t,r]of n){let s={};r.seq!==void 0&&(s.seq=r.seq),r.bag&&(s.bag=[...r.bag]),r.last!==void 0&&(s.last=r.last),e[t]=s}return e}function Pe(n){let e=new Map;for(let[t,r]of Object.entries(n??{})){let s={};r.seq!==void 0&&(s.seq=r.seq),r.bag&&(s.bag=[...r.bag]),r.last!==void 0&&(s.last=r.last),e.set(t,s)}return e}function Ee(n,e,t,r){let s=r?JSON.stringify(t.save()):"";return n.mountOwned(e,t,{owner:F}),r&&JSON.stringify(t.save())!==s}function Ce(n){return{name:n.name,type:n.type,values:n.values,stages:n.stages,default:n.default}}function Ie(n){return{...n.world?{world:n.world}:{},...n.hostScopes}}function Z(n,e,t){let r=n.qualityLadders.get(e);if(!r){r=new Map;for(let s of t()??[]){let i=s.name.toLowerCase();s.type==="quality"&&s.stages&&!r.has(i)&&r.set(i,s.stages)}n.qualityLadders.set(e,r)}return r}function Oe(n){return{name:n.name,type:n.type,values:n.values,stages:n.stages,default:n.default,writable:n.writable}}function rt(n,e){let t=Oe(n),r=n.writable??e;return r===void 0?t:{...t,writable:r}}function ee(n,e){return n.sceneGameIdToId.get(e)??(n.bundle.scenes[e]?e:void 0)}function te(n,e,t){return n.blockGameIdToId.get(e)?.get(t)??(n.blockIndex.get(t)?.sceneId===e?t:void 0)}function Be(n,e){n.refSplitRevision!==n.registry.revision&&(n.refSplitCache.clear(),n.refSplitRevision=n.registry.revision);let t=n.refSplitCache.get(e);return t||(t=me(e,r=>r==="scene"||n.registry.has(r)||(n.bundle.externalScopes?.includes(r)??!1)),n.refSplitCache.set(e,t)),t}function nt(n){let e={};n.shared?.patter&&(e.patter=n.shared.patter);for(let[t,r]of Object.entries(n.stageBags??{}))e[y.stage(t)]=r;for(let[t,r]of Object.entries(n.flows??{})){r.scopes?.patter&&(e[y.flowGlobals(t)]=r.scopes.patter);for(let[s,i]of Object.entries(r.sceneBags??{}))e[y.flowScene(t,s)]=i}return e}function De(n){return typeof n=="boolean"?n:typeof n=="number"?n!==0:typeof n=="string"?n!=="":n.length>0}var st=(n,e)=>n.shared??e;function re(n,e){return{name:n.name,type:n.type,hasDefault:n.default!==void 0,...n.default!==void 0?{default:n.default}:{},shared:st(n,e)}}function it(n){return{name:n.name,type:n.type,hasDefault:n.default!==void 0,...n.values?{values:[...n.values]}:{},...n.purpose?{purpose:n.purpose}:{}}}function ot(n,e){e.blocks++;let t=[...n.children];for(;t.length;){let r=t.pop();if(r.type==="group"){e.groups++,r.prompt&&e.prompts++,t.push(...r.children);continue}e.snippets++;for(let s of r.beats??[])e.beats++,s.kind==="gameEvent"&&e.gameEvents++}}function Ne(n){let e={scenes:0,blocks:0,groups:0,snippets:0,beats:0,prompts:0,gameEvents:0,cast:n.cast?.length??0},t=[],r=[];for(let o of Object.values(n.scenes)){e.scenes++;let a=S(o);t.push({gameId:a,name:o.name,blocks:o.blocks.map(c=>({gameId:S(c),name:c.name}))});for(let c of o.blocks)ot(c,e);o.sceneProps?.length&&r.push({gameId:a,properties:o.sceneProps.map(c=>re(c,!1))})}let s=(n.scopeRegistry?.scopes??[]).map(o=>({token:o.token,writable:o.writable??!0,opaque:o.declarations===void 0,properties:(o.declarations??[]).map(a=>re(a,!0))})),i=Object.entries(n.gameDataFields??{}).filter(([,o])=>(o?.length??0)>0).map(([o,a])=>({kind:o,fields:(a??[]).map(it)}));return{identity:{schema:n.schema,project:n.content.project,...n.content.version!==void 0?{version:n.content.version}:{},...n.content.hash!==void 0?{hash:n.content.hash}:{},...n.content.structureHash!==void 0?{structureHash:n.content.structureHash}:{},voiced:n.voiced,defaultLocale:n.locales.default,locales:[...n.locales.included],localisation:n.localisation?.mode??"embedded",sourceDebug:n.localisation?.sourceDebug??!1},addresses:t,hostScopes:s,properties:{patter:(n.properties??[]).map(o=>re(o,!0)),scene:r},gameData:i,counts:e}}function Fe(n,e){return n.gameDataFields?.[e]??[]}function ne(n,e,t){return e&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:n.find(r=>r.name===t)?.default}function Ae(n,e){let t={};for(let r of n){let s=ne(n,e,r.name);s!==void 0&&(t[r.name]=s)}for(let[r,s]of Object.entries(e??{}))r in t||(t[r]=s);return t}return qe(at);})();\n';
|
|
200808
200808
|
|
|
200809
200809
|
// ../ops/src/export-html.ts
|
|
200810
200810
|
var esc = (s) => s.replace(/[&<>]/g, (c2) => ({ "&": "&", "<": "<", ">": ">" })[c2]);
|
|
@@ -201114,7 +201114,7 @@ var Engine = class _Engine {
|
|
|
201114
201114
|
sceneGameIdToId = /* @__PURE__ */ new Map();
|
|
201115
201115
|
blockGameIdToId = /* @__PURE__ */ new Map();
|
|
201116
201116
|
/** The options this engine was built with - reused verbatim by `hotSwap` so the replacement
|
|
201117
|
-
* engine keeps the same
|
|
201117
|
+
* engine keeps the same host scopes, custom RNG, and diagnostic hooks. */
|
|
201118
201118
|
creationOptions;
|
|
201119
201119
|
/** The run's ordered stream: every flow's events, each naming its flow. Empty and
|
|
201120
201120
|
* unwritten unless `options.log` asked for it. */
|
|
@@ -201166,12 +201166,12 @@ var Engine = class _Engine {
|
|
|
201166
201166
|
registry.mountOwned("patter", patterBag, { owner: OWNER });
|
|
201167
201167
|
registered.push("patter");
|
|
201168
201168
|
const hostBound = /* @__PURE__ */ new Set();
|
|
201169
|
-
|
|
201170
|
-
const
|
|
201171
|
-
const decls = (
|
|
201172
|
-
registry.defineForeign(
|
|
201173
|
-
registered.push(
|
|
201174
|
-
hostBound.add(
|
|
201169
|
+
for (const [token2, resolver] of Object.entries(boundScopes(options))) {
|
|
201170
|
+
const spec = bundle.scopeRegistry?.scopes.find((s) => s.token === token2);
|
|
201171
|
+
const decls = (spec?.declarations ?? []).map(toForeignDecl);
|
|
201172
|
+
registry.defineForeign(token2, resolver, decls, { writable: spec?.writable ?? true, owner: OWNER });
|
|
201173
|
+
registered.push(token2);
|
|
201174
|
+
hostBound.add(token2);
|
|
201175
201175
|
}
|
|
201176
201176
|
for (const spec of ownsRegistry ? bundle.scopeRegistry?.scopes ?? [] : []) {
|
|
201177
201177
|
if (hostBound.has(spec.token) || registry.has(spec.token)) continue;
|
|
@@ -201191,6 +201191,7 @@ var Engine = class _Engine {
|
|
|
201191
201191
|
}
|
|
201192
201192
|
this.host = {
|
|
201193
201193
|
logEnabled: options.log ?? false,
|
|
201194
|
+
tracing: options.log ?? false,
|
|
201194
201195
|
emitEngine: (flow, event, scene) => this.emitEngine(flow, event, scene),
|
|
201195
201196
|
bundle,
|
|
201196
201197
|
emitIds,
|
|
@@ -201213,6 +201214,7 @@ var Engine = class _Engine {
|
|
|
201213
201214
|
patterSharedNames,
|
|
201214
201215
|
sceneSharedNames,
|
|
201215
201216
|
sharedVisits: /* @__PURE__ */ new Map(),
|
|
201217
|
+
qualityLadders: /* @__PURE__ */ new Map(),
|
|
201216
201218
|
sharedSelectors: /* @__PURE__ */ new Map(),
|
|
201217
201219
|
stageBags: /* @__PURE__ */ new Map(),
|
|
201218
201220
|
journal: null,
|
|
@@ -201239,6 +201241,11 @@ var Engine = class _Engine {
|
|
|
201239
201241
|
get isSourceDebug() {
|
|
201240
201242
|
return this.sourceDebug;
|
|
201241
201243
|
}
|
|
201244
|
+
/** The bundle's build identity (its content hash), the one a debug link handshakes with, or an empty
|
|
201245
|
+
* string for a bundle compiled without one. */
|
|
201246
|
+
get buildId() {
|
|
201247
|
+
return this.host.bundle.content?.hash ?? "";
|
|
201248
|
+
}
|
|
201242
201249
|
/**
|
|
201243
201250
|
* Switch the active locale LIVE - a real game's "language" setting can change mid-session. Subsequent
|
|
201244
201251
|
* string lookups (new beats, re-resolved character names, `{@ref}` interpolation) render in the new
|
|
@@ -201359,7 +201366,7 @@ var Engine = class _Engine {
|
|
|
201359
201366
|
});
|
|
201360
201367
|
}
|
|
201361
201368
|
this.flowsById.set(id, flow);
|
|
201362
|
-
flow.
|
|
201369
|
+
flow.begin(sceneId, blockId);
|
|
201363
201370
|
return flow;
|
|
201364
201371
|
}
|
|
201365
201372
|
/**
|
|
@@ -201723,7 +201730,7 @@ var Engine = class _Engine {
|
|
|
201723
201730
|
for (const s of this.host.stageBags.keys()) reg.remove(keys.stage(s), { keep });
|
|
201724
201731
|
this.host.stageBags.clear();
|
|
201725
201732
|
for (const t of ["patter", ...this.host.hostScopes]) if (reg.has(t)) reg.remove(t, { keep });
|
|
201726
|
-
|
|
201733
|
+
for (const t of Object.keys(boundScopes(this.creationOptions))) if (reg.has(t)) reg.remove(t);
|
|
201727
201734
|
}
|
|
201728
201735
|
/** Read a shared (`@patter` / foreign) property by ref. `@scene` refs are rejected (flow-level). */
|
|
201729
201736
|
getProperty(ref) {
|
|
@@ -201760,13 +201767,22 @@ var Engine = class _Engine {
|
|
|
201760
201767
|
* retained. Returns its own unsubscribe. */
|
|
201761
201768
|
onTrace(handler) {
|
|
201762
201769
|
this.engineTraceHandlers.add(handler);
|
|
201763
|
-
|
|
201770
|
+
this.host.tracing = true;
|
|
201771
|
+
return () => {
|
|
201772
|
+
this.engineTraceHandlers.delete(handler);
|
|
201773
|
+
this.host.tracing = this.host.logEnabled || this.engineTraceHandlers.size > 0;
|
|
201774
|
+
};
|
|
201764
201775
|
}
|
|
201765
201776
|
emitEngine(flow, event, scene) {
|
|
201766
201777
|
for (const h of this.engineTraceHandlers) h(flow, event);
|
|
201767
201778
|
if (!this.host.logEnabled) return;
|
|
201768
201779
|
this.engineLog.push({ ...event, flow, seq: this.engineSeq++, ...scene ? { scene } : {} });
|
|
201769
201780
|
}
|
|
201781
|
+
/** How many times each node has been entered across every flow, by node id: the shared count. With a
|
|
201782
|
+
* flow's own {@link Flow.getVisitCounts}, every visit count the run keeps, read without a save. */
|
|
201783
|
+
getVisitCounts() {
|
|
201784
|
+
return Object.fromEntries(this.host.sharedVisits);
|
|
201785
|
+
}
|
|
201770
201786
|
listProperties() {
|
|
201771
201787
|
return this.host.patterSharedDecls.map((d) => ({
|
|
201772
201788
|
name: d.name,
|
|
@@ -201971,19 +201987,21 @@ var Flow = class {
|
|
|
201971
201987
|
* lowercase, as the compiler emits references (the selfBackedResolver lesson). */
|
|
201972
201988
|
stagesFor(scope, name) {
|
|
201973
201989
|
const key2 = name.toLowerCase();
|
|
201974
|
-
const fromDecls = (decls) => decls?.find((d) => d.name.toLowerCase() === key2 && d.type === "quality")?.stages;
|
|
201975
201990
|
if (scope === "patter") {
|
|
201976
|
-
return
|
|
201991
|
+
return ladders(this.host, "patter", () => [...this.host.patterSharedDecls, ...this.host.patterLocalDecls]).get(key2);
|
|
201977
201992
|
}
|
|
201978
201993
|
if (scope === "scene") {
|
|
201979
|
-
const
|
|
201980
|
-
|
|
201994
|
+
const sceneId = this.currentSceneId;
|
|
201995
|
+
if (sceneId == null) return void 0;
|
|
201996
|
+
return ladders(this.host, `scene/${sceneId}`, () => this.host.bundle.scenes[sceneId]?.sceneProps).get(key2);
|
|
201981
201997
|
}
|
|
201982
|
-
return this.registryQualities?.(scope, name) ??
|
|
201998
|
+
return this.registryQualities?.(scope, name) ?? ladders(this.host, `host/${scope}`, () => this.host.bundle.scopeRegistry?.scopes.find((s) => s.token === scope)?.declarations).get(key2);
|
|
201983
201999
|
}
|
|
201984
202000
|
// -- Host API -------------------------------------------------------------
|
|
201985
|
-
/** Begin this flow at a scene (and optionally a specific block within it).
|
|
201986
|
-
|
|
202001
|
+
/** Begin this flow at a scene (and optionally a specific block within it). The engine's own entry point:
|
|
202002
|
+
* openFlow and a goto on an unstarted flow begin a flow here. A game calls {@link reset}.
|
|
202003
|
+
* @internal */
|
|
202004
|
+
begin(sceneId, blockId) {
|
|
201987
202005
|
if (this.host.journal && !this.host.journal.opened.has(this)) throw new Error("a flow can't be started or reset while a checkpoint is open");
|
|
201988
202006
|
this.releaseBags(false);
|
|
201989
202007
|
this.host.registry.discardParked(keys.flow(this.id));
|
|
@@ -201995,7 +202013,7 @@ var Flow = class {
|
|
|
201995
202013
|
this.flowEnded = false;
|
|
201996
202014
|
this.activeSnippet = null;
|
|
201997
202015
|
this.beatIndex = 0;
|
|
201998
|
-
this.
|
|
202016
|
+
this.clearPending();
|
|
201999
202017
|
this.started = true;
|
|
202000
202018
|
if (blockId) {
|
|
202001
202019
|
const loc = this.host.blockIndex.get(blockId);
|
|
@@ -202020,10 +202038,15 @@ var Flow = class {
|
|
|
202020
202038
|
* Forget everything in this flow and begin again - its per-flow state (not-shared
|
|
202021
202039
|
* `@patter` globals + `@scene` props), cursor, callstack, selector cursors, and
|
|
202022
202040
|
* visit counts. Shared state (shared `@patter` / `@scene`, world visit counts) is
|
|
202023
|
-
* untouched.
|
|
202041
|
+
* untouched. The one public way to begin a flow again (openFlow begins a new one).
|
|
202024
202042
|
*/
|
|
202025
202043
|
reset(sceneId, blockId) {
|
|
202026
|
-
this.
|
|
202044
|
+
this.begin(sceneId, blockId);
|
|
202045
|
+
}
|
|
202046
|
+
/** @deprecated Use {@link reset}, the one public name for beginning a flow again on every runtime. `start`
|
|
202047
|
+
* was the same call under a second name, and goes in a later release. */
|
|
202048
|
+
start(sceneId, blockId) {
|
|
202049
|
+
this.reset(sceneId, blockId);
|
|
202027
202050
|
}
|
|
202028
202051
|
/**
|
|
202029
202052
|
* Send this flow's cursor to an ADDRESS, exactly as an authored `go` jump would: the target scene's
|
|
@@ -202047,9 +202070,7 @@ var Flow = class {
|
|
|
202047
202070
|
this.touch();
|
|
202048
202071
|
if (scene === "END") {
|
|
202049
202072
|
this.started = true;
|
|
202050
|
-
this.
|
|
202051
|
-
this.pendingPrompt = null;
|
|
202052
|
-
this.pendingPromptOwnerId = null;
|
|
202073
|
+
this.clearPending();
|
|
202053
202074
|
this.activeSnippet = null;
|
|
202054
202075
|
this.beatIndex = 0;
|
|
202055
202076
|
this.flowEnded = true;
|
|
@@ -202064,12 +202085,10 @@ var Flow = class {
|
|
|
202064
202085
|
if (blockId === void 0) return false;
|
|
202065
202086
|
}
|
|
202066
202087
|
if (!this.started) {
|
|
202067
|
-
this.
|
|
202088
|
+
this.begin(sceneId, blockId);
|
|
202068
202089
|
return true;
|
|
202069
202090
|
}
|
|
202070
|
-
this.
|
|
202071
|
-
this.pendingPrompt = null;
|
|
202072
|
-
this.pendingPromptOwnerId = null;
|
|
202091
|
+
this.clearPending();
|
|
202073
202092
|
this.activeSnippet = null;
|
|
202074
202093
|
this.beatIndex = 0;
|
|
202075
202094
|
this.flowEnded = false;
|
|
@@ -202094,6 +202113,15 @@ var Flow = class {
|
|
|
202094
202113
|
this.stack = [];
|
|
202095
202114
|
this.activeSnippet = null;
|
|
202096
202115
|
this.beatIndex = 0;
|
|
202116
|
+
this.clearPending();
|
|
202117
|
+
}
|
|
202118
|
+
/**
|
|
202119
|
+
* Drop everything waiting to be delivered: an open choice, and a chosen option's prompt still to be
|
|
202120
|
+
* replayed. Every move that abandons the flow's place (start and reset, goto, close) does this, so none
|
|
202121
|
+
* leaves a stale prompt behind. start() cleared only the choice, so a reset between choose() and the
|
|
202122
|
+
* next advance() replayed the abandoned run's prompt as the new run's first beat.
|
|
202123
|
+
*/
|
|
202124
|
+
clearPending() {
|
|
202097
202125
|
this.pendingChoice = null;
|
|
202098
202126
|
this.pendingPrompt = null;
|
|
202099
202127
|
this.pendingPromptOwnerId = null;
|
|
@@ -202190,7 +202218,7 @@ var Flow = class {
|
|
|
202190
202218
|
}
|
|
202191
202219
|
const from = frame.index;
|
|
202192
202220
|
while (frame.index < children.length && !this.eligible(children[frame.index])) frame.index++;
|
|
202193
|
-
if (this.host.
|
|
202221
|
+
if (this.host.tracing && frame.index !== from) {
|
|
202194
202222
|
this.emit({
|
|
202195
202223
|
type: "select",
|
|
202196
202224
|
group: frame.containerId,
|
|
@@ -202226,14 +202254,18 @@ var Flow = class {
|
|
|
202226
202254
|
clearLog() {
|
|
202227
202255
|
this.flowLog.length = 0;
|
|
202228
202256
|
}
|
|
202229
|
-
/** Record one decision, on this flow's log and the engine's
|
|
202230
|
-
*
|
|
202257
|
+
/** Record one decision, on this flow's log and the engine's, and hand it to any `onTrace`. Each call
|
|
202258
|
+
* site checks `host.tracing` first, so with nothing logging or tracing the entry is never built. */
|
|
202231
202259
|
emit(event) {
|
|
202232
202260
|
const scene = this.currentSceneId ?? void 0;
|
|
202233
202261
|
this.host.emitEngine(this.id, event, scene);
|
|
202234
202262
|
if (!this.host.logEnabled) return;
|
|
202235
202263
|
this.flowLog.push({ ...event, seq: this.flowSeq++, ...scene ? { scene } : {} });
|
|
202236
202264
|
}
|
|
202265
|
+
/** How many times this flow has entered each node, by node id. */
|
|
202266
|
+
getVisitCounts() {
|
|
202267
|
+
return Object.fromEntries(this.visitCounts);
|
|
202268
|
+
}
|
|
202237
202269
|
/** The options of a pending choice (empty when not at a choice point). */
|
|
202238
202270
|
getChoices() {
|
|
202239
202271
|
return this.pendingChoice?.options ?? [];
|
|
@@ -202247,7 +202279,7 @@ var Flow = class {
|
|
|
202247
202279
|
if (!option.eligible) throw new Error(`choice option is not eligible: ${id}`);
|
|
202248
202280
|
this.touch();
|
|
202249
202281
|
const node = choice.byId.get(id);
|
|
202250
|
-
this.emit({ type: "chose", group: choice.groupId, option: id });
|
|
202282
|
+
if (this.host.tracing) this.emit({ type: "chose", group: choice.groupId, option: id });
|
|
202251
202283
|
this.pendingChoice = null;
|
|
202252
202284
|
const authored = this.host.replayPromptOnChoose ? this.authoredPromptOf(node) : void 0;
|
|
202253
202285
|
this.pendingPrompt = authored && option.prompt ? { beat: authored, shown: { ...option.prompt } } : null;
|
|
@@ -202443,7 +202475,7 @@ var Flow = class {
|
|
|
202443
202475
|
byId.set(child2.id, child2);
|
|
202444
202476
|
}
|
|
202445
202477
|
if (options.some((o) => o.eligible)) {
|
|
202446
|
-
this.emit({ type: "choice", group: group.id, options: options.map((o) => ({ id: o.id, eligible: o.eligible })) });
|
|
202478
|
+
if (this.host.tracing) this.emit({ type: "choice", group: group.id, options: options.map((o) => ({ id: o.id, eligible: o.eligible })) });
|
|
202447
202479
|
this.pendingChoice = { groupId: group.id, options, byId };
|
|
202448
202480
|
return;
|
|
202449
202481
|
}
|
|
@@ -202452,7 +202484,7 @@ var Flow = class {
|
|
|
202452
202484
|
this.enterChild(fallback2);
|
|
202453
202485
|
return;
|
|
202454
202486
|
}
|
|
202455
|
-
this.emit({ type: "dry", group: group.id });
|
|
202487
|
+
if (this.host.tracing) this.emit({ type: "dry", group: group.id });
|
|
202456
202488
|
this.host.onDryChoice?.(group.id);
|
|
202457
202489
|
}
|
|
202458
202490
|
// -- Jumps (jump / call-return) ----------------------------------------
|
|
@@ -202467,7 +202499,7 @@ var Flow = class {
|
|
|
202467
202499
|
* hard-ends the flow regardless of the callstack.
|
|
202468
202500
|
*/
|
|
202469
202501
|
enterTarget(to, mode) {
|
|
202470
|
-
this.emit({ type: "jump", to, mode });
|
|
202502
|
+
if (this.host.tracing) this.emit({ type: "jump", to, mode });
|
|
202471
202503
|
if (to === "END") {
|
|
202472
202504
|
this.flowEnded = true;
|
|
202473
202505
|
this.stack = [];
|
|
@@ -202504,7 +202536,7 @@ var Flow = class {
|
|
|
202504
202536
|
const order = group.options?.order ?? "sequential";
|
|
202505
202537
|
const exhaust = group.options?.exhaust ?? "once";
|
|
202506
202538
|
const trace = (picked) => {
|
|
202507
|
-
this.emit({
|
|
202539
|
+
if (this.host.tracing) this.emit({
|
|
202508
202540
|
type: "select",
|
|
202509
202541
|
group: group.id,
|
|
202510
202542
|
selector: group.selector ?? "default",
|
|
@@ -202669,9 +202701,9 @@ var Flow = class {
|
|
|
202669
202701
|
let value;
|
|
202670
202702
|
try {
|
|
202671
202703
|
value = this.evalExpr(e.value);
|
|
202672
|
-
const prev = this.host.
|
|
202704
|
+
const prev = this.host.tracing ? this.getProperty(e.target) : void 0;
|
|
202673
202705
|
this.writeProperty(e.target, value, false);
|
|
202674
|
-
this.emit({ type: "write", target: e.target, value, ...prev !== void 0 ? { prev } : {} });
|
|
202706
|
+
if (this.host.tracing) this.emit({ type: "write", target: e.target, value, ...prev !== void 0 ? { prev } : {} });
|
|
202675
202707
|
} catch (err) {
|
|
202676
202708
|
this.reportError("effect", owner, e.value, err);
|
|
202677
202709
|
}
|
|
@@ -202692,7 +202724,7 @@ var Flow = class {
|
|
|
202692
202724
|
const message = err instanceof Error ? err.message : String(err);
|
|
202693
202725
|
const source2 = expr?.src;
|
|
202694
202726
|
this.host.onError({ flow: this.id, kind, node, ...source2 ? { source: source2 } : {}, message });
|
|
202695
|
-
this.emit({ type: "diagnostic", kind, node, ...source2 ? { source: source2 } : {}, message });
|
|
202727
|
+
if (this.host.tracing) this.emit({ type: "diagnostic", kind, node, ...source2 ? { source: source2 } : {}, message });
|
|
202696
202728
|
}
|
|
202697
202729
|
evalExpr(expr) {
|
|
202698
202730
|
return evaluate(this.conditionAst(expr), this.context(), patterDialect);
|
|
@@ -202979,6 +203011,21 @@ function mountClaims(registry, key2, bag, ask) {
|
|
|
202979
203011
|
function toDecl(decl) {
|
|
202980
203012
|
return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default };
|
|
202981
203013
|
}
|
|
203014
|
+
function boundScopes(options) {
|
|
203015
|
+
return { ...options.world ? { world: options.world } : {}, ...options.hostScopes };
|
|
203016
|
+
}
|
|
203017
|
+
function ladders(host2, cacheKey, decls) {
|
|
203018
|
+
let found = host2.qualityLadders.get(cacheKey);
|
|
203019
|
+
if (!found) {
|
|
203020
|
+
found = /* @__PURE__ */ new Map();
|
|
203021
|
+
for (const d of decls() ?? []) {
|
|
203022
|
+
const k = d.name.toLowerCase();
|
|
203023
|
+
if (d.type === "quality" && d.stages && !found.has(k)) found.set(k, d.stages);
|
|
203024
|
+
}
|
|
203025
|
+
host2.qualityLadders.set(cacheKey, found);
|
|
203026
|
+
}
|
|
203027
|
+
return found;
|
|
203028
|
+
}
|
|
202982
203029
|
function toForeignDecl(decl) {
|
|
202983
203030
|
return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default, writable: decl.writable };
|
|
202984
203031
|
}
|
|
@@ -203502,7 +203549,7 @@ function renderCoverageText(report, sceneName = (id) => id, opts = {}) {
|
|
|
203502
203549
|
);
|
|
203503
203550
|
out.push(`${report.runs} run(s) - ${report.maxSteps} max steps - seed ${report.seed}${report.cancelled ? " - CANCELLED" : ""}`);
|
|
203504
203551
|
const term = report.termination;
|
|
203505
|
-
out.push(`runs ended: ${term.ended} reached the end, ${term.stalled} stalled at a choice with nothing to pick, ${term.capped} hit the step limit, ${term.evalError} errored`);
|
|
203552
|
+
out.push(`runs ended: ${term.ended} reached the end, ${term.stalled ? `${term.stalled} stalled at a choice with nothing to pick, ` : ""}${term.capped} hit the step limit, ${term.evalError} errored`);
|
|
203506
203553
|
if (report.drivers.length) out.push(`input drivers: ${report.drivers.map((d) => d.ref).join(", ")}`);
|
|
203507
203554
|
if (report.unwrittenInputs.length) {
|
|
203508
203555
|
out.push(`? = gated on an input nothing writes/drives: ${report.unwrittenInputs.join(", ")} (add a coverage driver?)`);
|
|
@@ -248993,7 +249040,7 @@ function fileStatus(filePaths, options = {}) {
|
|
|
248993
249040
|
// package.json
|
|
248994
249041
|
var package_default = {
|
|
248995
249042
|
name: "@patterkit/cli",
|
|
248996
|
-
version: "0.8.
|
|
249043
|
+
version: "0.8.1",
|
|
248997
249044
|
description: "The `patter` CLI: validate, format, export, and play a Patter project.",
|
|
248998
249045
|
type: "module",
|
|
248999
249046
|
license: "MIT",
|
|
@@ -249023,7 +249070,7 @@ var package_default = {
|
|
|
249023
249070
|
},
|
|
249024
249071
|
dependencies: {
|
|
249025
249072
|
"@patterkit/core": "0.3.2",
|
|
249026
|
-
"@patterkit/ops": "0.13.
|
|
249073
|
+
"@patterkit/ops": "0.13.1",
|
|
249027
249074
|
"@wildwinter/simple-vc-lib": "^0.5.0"
|
|
249028
249075
|
}
|
|
249029
249076
|
};
|
|
@@ -249766,7 +249813,7 @@ function describeSuggestion(o) {
|
|
|
249766
249813
|
}
|
|
249767
249814
|
|
|
249768
249815
|
// src/cli.ts
|
|
249769
|
-
process.
|
|
249816
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
249770
249817
|
/*! Bundled license information:
|
|
249771
249818
|
|
|
249772
249819
|
xmlchars/xml/1.0/ed5.js:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patterkit/cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "The `patter` CLI: validate, format, export, and play a Patter project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@patterkit/core": "0.3.2",
|
|
33
|
-
"@patterkit/ops": "0.13.
|
|
33
|
+
"@patterkit/ops": "0.13.1",
|
|
34
34
|
"@wildwinter/simple-vc-lib": "^0.5.0"
|
|
35
35
|
}
|
|
36
36
|
}
|