@patterkit/ops 1.0.0 → 1.0.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/index.js +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -2706,7 +2706,7 @@ import { canonicalStringify as canonicalStringify5 } from "@patterkit/core";
|
|
|
2706
2706
|
import { DEFAULT_PAD_AFTER } from "@patterkit/model";
|
|
2707
2707
|
|
|
2708
2708
|
// src/playable-runtime.ts
|
|
2709
|
-
var PLAYABLE_RUNTIME_JS = 'var Patterplay=(()=>{var ue=Object.defineProperty;var At=Object.getOwnPropertyDescriptor;var Ft=Object.getOwnPropertyNames;var Bt=Object.prototype.hasOwnProperty;var Lt=(r,e)=>{for(var t in e)ue(r,t,{get:e[t],enumerable:!0})},Tt=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Ft(e))!Bt.call(r,s)&&s!==t&&ue(r,s,{get:()=>e[s],enumerable:!(n=At(e,s))||n.enumerable});return r};var Mt=r=>Tt(ue({},"__esModule",{value:!0}),r);var fn={};Lt(fn,{Checkpoint:()=>J,DEFAULT_ESTIMATE_SPEED:()=>V,DEFAULT_PAD_AFTER:()=>O,Engine:()=>le,Flow:()=>A,LINE_DURATION_MAX:()=>ve,LINE_DURATION_MIN:()=>be,PATTERPLAY_VERSION:()=>vt,SUBTITLE_READING_MIN:()=>Ue,buildTagIndex:()=>ae,compareStages:()=>B,describeBundle:()=>kt,effectiveGameData:()=>Dt,estimateLineDuration:()=>We,extensionDecls:()=>It,extensionsOf:()=>Ct,gameDataFields:()=>Et,gameDataValue:()=>Re,nextStage:()=>L,resolveSceneRef:()=>se,sceneAddressIndex:()=>we,stageIndex:()=>F,versionInRange:()=>xt});function M(r,e){return r!==void 0&&Object.prototype.hasOwnProperty.call(r,e)?r[e]:void 0}function R(r){switch(r[0]){case"b":return{kind:"bool",value:r[1]};case"n":return{kind:"number",value:r[1]};case"s":return{kind:"string",value:r[1]};case"sv":return{kind:"scopedvar",scope:r[1],name:r[2]};case"u":return{kind:"unary",op:r[1],operand:R(r[2])};case"bin":return{kind:"binary",op:r[1],left:R(r[2]),right:R(r[3])};case"call":{let e=r.slice(2).map(R);return{kind:"call",name:r[1],args:e}}case"fd":return{kind:"flagdelta",sign:r[1],name:r[2]}}}var u=class extends Error{constructor(e){super(e),this.name="EvalError"}};function Z(r,e,t){let n=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=M(e.scopes,i.scope);if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):M(o,i.name);if(a===void 0){if(n.get(i.scope)==="throw")throw new u(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{if(i.name==="advance"&&!M(t.functions,i.name)){let a=i.args[0];if(i.args.length!==1||a===void 0)throw new u(`advance() takes exactly 1 argument, got ${i.args.length}`);let c=ge(a,e);if(c===void 0)throw new u("advance() needs a quality reference (@scope.name of a quality property)");let l=v(s(a),c,"advance");return c[Math.min(l+1,c.length-1)]}let o=M(t.functions,i.name);if(!o)throw new u(`unknown function \'${i.name}\'`);return o.eval(i.args,{evaluate:s,ctx:e})}case"flagdelta":throw new u("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 u(`\'not\' requires a boolean operand, got ${typeof a}`);return!a}let o=s(i.operand);if(typeof o!="number")throw new u(`unary \'-\' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let g=s(i.left);if(typeof g!="boolean")throw new u(`\'and\' requires boolean operands, left is ${typeof g}`);if(!g)return!1;let f=s(i.right);if(typeof f!="boolean")throw new u(`\'and\' requires boolean operands, right is ${typeof f}`);return f}if(i.op==="or"){let g=s(i.left);if(typeof g!="boolean")throw new u(`\'or\' requires boolean operands, left is ${typeof g}`);if(g)return!0;let f=s(i.right);if(typeof f!="boolean")throw new u(`\'or\' requires boolean operands, right is ${typeof f}`);return f}let o=s(i.left),a=s(i.right),c=ge(i.left,e),l=ge(i.right,e),d=c??l;if(d!==void 0){if(c&&l&&!$t(c,l)&&(i.op===">"||i.op===">="||i.op==="<"||i.op==="<="))throw new u(`\'${i.op}\' compares two different qualities, whose stage orders are unrelated`);switch(i.op){case">":return v(o,d,">")>v(a,d,">");case">=":return v(o,d,">=")>=v(a,d,">=");case"<":return v(o,d,"<")<v(a,d,"<");case"<=":return v(o,d,"<=")<=v(a,d,"<=");case"+":case"-":case"*":case"/":throw new u(`\'${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 Be(o,a);case"!=":return!Be(o,a);case">":return P(o,a,">"),o>a;case">=":return P(o,a,">="),o>=a;case"<":return P(o,a,"<"),o<a;case"<=":return P(o,a,"<="),o<=a;case"+":if(typeof o=="number"&&typeof a=="number"||typeof o=="string"&&typeof a=="string")return o+a;throw new u(`\'+\' requires two numbers or two strings, got ${typeof o} and ${typeof a}`);case"-":return P(o,a,"-"),o-a;case"*":return P(o,a,"*"),o*a;case"/":if(P(o,a,"/"),a===0)throw new u("division by zero");return o/a}}}};return s(r)}function Be(r,e){if(Array.isArray(r)||Array.isArray(e)){if(!Array.isArray(r)||!Array.isArray(e)||r.length!==e.length)return!1;let t=[...r].sort(),n=[...e].sort();for(let s=0;s<t.length;s++)if(t[s]!==n[s])return!1;return!0}return r===e}function P(r,e,t){if(typeof r!="number"||typeof e!="number")throw new u(`\'${t}\' requires numeric operands, got ${typeof r} and ${typeof e}`)}function ge(r,e){if(!(r.kind!=="scopedvar"||e.qualities===void 0))return e.qualities(r.scope,r.name)}function v(r,e,t){if(typeof r!="string")throw new u(`\'${t}\' on a quality compares stages, got ${typeof r}`);let n=e.indexOf(r);if(n<0)throw new u(`"${r}" is not a stage of this quality (stages: ${e.join(", ")})`);return n}var $t=(r,e)=>r.length===e.length&&r.every((t,n)=>t===e[n]);function $(r){if(Number.isNaN(r)||!Number.isFinite(r))return 0;let e=Math.trunc(r)%4294967296;return e<0?e+4294967296:e}function fe(r){let e=$(r);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 me=r=>Array.isArray(r)?r:r.stages??[],jt=r=>Array.isArray(r)?"flags":r==null?"nothing":typeof r;function F(r,e){return typeof e=="string"?me(r).indexOf(e):-1}function he(r,e){if(typeof e!="string")throw new u(`a stage is a name, got ${jt(e)}`);let t=r.indexOf(e);if(t<0)throw new u(`"${e}" is not a stage of this quality (stages: ${r.join(", ")})`);return t}function B(r,e,t){let n=me(r),s=he(n,e)-he(n,t);return s<0?-1:s>0?1:0}function L(r,e){let t=me(r);return t[Math.min(he(t,e)+1,t.length-1)]}function j(r,e,t){switch(r.type){case"boolean":return typeof e=="boolean";case"number":return typeof e=="number";case"string":case"text":case"multiline":return typeof e=="string";case"enum":return typeof e!="string"?!1:e===""&&t?.noneChosen?!0:!Array.isArray(r.values)||r.values.includes(e);case"flags":return Array.isArray(e)&&e.every(n=>typeof n=="string"&&(!Array.isArray(r.values)||r.values.includes(n)));case"quality":return typeof e=="string"&&(!Array.isArray(r.stages)||r.stages.includes(e));default:return!0}}var Gt={name:"check_flags",count:r=>Math.max(1,r.args.length-1)},Vt=[Gt];function Le(r,e,t){let n=t?.countingCalls??Vt;return ee(r,t?.want??!0,e,n)}function ee(r,e,t,n){if(r.kind==="binary"&&(r.op==="and"||r.op==="or")){let s=ee(r.left,e,t,n),i=ee(r.right,e,t,n);return r.op==="and"===e?s>0&&i>0?s+i:0:Math.max(s,i)}if(r.kind==="unary"&&r.op==="not")return ee(r.operand,!e,t,n);if(r.kind==="call"){let s=n.find(i=>i.name===r.name);if(s){let i=s.count(r),o=t(r);return e?o?i:0:o?0:1}}return t(r)===e?1:0}var E=class r{values=Object.create(null);decls=new Map;subscribers=new Set;auditors=new Set;norm;pathPrefix;constructor(e=[],t){this.norm=t?.normalise??(n=>n.toLowerCase()),this.pathPrefix=t?.pathPrefix??"",this.seed(e)}seed(e){for(let t of e){let n=this.norm(t.name);this.decls.set(n,t),this.values[n]=structuredClone(t.default??T(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,n){let s=this.norm(e);if(!n?.host&&!this.writable(s))throw new Error(`\'${e}\' is read-only`);let i={name:s,prev:this.values[s],next:t,silent:n?.silent??!1,reason:n?.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])=>Me(t,this.get(e),void 0,e,this.pathPrefix))}declarations(){return[...this.decls.values()]}clone(){let e=new r([],{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,t){let n=new Map;for(let[i,o]of Object.entries(e)){let a=this.norm(i);this.values[a]=structuredClone(o),n.set(a,o)}let s=[];if(!t?.refit)return s;for(let[i,o]of this.decls){if(!n.has(i))continue;let a=n.get(i);j(o,a,{noneChosen:o.type==="enum"&&o.default===""})||(this.values[i]=structuredClone(T(o)),s.push({name:i,value:a}))}return s}};function Me(r,e,t,n,s=""){let i=n??r.name.toLowerCase();return{name:i,path:s+i,type:r.type,value:e,default:r.default??T(r),...r.values!==void 0?{values:r.values}:{},...r.stages!==void 0?{stages:r.stages}:{},writable:t??r.writable??!0}}var qt=r=>r.toLowerCase(),ye=1,te=class{scopes=new Map;parked=new Map;parkedRefit=new Set;misfits=[];rev=0;get revision(){return this.rev}defineOwned(e,t,n){let s=typeof n=="string"?{pathPrefix:n}:n??{},i=new E(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,n){this.assertFree(e,n?.owner),this.scopes.set(e,{kind:"owned",bag:t,...n?.owner!==void 0?{owner:n.owner}:{}}),this.rev++;let s=this.parked.get(e);return s&&(this.note(e,t.load(s,{refit:this.parkedRefit.has(e)})),this.parked.delete(e),this.parkedRefit.delete(e)),this}remove(e,t){let n=this.scopes.get(e);if(!n)throw new Error(`unknown scope \'@${e}\'`);return t?.keep&&n.kind==="owned"&&(this.parked.set(e,n.bag.save()),this.parkedRefit.delete(e)),this.scopes.delete(e),this.rev++,this}discardParked(e){if(e===void 0)this.parked.clear(),this.parkedRefit.clear();else for(let t of[...this.parked.keys()])t.startsWith(e)&&(this.parked.delete(t),this.parkedRefit.delete(t));return this}takeMisfits(e){if(!e){let n=this.misfits;return this.misfits=[],n}let t=this.misfits.filter(n=>e(n.scope));return this.misfits=this.misfits.filter(n=>!e(n.scope)),t}note(e,t){for(let n of t)this.misfits.push({scope:e,name:n.name,value:n.value})}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,n=[],s=!0){let i=typeof s=="boolean"?{writable:s}:s;this.assertFree(e,i.owner);let o=i.normalise??qt,a=new Map;for(let c of n)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 n=this.scopes.get(e);if(n)return n.kind==="owned"?n.bag.get(t):n.resolver.get(n.norm(t))}set(e,t,n,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,n,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,n)}foreignWritable(e,t){return e.resolver.set?e.decls.get(t)?.writable??e.scopeWritable:!1}listProperties(){let e=[];for(let[t,n]of this.scopes){let s=n.owner!==void 0?{owner:n.owner}:{};if(n.kind==="owned")for(let i of n.bag.rows())e.push({scope:t,...s,...i});else for(let[i,o]of n.decls)e.push({scope:t,...s,...Me(o,n.resolver.get(i),this.foreignWritable(n,i),i,`${t}.`)})}return e}toEvalContext(e,t){let n=this.view(t?.aliases),s={};for(let[o,a]of n)s[o]=a.kind==="owned"?a.bag.values:a.resolver;let i=this.qualityLadders(n);return i.size===0?{scopes:s,host:e}:{scopes:s,host:e,qualities:(o,a)=>{let c=n.get(o);return c?i.get(o)?.get(_t(c)(a)):void 0}}}view(e){let t=new Map(this.scopes);for(let[n,s]of Object.entries(e??{})){let i=this.scopes.get(s);if(!i)throw new Error(`alias \'@${n}\' names \'${s}\', which is not registered`);t.set(n,i)}return t}qualityLadders(e){let t=new Map;for(let[n,s]of e)for(let[i,o]of Te(s)){if(o.type!=="quality"||o.stages===void 0)continue;let a=t.get(n);a||(a=new Map,t.set(n,a)),a.set(i,o.stages)}return t}toSchema(e){let t=new Map;for(let[n,s]of this.view(e?.aliases)){let i=Te(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(n,o)}return{properties:t}}save(){let e={};for(let[t,n]of this.scopes)n.kind==="owned"&&(e[t]=n.bag.save());for(let[t,n]of this.parked)e[t]=structuredClone(n);return e}load(e,t){t?.keepParked||(this.parked.clear(),this.parkedRefit.clear());let n=t?.refit===!0;for(let[s,i]of Object.entries(e)){let o=this.scopes.get(s);o?.kind==="owned"?this.note(s,o.bag.load(i,{refit:n})):o||(this.parked.set(s,structuredClone(i)),n?this.parkedRefit.add(s):this.parkedRefit.delete(s))}}saveFragment(){return{version:ye,scopes:this.save()}}loadFragment(e){if(e.version!==ye)throw new Error(`unsupported owned-state fragment version ${e.version} (supported: ${ye})`);this.load(e.scopes)}assertFree(e,t){let n=this.scopes.get(e);if(!n)return;let s=n.owner!==void 0?` by ${n.owner}`:"",i=t!==void 0?` (wanted by ${t})`:"";throw new Error(`scope \'@${e}\' is already registered${s}${i}`)}};function Te(r){return r.kind==="foreign"?[...r.decls.entries()]:r.bag.declarations().map(e=>[r.bag.normalise(e.name),e])}function _t(r){return r.kind==="foreign"?r.norm:e=>r.bag.normalise(e)}function T(r){if(r.default!==void 0)return r.default;switch(r.type){case"boolean":return!1;case"number":return 0;case"string":case"text":case"multiline":return"";case"enum":return r.values?.[0]??"";case"flags":return[];case"quality":return r.stages?.[0]??"";default:return!1}}var $e=[{token:"patter",engine:"Patterplay",means:"Patter\'s shared globals"},{token:"story",engine:"Storylet Engine",means:"the Storylet Engine\'s shared @story properties"}];function G(r){return r.ctx.host??{}}var Se={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(r,e){if(r.length!==2)throw new u("random(a, b) requires exactly 2 arguments");let t=G(e).nextRandom;if(!t)throw new u("random() called without a PRNG in context");let n=e.evaluate(r[0]),s=e.evaluate(r[1]);if(typeof n!="number"||typeof s!="number")throw new u("random(a, b) arguments must be numbers");if(!Number.isInteger(n)||!Number.isInteger(s))throw new u("random(a, b) arguments must be integers");let i=Math.min(n,s),o=Math.max(n,s);return Math.floor(t()*(o-i+1))+i}},check_flags:{minArgs:1,returnType:"boolean",flagDeltaArgs:!0,validate:Ge("check_flags"),eval(r,e){let t=je(r[0],e,"check_flags");for(let n=1;n<r.length;n++){let s=r[n];if(s.kind!=="flagdelta")throw new u("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:Ge("set_flags"),eval(r,e){let t=[...je(r[0],e,"set_flags")];for(let n=1;n<r.length;n++){let s=r[n];if(s.kind!=="flagdelta")throw new u("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:re("visits"),eval:(r,e)=>G(e).visits?.(ne(r,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:re("seen"),eval:(r,e)=>(G(e).visits?.(ne(r,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:re("patter_visits"),eval:(r,e)=>G(e).patterVisits?.(ne(r,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:re("patter_seen"),eval:(r,e)=>(G(e).patterVisits?.(ne(r,e,"patter_seen"))??0)>0}}},qn=$e.map(r=>r.token).filter(r=>r!=="patter"&&r!=="scene");function Ve(r,e){let t=r.replace(/^@/,"").split(".");return t.length===2&&e(t[0])?{scope:t[0],name:t[1].toLowerCase()}:{scope:"patter",name:t.join(".").toLowerCase()}}function ne(r,e,t){let n=e.evaluate(r[0]);if(typeof n!="string")throw new u(`${t}(id) requires a string node id`);return n}function re(r){return(e,t)=>{let n=e[0];n&&n.kind!=="string"&&t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${r}(id): the argument must be a string id literal (a scene / block / node id)`})}}function je(r,e,t){if(!r)throw new u(`${t}() requires at least one argument (the flags variable)`);let n=e.evaluate(r);if(Array.isArray(n))return n;if(n===!1||n===null||n===void 0)return[];throw new u(`${t}() first argument must be a flags property`)}function Ge(r){return(e,t)=>{if(e.length===0)return;let n=e[0];if(n.kind!=="scopedvar"){t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${r}(): first argument must be a flags property reference (@name or @scope.name)`});return}let s=t.schema.properties.get(n.scope)?.get(n.name);if(s&&s.type!=="flags"){let i=n.scope===t.defaultScope?n.name:`${n.scope}.${n.name}`;t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${r}(): \'@${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:`${r}(): 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:`${r}(): unknown flag \'${o.name}\'`,reference:o.name})}}}var Ht=/^@[A-Za-z0-9_.]+$/;function*Ut(r){let e="",t=0;for(;t<r.length;){let n=r[t];if(n==="{"&&r[t+1]==="{"){e+="{",t+=2;continue}if(n==="}"&&r[t+1]==="}"){e+="}",t+=2;continue}if(n==="{"){let s=r.indexOf("}",t+1);if(s!==-1){let i=r.slice(t,s+1),o=r.slice(t+1,s).trim();if(o.startsWith("@")){e&&(yield{kind:"text",value:e},e=""),yield{kind:"slot",raw:i,inner:o,ref:Ht.test(o)?o:void 0},t=s+1;continue}e+=i,t=s+1;continue}}e+=n,t+=1}e&&(yield{kind:"text",value:e})}function Wt(r){return Array.isArray(r)?r.join(", "):typeof r=="boolean"?r?"true":"false":String(r)}function Kt(r){return r===" "||r===" "||r===`\n`||r==="\\r"||r==="\\f"||r==="\\v"}function Jt(r){let e="",t=!1;for(let n of r){if(Kt(n)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=n}return e}function qe(r,e,t){if(e.length===0||r.indexOf(e)<0)return r;let n="",s=0,i=!1;for(;s<r.length;){if(r.startsWith(e,s)){let o=r.indexOf(t,s+e.length);if(o>=0){s=o+t.length,i=!0;continue}n+=r.slice(s);break}n+=r[s],s+=1}return i?Jt(n):r}function _e(r,e){if(r.indexOf("{")<0)return r;let t="";for(let n of Ut(r)){if(n.kind==="text"){t+=n.value;continue}if(!n.ref){t+=n.raw;continue}let s=e(n.ref);t+=s===void 0?"":Wt(s)}return t}function He(r){return r.toLowerCase().replace(/[\'\u2019]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function D(r,e){for(let t of r){e(t);let n=t.children;n&&D(n,e)}}function y(r){let e=r.gameId?.trim();return e||He(r.name)}function we(r){let e=new Map;for(let[t,n]of Object.entries(r))e.set(y(n),t);return e}function se(r,e,t){return(t??we(r)).get(e)??(Object.hasOwn(r,e)?e:void 0)}var O=.6;var V=1;var Qt=14,be=.5,ve=18,Ue=1.5;var zt=[[173,173,0],[12352,12543,2],[12784,12799,2],[13312,19903,3],[19968,40959,3],[44032,55203,2.5],[63744,64255,3],[65382,65439,2],[131072,201551,3]];function We(r,e,t){let n=typeof t=="number"&&Number.isFinite(t)&&t>0?t:V,s=0;for(let i of r??""){let o=i.codePointAt(0),a=1;for(let[c,l,d]of zt){if(o<c)break;if(o<=l){a=d;break}}s+=a}return Math.min(Math.max(s/(Qt*n),be),ve)}function ie(r){return`cast:${r}`}function oe(r){return`qualifier:${r}`}function Ke(r,e){return`speaker:${r}:${e}`}var Je="speaker:pattern",Qe="{name} ({qualifier})";function ze(r,e,t){return r.split("{name}").map(n=>n.split("{qualifier}").join(t)).join(e)}var xe={open:"[",close:"]"},Xe="SFX";var q=4;function _(r){let e=new Set,t=[];for(let n of r)e.has(n)||(e.add(n),t.push(n));return t}function ae(r){let e=new Map,t=(n,s)=>{let i=_([...s,...n.tags??[]]);if(e.set(n.id,i),n.type==="group"&&n.prompt&&e.set(n.prompt.id,_([...i,...n.prompt.tags??[]])),n.type==="group")for(let o of n.children)t(o,i);else for(let o of n.beats??[])e.set(o.id,_([...i,...o.tags??[]]))};for(let n of Object.values(r.scenes)){let s=_(n.tags??[]);e.set(n.id,s);for(let i of n.blocks){let o=_([...s,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var Ye=r=>r.kind==="line"||r.kind==="text",H=r=>typeof r=="number"&&Number.isFinite(r)?r:void 0;function Ze(r){let e=new Map,t=(i,o,a)=>{let c=i.kind==="gameEvent"?void 0:H(i.padAfter),l=c??o;a&&l<0&&(l=0),e.set(i.id,c!==void 0?{own:c,resolved:l}:{resolved:l})},n=(i,o)=>{let a=H(i.padAfterDefault)??o;if(i.type==="group"){i.prompt&&t(i.prompt,a,!1);for(let d of i.children)n(d,a);return}let c=i.beats??[],l=-1;c.forEach((d,g)=>{Ye(d)&&(l=g)}),c.forEach((d,g)=>{Ye(d)&&t(d,a,g===l)})},s=H(r.padAfterDefault)??O;for(let i of Object.values(r.scenes)){let o=H(i.padAfterDefault)??s;for(let a of i.blocks){let c=H(a.padAfterDefault)??o;for(let l of a.children)n(l,c)}}return e}var et=new WeakMap,tt=new WeakMap;function Xt(r){let e=tt.get(r);return e||(e=ae(r),tt.set(r,e)),e}var nt=new WeakMap;function Yt(r){let e=nt.get(r);return e||(e=Ze(r),nt.set(r,e)),e}var rt=new WeakMap;function Zt(r){let e=rt.get(r);if(e)return e;e=new Map;for(let t of Object.values(r.scenes))for(let n of t.blocks)D(n.children,s=>{if(s.type==="group"&&s.selector==="choice")for(let i of s.children)e.set(i.id,s.id)});return rt.set(r,e),e}var st=new WeakMap;function en(r){let e=st.get(r);if(e)return e;e=new Map;for(let t of Object.values(r.scenes))for(let n of t.blocks)D(n.children,s=>{if(s.type==="group"){s.prompt&&e.set(s.prompt.id,s.prompt);return}for(let i of s.beats??[])e.set(i.id,i)});return st.set(r,e),e}function b(r){if(r===void 0)return;let e={};for(let[t,n]of Object.entries(r))e[t]=Array.isArray(n)?[...n]:n;return e}function N(r,e){return r.tagIndex.get(e)?.slice()}var W="Patter",U=r=>r.replace(/%/g,"%25").replace(/\\//g,"%2F"),tn=r=>r.replace(/%2F/g,"/").replace(/%25/g,"%"),it=Symbol("ownsRegistry"),ot=Symbol("setupReported"),w={stage:r=>`patter/scene/${U(r)}`,flow:r=>`patter/flow/${U(r)}/`,flowGlobals:r=>`patter/flow/${U(r)}/patter`,flowScene:(r,e)=>`patter/flow/${U(r)}/scene/${U(e)}`},J=class{constructor(e){this.journal=e}journal},le=class r{host;defaultSeed;flowsById=new Map;allStrings;currentLocale;requestedLocale;sourceDebug;sceneGameIdToId=new Map;blockGameIdToId=new Map;creationOptions;engineLog=[];engineSeq=0;engineTraceHandlers=new Set;constructor(e,t={}){this.creationOptions=t;let n=[];for(let p of Object.keys(t))rn.has(p)||n.push({node:p,message:p==="world"?\'the engine option "world" has gone: bind the scope as hostScopes: { world }\':`"${p}" isn\'t an engine option, so it\'s ignored`});let s=e.strings;this.allStrings=s,this.requestedLocale=t.locale,this.currentLocale=ke(e,t.locale),this.currentLocale.problem&&n.push({node:t.locale,message:this.currentLocale.problem});let i=ut(s,this.currentLocale),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 p of e.cast??[])p.displayName&&l.set(p.name,p.displayName);let d=new Map;for(let p of e.qualifiers??[])p?.gameId&&d.set(p.gameId,p.name);let g=new Map;for(let p of e.cast??[])for(let[m,h]of Object.entries(p.qualifierLabels??{}))typeof h=="string"&&g.set(`${p.name}\\0${m}`,h);let f=e.speakerPattern??Qe;this.defaultSeed=(t.seed??2654435769)>>>0;let C=new Map,z=new Map,Pe=new Map;for(let[p,m]of Object.entries(e.scenes)){this.sceneGameIdToId.set(y(m),p);let h=new Map;for(let S of m.blocks)z.set(S.id,{sceneId:p}),Pe.set(S.id,S),h.set(y(S),S.id),D(S.children,k=>C.set(k.id,k));this.blockGameIdToId.set(p,h)}let Oe=e.properties??[],de=Oe.filter(p=>p.shared??!0).map(dt),Rt=Oe.filter(p=>!(p.shared??!0)).map(dt),Pt=new Set(de.map(p=>p.name.toLowerCase())),x=t.registry??new te,Ne=!t.registry||t[it]===!0,Ae=new E(de,{pathPrefix:"@patter."}),pe=[],X=[];try{x.mountOwned("patter",Ae,{owner:W}),X.push("patter");let p=new Set,m=e.scopeRegistry?.scopes??[];for(let[h,S]of Object.entries(t.hostScopes??{})){let k=m.find(Y=>Y.token===h);if(!k&&!(e.externalScopes??[]).includes(h)){let Y=m.find(Nt=>Nt.token.toLowerCase()===h.toLowerCase());n.push({node:h,message:Y?`hostScopes binds "${h}", which this bundle doesn\'t declare: it declares "${Y.token}", and a scope\'s token is case-sensitive`:`hostScopes binds "${h}", which this bundle doesn\'t declare`})}let Ot=(k?.declarations??[]).map(yt);x.defineForeign(h,S,Ot,{writable:k?.writable??!0,owner:W}),X.push(h),p.add(h)}for(let h of Ne?e.scopeRegistry?.scopes??[]:[]){if(p.has(h.token)||x.has(h.token))continue;let S=(h.declarations??[]).map(k=>an(k,h.writable));x.defineOwned(h.token,S,{owner:W}),X.push(h.token),pe.push(h.token)}}catch(p){for(let m of X)x.remove(m,{keep:!0});throw p}let Fe=new Map;for(let[p,m]of Object.entries(e.scenes)){let h=new Set((m.sceneProps??[]).filter(S=>S.shared??!1).map(S=>S.name.toLowerCase()));Fe.set(p,h)}if(this.host={logEnabled:t.log??!1,tracing:t.log??!1,emitEngine:(p,m,h)=>this.emitEngine(p,m,h),bundle:e,emitIds:c,strings:i,defaultStrings:o,castDisplay:l,qualifierDisplay:d,speakerLabels:g,speakerPattern:f,nodeIndex:C,blockIndex:z,blockById:Pe,sceneGameIdToId:this.sceneGameIdToId,blockGameIdToId:this.blockGameIdToId,tagIndex:Xt(e),padIndex:Yt(e),registry:x,ownsRegistry:Ne,patterBag:Ae,hostScopes:pe,patterSharedDecls:de,patterLocalDecls:Rt,patterSharedNames:Pt,sceneSharedNames:Fe,sharedVisits:new Map,qualityLadders:new Map,sharedSelectors:new Map,stageBags:new Map,journal:null,customRng:t.rng,onDryChoice:t.onDryChoice,steer:pt(t.steer,n),onError:t.onError??(p=>console.warn(p.kind==="setup"?`Patterplay: ${p.message}`:p.kind==="save"?`Patterplay: flow \'${p.flow}\': ${p.message}`:`Patterplay: ${p.kind} on ${p.node} in flow \'${p.flow}\' failed, played through: ${p.message}`)),reportRefits:()=>{let p=x.takeMisfits(m=>m==="patter"||m.startsWith("patter/")||pe.includes(m));if(p.length!==0)if(t.onRefit)t.onRefit(p);else for(let m of p)console.warn(`Patterplay: the save\'s ${m.scope}.${m.name} was ${JSON.stringify(m.value)}, which no longer fits its declaration; it is back at its default`)},replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??xe).open,captionClose:(e.closedCaptions??xe).close,captionCharacter:e.closedCaptions?.character||Xe,refSplitCache:new Map,refSplitRevision:x.revision},this.host.reportRefits(),t[ot]!==!0)for(let p of n)this.reportSetup(p.node,p.message)}reportSetup(e,t){this.host.onError({flow:"",kind:"setup",node:e,message:t}),this.host.tracing&&this.emitEngine("",{type:"diagnostic",kind:"setup",node:e,message:t})}get locale(){return this.currentLocale.locale}get locales(){let{default:e,included:t}=this.host.bundle.locales;return{default:e,included:[...t]}}get isSourceDebug(){return this.sourceDebug}get buildId(){return this.host.bundle.content?.hash??""}setLocale(e){this.requestedLocale=e,this.useLocale(ke(this.host.bundle,e)),this.currentLocale.problem&&this.reportSetup(e,this.currentLocale.problem)}useLocale(e){this.currentLocale=e,this.host.strings=ut(this.allStrings,e)}replaceStrings(e){this.allStrings=e.strings;let t=this.currentLocale.problem;this.useLocale(ke(e,this.requestedLocale)),this.host.defaultStrings=this.allStrings[this.host.bundle.locales.default]??{};let n=this.currentLocale.problem;n&&n!==t&&this.reportSetup(this.requestedLocale,n)}hotSwap(e){this.refuseInCheckpoint("hotSwap");let t=this.saveGame(),n=l=>(l.setClosedCaptions(this.host.captionsOn),l),s=this.requestedLocale,i=(l=!1)=>new r(e,{...this.creationOptions,...s!==void 0?{locale:s}:{},steer:this.host.steer,registry:this.host.registry,[it]:this.host.ownsRegistry,[ot]:l}),o=new Set(["patter",...this.host.hostScopes]),a=this.host.ownsRegistry?void 0:Object.fromEntries(Object.entries(this.host.registry.save()).filter(([l])=>o.has(l)||l.startsWith("patter/")));this.release(!0),a&&this.host.registry.load(a,{keepParked:!0,refit:!0});let c=i();try{return c.loadGame(t),n(c)}catch{c.release(!0);let l=this.host.ownsRegistry?t.registry:a;l&&this.host.registry.load(l,{keepParked:!0,refit:!0});let d=i(!0);for(let[g,f]of Object.entries(t.flows)){let C=f.cursor.currentSceneId;try{d.openFlow(g,C!==null?{scene:C}:{})}catch{}}return n(d)}}get closedCaptions(){return this.host.captionsOn}setClosedCaptions(e){this.host.captionsOn=e}setSteer(e){if(e==null){this.host.steer=void 0;return}let t=[];this.host.steer=pt(e,t,"setSteer was given something that isn\'t a steerer (an object with gate and pick methods), so the engine is left unsteered");for(let{node:n,message:s}of t)this.reportSetup(n,s)}openFlow(e,t={}){this.assertExternalScopes();let{sceneId:n,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 A(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(n,s),a}runFlow(e,t,n){let s=this.flowsById.get(e);if(!s)return this.openFlow(e,{scene:t,block:n}).advanceToStop().played;if(!s.goto(t,n))throw new Error(`runFlow: address not found: ${t}${n===void 0?"":` / ${n}`}`);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 n=Ee(this.host,e);if(n===void 0)throw new Error(`unknown scene: ${e}`);if(t===void 0)return{sceneId:n};let s=De(this.host,n,t);if(s===void 0)throw new Error(`unknown block: ${t}`);return{sceneId:n,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:De(this.host,e,t)}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?y(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?y(t):void 0}tagsForBeat(e){return N(this.host,e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?N(this.host,t):void 0)??[]}tagsForBlock(e,t){let n=this.resolveSceneRef(e),s=this.resolveBlockRef(n,t);return(s!=null?N(this.host,s):void 0)??[]}gameDataForScene(e){let t=this.resolveSceneRef(e),n=t!=null?this.host.bundle.scenes[t]:void 0;return b(n?.gameData)??{}}gameDataForBlock(e,t){let n=this.resolveBlockRef(this.resolveSceneRef(e),t),s=n!=null?this.host.blockById.get(n):void 0;return b(s?.gameData)??{}}extensionsForScene(e){let t=this.resolveSceneRef(e);return{...(t!=null?this.host.bundle.scenes[t]:void 0)?.extensions}}extensionsForBlock(e,t){let n=this.resolveBlockRef(this.resolveSceneRef(e),t);return{...(n!=null?this.host.blockById.get(n):void 0)?.extensions}}extensionsForSnippet(e){let t=this.host.nodeIndex.get(e);return t?.type==="snippet"?{...t.extensions}:{}}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),n=t!=null?this.host.bundle.scenes[t]:void 0;if(!n)return[];let s=new Set;for(let i of n.blocks)at(i.children,s);return[...s]}castForBlock(e,t){let n=this.resolveSceneRef(e),s=this.resolveBlockRef(n,t),i=s!=null?this.host.blockById.get(s):void 0;if(!i)return[];let o=new Set;return at(i.children,o),[...o]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...y(e)?{gameId:y(e)}:{},name:e.name,...ct(e.gameData),...I(e.extensions),...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...y(t)?{gameId:y(t)}:{},name:t.name,...ct(t.gameData),...I(t.extensions),...this.tagsField(t.id),children:t.children.map(n=>this.outlineNode(n))}))}))}getBeatSequence(){let e=[];for(let t of Object.values(this.host.bundle.scenes))for(let n of t.blocks)D(n.children,s=>{if(s.type==="snippet")for(let i of s.beats??[])e.push({sceneId:t.id,blockId:n.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=N(this.host,e.id),n={id:e.id,kind:e.kind};if(e.kind==="line"){if(e.character!==void 0){n.character=e.character;let i=this.host.defaultStrings[ie(e.character)]??this.host.castDisplay.get(e.character);i!==void 0&&(n.characterName=i)}if(e.direction!==void 0&&(n.direction=e.direction),e.qualifier!==void 0){n.qualifier=e.qualifier;let i=this.host.defaultStrings[oe(e.qualifier)]??this.host.qualifierDisplay.get(e.qualifier);i!==void 0&&(n.qualifierName=i)}let s=ce(this.host,e.character,e.qualifier,!0);s!==void 0&&(n.speakerLabel=s)}if(e.kind==="line"||e.kind==="text"){let s=this.host.padIndex.get(e.id);n.padAfter=s?.resolved??O,s?.own!==void 0&&(n.ownPadAfter=s.own);let i=this.host.defaultStrings[e.id];i!==void 0&&(n.text=i)}return e.gameData&&Object.keys(e.gameData).length&&(n.gameData=b(e.gameData)),e.extensions&&Object.keys(e.extensions).length&&(n.extensions=e.extensions),t&&t.length&&(n.tags=t),n}tagsField(e){let t=N(this.host,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,n]of this.host.stageBags)e.push({bag:n,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 J(e)}rollback(e){this.endCheckpoint(e);let t=e.journal.undo;for(let n=t.length-1;n>=0;n--)t[n]();r.forget(e.journal)}commit(e){this.endCheckpoint(e),r.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`)}captureFlow(e){let t=this.flowsById.get(e);if(!t)throw new Error(`no open flow \'${e}\' to capture`);return{version:q,...t.snapshot(),...ln(e,this.host.registry.save())}}restoreFlow(e,t){this.refuseInCheckpoint("restoreFlow");let n=t.version;if(n!==3&&n!==q)throw new Error(`unsupported flow state version: ${String(n)}`);let s=t.cursor;if(typeof s!="object"||s===null)throw new Error("malformed flow state: no cursor");if(this.flowsById.has(e))throw new Error(`a flow \'${e}\' is already open; close it before restoring another under that id`);this.assertExternalScopes();let i=w.flow(e);this.host.registry.discardParked(i),this.host.registry.load(cn(e,t),{keepParked:!0,refit:!0});let o=new A(e,this.host,this.defaultSeed);try{o.restore(t)}catch(a){throw o.close(),this.host.registry.discardParked(i),a}return this.flowsById.set(e,o),this.host.reportRefits(),o}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(w.stage(e));this.host.stageBags.clear(),this.host.registry.discardParked("patter/")}release(e){for(let n of this.flowsById.values())n.releaseBags(e),n.close();this.flowsById.clear();let t=this.host.registry;for(let n of this.host.stageBags.keys())t.remove(w.stage(n),{keep:e});this.host.stageBags.clear();for(let n of["patter",...this.host.hostScopes])t.has(n)&&t.remove(n,{keep:e});for(let n of Object.keys(this.creationOptions.hostScopes??{}))t.has(n)&&t.remove(n)}getProperty(e){let{scope:t,name:n}=this.splitShared(e);return this.host.registry.get(t,n)}setProperty(e,t){let{scope:n,name:s}=this.splitShared(e);mt(this.host,n,s,t,null);let i=this.host.journal?this.host.registry.get(n,s):void 0;this.host.registry.set(n,s,t,{host:!0}),this.host.journal&&i!==void 0&&this.host.journal.undo.push(()=>this.host.registry.set(n,s,i,{host:!0}))}stageIndex(e,t){return F(this.ladderOf(e),t)}compareStages(e,t,n){return B(this.ladderOf(e),t,n)}nextStage(e,t){return L(this.ladderOf(e),t)}ladderOf(e){let{scope:t,name:n}=this.splitShared(e),s=on(this.host,t,n);if(!s)throw new Error(`\'${e}\' is not a quality`);return s}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,n){for(let s of this.engineTraceHandlers)s(e,t);this.host.logEnabled&&this.engineLog.push({...t,flow:e,seq:this.engineSeq++,...n?{scene:n}:{}})}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:T(e),writable:e.writable??!0}))}splitShared(e){let t=St(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}saveGame(){let e={};for(let[t,n]of this.flowsById)e[t]=n.snapshot();return{version:q,...this.host.ownsRegistry?{registry:this.host.registry.save()}:{},sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:ft(this.host.sharedSelectors),flows:e}}loadGame(e){this.refuseInCheckpoint("loadGame");let t=e.version;if(t!==3&&t!==q)throw new Error(`unsupported save version: ${String(t)}`);let n=e.flows;if(typeof n!="object"||n===null||Array.isArray(n))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(w.stage(o),{keep:!0});this.host.stageBags.clear();let i=e.registry;i&&(this.host.ownsRegistry?s.load(i,{refit:!0}):s.load(i,{keepParked:!0,refit:!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 ht(e.sharedSelectors))this.host.sharedSelectors.set(o,a);for(let[o,a]of Object.entries(e.flows)){let c=new A(o,this.host,this.defaultSeed);c.restore(a),this.flowsById.set(o,c)}this.host.reportRefits()}},A=class{id;host;local;registered=new Set;rngState;started=!1;flowEnded=!1;dryChoice=null;ranDry=null;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 n=this.currentSceneId;if(n===null)return;let s=this.sceneBagFor(n,e);s&&s.set(e,t)}};evalCtx;ctxRevision=-1;registryQualities;flowLog=[];flowSeq=0;constructor(e,t,n){this.id=e,this.host=t,this.rngState=$(n),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(),n=this.evalCtx.scopes;for(let s of Object.keys(n))delete n[s];Object.assign(n,t.scopes),n.patter=this.patterResolver,n.scene=this.sceneResolver,this.registryQualities=t.qualities,this.ctxRevision=e.revision}return this.evalCtx}stagesFor(e,t){let n=t.toLowerCase();if(e==="patter")return K(this.host,"patter",()=>[...this.host.patterSharedDecls,...this.host.patterLocalDecls]).get(n);if(e==="scene"){let s=this.currentSceneId;return s==null?void 0:K(this.host,`scene/${s}`,()=>this.host.bundle.scenes[s]?.sceneProps).get(n)}return this.registryQualities?.(e,t)??K(this.host,`host/${e}`,()=>this.host.bundle.scopeRegistry?.scopes.find(s=>s.token===e)?.declarations).get(n)}begin(e,t){let n=this.host.bundle.start;if(e===void 0&&t===void 0&&n&&this.host.bundle.scenes[n.scene]&&(e=n.scene,n.block!==void 0&&this.host.blockIndex.get(n.block)?.sceneId===n.scene&&(t=n.block)),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(w.flow(this.id)),this.mountLocal(),this.selectors.clear(),this.visitCounts.clear(),this.stack=[],this.currentSceneId=null,this.flowEnded=!1,this.dryChoice=null,this.ranDry=null,this.activeSnippet=null,this.beatIndex=0,this.clearPending(),this.started=!0,t){let s=this.host.blockIndex.get(t);if(!s)throw new Error(`unknown block: ${t}`);this.enterSceneSetup(s.sceneId),this.stack=[{sceneId:s.sceneId,containerId:t,index:0}],this.enter(t)}else{let s=e??Object.keys(this.host.bundle.scenes)[0],i=s?this.host.bundle.scenes[s]:void 0;if(!i)throw new Error(s?`unknown scene: ${s}`:"no scenes in bundle");this.enterSceneSetup(s);let o=i.blocks[0];o&&(this.stack=[{sceneId:s,containerId:o.id,index:0}],this.enter(o.id))}this.settle()}reset(e,t){this.begin(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=[],this.dryChoice=null,this.ranDry=null,!0;let n=Ee(this.host,e);if(n===void 0)return!1;let s;return t!==void 0&&(s=De(this.host,n,t),s===void 0)?!1:this.started?(this.clearPending(),this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!1,this.dryChoice=null,this.ranDry=null,this.enterTarget(s??n,"jump"),this.settle(),!0):(this.begin(n,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:n,flowEnded:s,dryChoice:i,ranDry:o,currentSceneId:a,activeSnippet:c,beatIndex:l,pendingChoice:d,pendingPrompt:g,pendingPromptOwnerId:f}=this,C=this.stack.map(z=>({...z}));e.undo.push(()=>{Object.assign(this,{rngState:t,started:n,flowEnded:s,dryChoice:i,ranDry:o,currentSceneId:a,activeSnippet:c,beatIndex:l,pendingChoice:d,pendingPrompt:g,pendingPromptOwnerId:f,stack:C})})}get isClosed(){return this.closed}get currentScene(){return this.currentSceneId}advance(){if(this.closed)return{type:"end",reason:"ended"};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&&!this.activeSnippet&&!this.pendingChoice&&(this.flowEnded=!0),this.flowEnded?this.endResult():(this.dryChoice=null,this.pendingChoice?{type:"choice",groupId:this.pendingChoice.groupId,options:this.offer(this.pendingChoice)}:this.beatResult(this.activeSnippet.beats[this.beatIndex++]))}endResult(){if(this.dryChoice!==null){let e=this.dryChoice;this.dryChoice=null,this.ranDry=e,this.report({flow:this.id,kind:"dry-choice",node:e,message:`choice \'${e}\' ran dry (no option left to take, and no fallback) with nothing after it, so the flow ended there`})}return{type:"end",reason:this.ranDry!==null?"ran-dry":"ended"}}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 n=this.childrenOf(t.containerId);if(!n){this.stack.pop();continue}let s=t.index;for(;t.index<n.length&&!this.eligible(n[t.index],"run");)t.index++;if(this.host.tracing&&t.index!==s&&this.emit({type:"select",group:t.containerId,selector:"run",children:n.slice(s,t.index+1).map((i,o)=>({id:i.id,eligible:s+o===t.index})),picked:n[t.index]?.id??null}),t.index>=n.length){this.stack.pop();continue}this.enterChild(n[t.index++])}}listBags(){let e=[{bag:this.local,pathPrefix:`${this.id}/@patter.`}];for(let[t,n]of this.sceneBags)e.push({bag:n,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)}stepFor(e){let t=en(this.host.bundle).get(e);return t?this.beatResult(t):void 0}getChoices(){return this.pendingChoice?this.offer(this.pendingChoice):[]}offer(e){return e.options.map(t=>{let n=e.byId.get(t.id),s=this.promptFor(n);return e.shown.set(t.id,s),{id:t.id,prompt:s,eligible:t.eligible,gameData:b(t.gameData),...I(n.extensions)}})}choose(e){let t=this.pendingChoice;if(!t)throw new Error("no choice is pending");let n=t.options.find(a=>a.id===e);if(!n)throw new Error(`unknown choice option: ${e}`);if(!n.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,o=i?t.shown.has(e)?t.shown.get(e):this.promptFor(s):void 0;this.pendingPrompt=i&&o?{beat:i,shown:{...o}}:null,this.pendingPromptOwnerId=this.pendingPrompt?s.id:null,this.enterChild(s)}isEnded(){return this.flowEnded}getProperty(e){let{scope:t,name:n}=this.splitRef(e);return t==="patter"?this.patterResolver.get(n):t==="scene"?this.sceneResolver.get(n):this.host.registry.get(t,n)}setProperty(e,t){this.writeProperty(e,t,!0)}stageIndex(e,t){return F(this.ladderOf(e),t)}compareStages(e,t,n){return B(this.ladderOf(e),t,n)}nextStage(e,t){return L(this.ladderOf(e),t)}ladderOf(e){let{scope:t,name:n}=this.splitRef(e);this.context();let s=this.stagesFor(t,n);if(!s)throw new Error(`\'${e}\' is not a quality`);return s}writeProperty(e,t,n){let{scope:s,name:i}=this.splitRef(e);if(n){if(s==="scene"&&this.currentSceneId===null)throw new Error(`\'${e}\': the flow has not entered a scene yet`);mt(this.host,s,i,t,this.currentSceneId)}let 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,n?{host:!0}:void 0),o&&a!==void 0&&o.undo.push(()=>this.host.registry.set(s,i,a,{host:!0}))}}snapshot(){let e=Zt(this.host.bundle),t=this.activeSnippet?.beats?.[this.beatIndex]?.id;return{rngState:this.rngState,visits:Object.fromEntries(this.visitCounts),cursor:{flowEnded:this.flowEnded,...this.ranDry!==null?{ranDry:this.ranDry}:{},currentSceneId:this.currentSceneId,stack:this.stack.map(n=>{let s=this.childrenOf(n.containerId)?.[n.index],i=e.get(n.containerId);return{...n,...s?{nextId:s.id}:{},...i!==void 0?{choiceId:i}:{}}}),activeSnippetId:this.activeSnippet?.id??null,...t!==void 0?{beatId:t}:{},pendingChoice:this.pendingChoice?{groupId:this.pendingChoice.groupId,options:this.pendingChoice.options.map(n=>({id:n.id,eligible:n.eligible,...n.gameData!==void 0?{gameData:b(n.gameData)}:{}}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,...this.pendingPrompt?.shown?{pendingPrompt:nn(this.pendingPrompt.shown)}:{},selectors:ft(this.selectors)}}}restore(e){if(this.host.journal)throw new Error("a flow can\'t be restored while a checkpoint is open");let t=this.restoreCursor(e);this.releaseBags(!0),this.mountLocal();for(let n of new Set([this.currentSceneId,...this.stack.map(s=>s.sceneId)]))n!==null&&this.host.bundle.scenes[n]&&this.ensureSceneBags(n);t&&(this.report({flow:this.id,kind:"save",node:t.node,message:`the save\'s place has gone from this build: ${t.instead}`}),t.reoffer&&this.setupChoice(t.reoffer))}restoreCursor(e){this.rngState=$(e.rngState),this.visitCounts=new Map(Object.entries(e.visits??{}));let t=e.cursor;this.started=!0,this.flowEnded=t.flowEnded,this.dryChoice=null,this.ranDry=t.flowEnded&&typeof t.ranDry=="string"?t.ranDry:null,this.currentSceneId=t.currentSceneId;let n=null;this.stack=[];for(let s of t.stack){let{nextId:i,choiceId:o,...a}=s,c=this.childrenOf(a.containerId),l=!c&&o!==void 0?this.host.nodeIndex.get(o):void 0;if(l?.type==="group"&&l.selector==="choice"){n={node:t.activeSnippetId??t.pendingChoice?.groupId??a.containerId,instead:`option ${a.containerId} has gone, so choice ${l.id} is offered again`,reoffer:l};break}let d=i!==void 0?c?.findIndex(g=>g.id===i)??-1:-1;this.stack.push(d>=0?{...a,index:d}:{...a})}if(this.activeSnippet=null,this.beatIndex=0,!n?.reoffer&&t.activeSnippetId!==null){let s=this.host.nodeIndex.get(t.activeSnippetId);if(s&&s.type==="snippet"){let i=s.beats??[];if(this.activeSnippet=s,t.beatId!==void 0){let o=i.findIndex(a=>a.id===t.beatId);this.beatIndex=o>=0?o:i.length,o<0&&(n={node:t.activeSnippetId,instead:`beat ${t.beatId} has gone from snippet ${t.activeSnippetId}, so the snippet ends there`})}else this.beatIndex=t.beatIndex??i.length}else n={node:t.activeSnippetId,instead:`snippet ${t.activeSnippetId} has gone, so play carries on after it`}}if(this.selectors=ht(t.selectors),this.pendingChoice=null,!n?.reoffer&&t.pendingChoice!==null){let s=new Map,i=[];for(let o of t.pendingChoice.options){let a=this.host.nodeIndex.get(o.id);a&&(s.set(o.id,a),i.push({id:o.id,eligible:o.eligible,...o.gameData!==void 0?{gameData:o.gameData}:{}}))}if(i.length>0)this.pendingChoice={groupId:t.pendingChoice.groupId,options:i,byId:s,shown:new Map};else{let o=this.host.nodeIndex.get(t.pendingChoice.groupId);n=o?.type==="group"&&o.selector==="choice"?{node:t.pendingChoice.groupId,instead:`none of choice ${o.id}\'s options is left, so it\'s offered again`,reoffer:o}:{node:t.pendingChoice.groupId,instead:`choice ${t.pendingChoice.groupId} has gone, so play carries on after it`}}}if(this.pendingPrompt=null,this.pendingPromptOwnerId=n?.reoffer?null:t.pendingPromptOwnerId??null,this.pendingPromptOwnerId){let s=this.host.nodeIndex.get(this.pendingPromptOwnerId),i=s?this.authoredPromptOf(s):void 0,o=t.pendingPrompt,a=o?.kind==="line"&&o.speakerLabel===void 0?ce(this.host,o.character,o.qualifier):void 0;i?this.pendingPrompt={beat:i,...o?{shown:{...o,padAfter:o.padAfter??this.padOf(i.id),...a!==void 0?{speakerLabel:a}:{}}}:{}}:this.pendingPromptOwnerId=null}return n}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 n=this.selectChild(e);n&&this.enterChild(n)}childrenOf(e){let t=this.host.blockById.get(e);if(t)return t.children;let n=this.host.nodeIndex.get(e);if(n&&n.type==="group")return n.children}beginSnippet(e){this.runEffects(e.onEnter,e.id),this.activeSnippet=e,this.beatIndex=0}setupChoice(e){let t=[],n=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,"option"),c=o.secretUntilEligible===!0;!a&&c||(t.push({id:o.id,eligible:a,...o.gameData!==void 0?{gameData:o.gameData}:{}}),n.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:n,shown:new Map};return}let i=s.find(o=>this.eligible(o,"fallback"));if(i){this.enterChild(i);return}this.host.tracing&&this.emit({type:"dry",group:e.id}),this.host.onDryChoice?.(e.id),this.dryChoice=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 n,s,i=this.host.bundle.scenes[e];if(i){this.enterSceneSetup(e);let a=i.blocks[0];if(!a){t==="jump"&&(this.stack=[]);return}n=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),n=a.sceneId,s=e}this.enter(s);let o={sceneId:n,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.holds(c)})),n=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),a=null;if(n.length>0){let c=this.selectorState(e);switch(e.selector){case"branch":a=n[0];break;case"sequence":a=s==="shuffle"?this.pickShuffle(n,i,c):s==="specificity"?this.pickSpecificity(n,i,c):this.pickSequential(n,i,c);break;default:return null}}return this.host.steer?.pick&&(e.selector==="branch"||e.selector==="sequence")&&(a=this.steerPick(e,e.selector,t,a)),o(a)}steerPick(e,t,n,s){let i=s?.id??"",o=this.host.steer.pick({flow:this.id,group:e.id,selector:t,children:n.map(c=>({...c})),default:i});if(typeof o!="string")throw new Error(`steer: pick for ${e.id} answered ${String(o)}, not a child id or ""`);if(o===i)return s;let a=o===""?null:e.children.find(c=>c.id===o);if(a===void 0)throw new Error(`steer: pick for ${e.id} answered "${o}", which isn\'t one of its children`);return this.host.tracing&&this.emit({type:"steered",node:e.id,kind:"pick",default:i,answer:o}),a}pickSequential(e,t,n){let s=e.length,i=n.seq??0;return n.seq=i+1,t==="repeat"?e[i%s]:i<s?e[i]:t==="stick"?e[s-1]:null}pickShuffle(e,t,n){let s=e.length,i=t==="stick",o=()=>(i?e.slice(0,s-1):e).map(f=>f.id),a=new Set(e.map(f=>f.id));if(n.bag===void 0&&(n.bag=o()),!n.bag.some(f=>a.has(f))){if(t==="once")return null;if(i){let f=e[s-1];return n.last=f.id,f}if(n.bag=o(),n.bag.length===0)return null}let c=n.bag.filter(f=>a.has(f)),l=n.last!==void 0&&c.length>1?c.indexOf(n.last):-1,d=Math.floor(this.rng()*(l>=0?c.length-1:c.length));l>=0&&d>=l&&d++;let g=c[d];return n.bag.splice(n.bag.indexOf(g),1),n.last=g,e.find(f=>f.id===g)}pickSpecificity(e,t,n){let s=e;if(t!=="repeat"){n.bag===void 0&&(n.bag=e.map(d=>d.id));let l=new Set(n.bag);if(s=e.filter(d=>l.has(d.id)),s.length===0)return t==="stick"&&n.last!==void 0?e.find(d=>d.id===n.last)??null:null}let i=-1,a=s.map(l=>{let d=this.specScore(l);return d>i&&(i=d),{c:l,s:d}}).filter(l=>l.s===i).map(l=>l.c),c;if(a.length===1)c=a[0];else{let l=n.last!==void 0?a.findIndex(g=>g.id===n.last):-1,d=Math.floor(this.rng()*(l>=0?a.length-1:a.length));l>=0&&d>=l&&d++,c=a[d]}return t!=="repeat"&&(n.bag=n.bag.filter(l=>l!==c.id)),n.last=c.id,c}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0,e):0}matchedSpec(e,t,n){return Le(e,i=>{try{return gt(Z(i,this.context(),Se))}catch(o){return this.reportError("best-match",n.id,n.condition,o),!1}},{want:t})}selectorState(e){let t=e.shared?this.host.sharedSelectors:this.selectors,n=this.host.journal,s;if(n&&(s=e.shared?n.selectors:n.flowSelectors.get(this),s||(s=new Set,n.flowSelectors.set(this,s))),n&&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;n.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 n of e??[]){let s;try{s=this.evalExpr(n.value);let i=this.host.tracing?this.getProperty(n.target):void 0;this.writeProperty(n.target,s,!1),this.host.tracing&&this.emit({type:"write",target:n.target,value:s,...i!==void 0?{prev:i}:{}})}catch(i){this.reportError("effect",t,n.value,i)}}}holds(e){if(!e.condition)return!0;try{return gt(this.evalExpr(e.condition))}catch(t){return this.reportError("condition",e.id,e.condition,t),!1}}eligible(e,t){let n=this.holds(e),s=this.host.steer?.gate;if(!s||!e.condition)return n;let i=s({flow:this.id,node:e.id,where:t,source:e.condition.src??"",default:n});if(typeof i!="boolean")throw new Error(`steer: gate for ${e.id} answered ${String(i)}, not true or false`);return i!==n&&this.host.tracing&&this.emit({type:"steered",node:e.id,kind:"gate",default:n,answer:i}),i}reportError(e,t,n,s){let i=s instanceof Error?s.message:String(s),o=n?.src;this.report({flow:this.id,kind:e,node:t,...o?{source:o}:{},message:i})}report(e){this.host.onError(e),this.host.tracing&&this.emit({type:"diagnostic",kind:e.kind,node:e.node,...e.source?{source:e.source}:{},message:e.message})}evalExpr(e){return Z(this.conditionAst(e),this.context(),Se)}conditionAst(e){let t=et.get(e);return t||(t=R(e.ast),et.set(e,t)),t}enter(e){let t=this.visitCounts,n=t.get(e);t.set(e,(n??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(()=>{n===void 0?t.delete(e):t.set(e,n),i===void 0?s.delete(e):s.set(e,i)})}rng=()=>{if(this.host.customRng)return this.host.customRng();let e=fe(this.rngState),t=e.next();return this.rngState=e.state(),t};beatResult(e){let t=N(this.host,e.id),n=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:b(e.gameData),...I(e.extensions),...n};case"text":return{type:"text",id:e.id,text:this.interpolate(this.resolveString(e.id)),padAfter:this.padOf(e.id),...e.action?{action:!0}:{},...this.spokenOf(e),gameData:b(e.gameData),...I(e.extensions),...n};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,qualifier:c?void 0:e.qualifier,qualifierName:c?void 0:this.resolveQualifierName(e.qualifier),speakerLabel:c?void 0:ce(this.host,e.character,e.qualifier),padAfter:this.padOf(e.id),...this.spokenOf(e),gameData:b(e.gameData),...I(e.extensions),...n}}}}interpolate(e){return _e(e,t=>this.getProperty(t))}stripCaptions(e){return qe(e,this.host.captionOpen,this.host.captionClose)}captionLine(e){return this.host.captionsOn?e:this.stripCaptions(e)}spokenOf(e){let t=this.host.bundle.estimateSpeed??V,n=this.host.emitIds?void 0:this.host.defaultStrings[e.id];if(n===void 0)return{estimateSpeed:t};let s;return e.kind==="text"?s=this.interpolate(n):e.character===this.host.captionCharacter?s="":s=this.stripCaptions(this.host.bundle.voiced?n:this.interpolate(n)),{spokenText:s,spokenLocale:this.host.bundle.locales.default,estimateSpeed:t}}promptFor(e){let t=this.promptBeatOf(e);if(!t)return;let n=this.interpolate(this.resolveString(t.id)),s=this.padOf(t.id);return t.kind==="line"?{kind:"line",text:this.captionLine(n),character:t.character,characterName:this.resolveCharacterName(t.character),direction:t.direction,qualifier:t.qualifier,qualifierName:this.resolveQualifierName(t.qualifier),speakerLabel:ce(this.host,t.character,t.qualifier),padAfter:s}:{kind:"text",text:n,padAfter:s}}authoredPromptOf(e){return e.type==="group"?e.prompt:void 0}promptResult(e,t){let n=N(this.host,e.id),s=n&&n.length?{tags:n}:{};return t.kind==="text"?{type:"text",id:e.id,text:t.text,padAfter:this.padOf(e.id),...this.spokenOf(e),gameData:b(e.gameData),...I(e.extensions),...s}:{type:"line",id:e.id,text:t.text,character:t.character,characterName:t.characterName,direction:t.direction,qualifier:t.qualifier,qualifierName:t.qualifierName,speakerLabel:t.speakerLabel,padAfter:this.padOf(e.id),...this.spokenOf(e),gameData:b(e.gameData),...I(e.extensions),...s}}promptBeatOf(e){return e.type==="group"&&e.prompt?e.prompt:((e.type==="snippet"?e:this.firstTextSnippetIn(e.children))?.beats??[]).find(n=>n.kind==="line"||n.kind==="text")}firstTextSnippetIn(e){let t;return D(e,n=>{!t&&n.type==="snippet"&&(n.beats??[]).some(s=>s.kind==="line"||s.kind==="text")&&(t=n)}),t}resolveString(e){if(this.host.emitIds)return e;let t=this.host.strings[e];if(t!==void 0)return t;let n=this.host.defaultStrings[e];return n!==void 0?`<Untranslated: ${e}> ${n}`:e}resolveCharacterName(e){if(e===void 0||this.host.emitIds)return;let t=ie(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}padOf(e){return this.host.padIndex.get(e)?.resolved??O}resolveQualifierName(e){if(e===void 0||this.host.emitIds)return;let t=oe(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.qualifierDisplay.get(e)}splitRef(e){return St(this.host,e)}newLocal(){return new E(this.host.patterLocalDecls,{pathPrefix:"@patter."})}mountLocal(){this.local=this.newLocal();let e=w.flowGlobals(this.id);this.host.registry.mountOwned(e,this.local,{owner:W}),this.registered.add(e),this.host.reportRefits()}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,n=this.host.bundle.scenes[e]?.sceneProps??[],s=this.host.journal,i=!this.sceneBags.has(e)||!this.host.stageBags.has(e);if(!this.sceneBags.has(e)){let o=new E(n.filter(l=>!t.has(l.name.toLowerCase())),{pathPrefix:"@scene."}),a=w.flowScene(this.id,e),c=lt(this.host.registry,a,o,s!==null);this.registered.add(a),this.sceneBags.set(e,o),s&&s.undo.push(()=>{this.sceneBags.get(e)===o&&(this.host.registry.remove(a,c?{keep:!0}:void 0),this.registered.delete(a),this.sceneBags.delete(e))})}if(!this.host.stageBags.has(e)){let o=new E(n.filter(c=>t.has(c.name.toLowerCase())),{pathPrefix:"@scene."}),a=lt(this.host.registry,w.stage(e),o,s!==null);this.host.stageBags.set(e,o),s&&s.undo.push(()=>{this.host.stageBags.get(e)===o&&(this.host.registry.remove(w.stage(e),a?{keep:!0}:void 0),this.host.stageBags.delete(e))})}i&&this.host.reportRefits()}seedScene(e){let t=this.host.sceneSharedNames.get(e.id)??new Set;this.ensureSceneBags(e.id);for(let n of e.sceneProps??[]){if(!n.temporary)continue;let s=n.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,T(n))}}};function at(r,e){D(r,t=>{if(t.type==="group"){t.prompt?.kind==="line"&&t.prompt.character&&e.add(t.prompt.character);return}for(let n of t.beats??[])n.kind==="line"&&n.character&&e.add(n.character)})}function ce(r,e,t,n=!1){if(!e||r.emitIds)return;let s=c=>(n?void 0:r.strings[c])??r.defaultStrings[c],i=s(ie(e))??r.castDisplay.get(e)??e;if(t===void 0)return i;let o=r.speakerLabels.get(`${e}\\0${t}`);if(o!==void 0)return s(Ke(e,t))??o;let a=s(oe(t))??r.qualifierDisplay.get(t)??t;return ze(s(Je)??r.speakerPattern,i,a)}function ct(r){return r&&Object.keys(r).length?{gameData:b(r)}:{}}function I(r){return r&&Object.keys(r).length?{extensions:r}:{}}function nn(r){let e={kind:r.kind,text:r.text};return r.character!==void 0&&(e.character=r.character),r.characterName!==void 0&&(e.characterName=r.characterName),r.direction!==void 0&&(e.direction=r.direction),r.qualifier!==void 0&&(e.qualifier=r.qualifier),r.qualifierName!==void 0&&(e.qualifierName=r.qualifierName),r.speakerLabel!==void 0&&(e.speakerLabel=r.speakerLabel),typeof r.padAfter=="number"&&(e.padAfter=r.padAfter),e}function ft(r){let e={};for(let[t,n]of r){let s={};n.seq!==void 0&&(s.seq=n.seq),n.bag&&(s.bag=[...n.bag]),n.last!==void 0&&(s.last=n.last),e[t]=s}return e}function ht(r){let e=new Map;for(let[t,n]of Object.entries(r??{})){let s={};n.seq!==void 0&&(s.seq=n.seq),n.bag&&(s.bag=[...n.bag]),n.last!==void 0&&(s.last=n.last),e.set(t,s)}return e}function lt(r,e,t,n){let s=n?JSON.stringify(t.save()):"";return r.mountOwned(e,t,{owner:W}),n&&JSON.stringify(t.save())!==s}function dt(r){return{name:r.name,type:r.type,values:r.values,stages:r.stages,default:r.default}}var rn=new Set(["rng","seed","locale","hostScopes","registry","replayPromptOnChoose","closedCaptions","onDryChoice","steer","onError","onRefit","log"]);function pt(r,e,t=`the engine option "steer" isn\'t a steerer (an object with gate and pick methods), so it\'s ignored`){if(r==null)return;let n=r;if(typeof r=="object"&&(n.gate===void 0||typeof n.gate=="function")&&(n.pick===void 0||typeof n.pick=="function"))return r;e.push({node:"steer",message:t})}function ke(r,e){let t=r.locales.default;if(e===void 0)return{locale:t,table:t};if(r.localisation?.mode==="ids")return{locale:e,table:e};let n=[...new Set([t,...r.locales.included,...Object.keys(r.strings)])];if(n.includes(e))return{locale:e,table:e};let s=c=>c.toLowerCase().replace(/_/g,"-"),i=n.find(c=>s(c)===s(e));if(i!==void 0)return{locale:i,table:i,problem:`the locale "${e}" is spelled "${i}" in this bundle, so it\'s using "${i}"`};let o=s(e).split("-")[0],a=n.find(c=>s(c)===o);return a!==void 0?{locale:a,table:a,problem:`this bundle has no locale "${e}", so it\'s using its language, "${a}"`}:{locale:t,problem:`this bundle has no locale "${e}", so it\'s using the default, "${t}", with every string marked untranslated`}}function ut(r,e){return e.table!==void 0?r[e.table]??{}:{}}function mt(r,e,t,n,s){let i=c=>c?.find(l=>l.name.toLowerCase()===t),o;if(e==="patter")o=i(r.bundle.properties);else if(e==="scene")o=i(s!==null?r.bundle.scenes[s]?.sceneProps:void 0);else{let c=r.bundle.scopeRegistry?.scopes.find(l=>l.token===e);if(!c||c.declarations===void 0)return;o=i(c.declarations)}let a=`@${e}.${t}`;if(o===void 0)throw new Error(`no property at "${a}": the content declares no ${a}`);if(!j(o,n,{noneChosen:o.type==="enum"&&o.default===""}))throw new Error(`"${a}" takes ${sn(o)}; ${JSON.stringify(n)} doesn\'t fit`)}function sn(r){let e=t=>(t??[]).map(n=>JSON.stringify(n)).join(", ");switch(r.type){case"number":return"a number";case"boolean":return"true or false";case"enum":return`one of ${e(r.values)}`;case"flags":return r.values!==void 0&&r.values.length>0?`a list of flags from ${e(r.values)}`:"a list of flags";case"quality":return`one of its stages ${e(r.stages)}`;default:return"text"}}function K(r,e,t){let n=r.qualityLadders.get(e);if(!n){n=new Map;for(let s of t()??[]){let i=s.name.toLowerCase();s.type==="quality"&&s.stages&&!n.has(i)&&n.set(i,s.stages)}r.qualityLadders.set(e,n)}return n}function on(r,e,t){let n=t.toLowerCase();return e==="patter"?K(r,"patter",()=>[...r.patterSharedDecls,...r.patterLocalDecls]).get(n):r.registry.toEvalContext().qualities?.(e,t)??K(r,`host/${e}`,()=>r.bundle.scopeRegistry?.scopes.find(s=>s.token===e)?.declarations).get(n)}function yt(r){return{name:r.name,type:r.type,values:r.values,stages:r.stages,default:r.default,writable:r.writable}}function an(r,e){let t=yt(r),n=r.writable??e;return n===void 0?t:{...t,writable:n}}function Ee(r,e){return se(r.bundle.scenes,e,r.sceneGameIdToId)}function De(r,e,t){return r.blockGameIdToId.get(e)?.get(t)??(r.blockIndex.get(t)?.sceneId===e?t:void 0)}function St(r,e){r.refSplitRevision!==r.registry.revision&&(r.refSplitCache.clear(),r.refSplitRevision=r.registry.revision);let t=r.refSplitCache.get(e);return t||(t=Ve(e,n=>n==="scene"||r.registry.has(n)||(r.bundle.externalScopes?.includes(n)??!1)),r.refSplitCache.set(e,t)),t}function cn(r,e){let t={};e.scopes?.patter&&(t[w.flowGlobals(r)]=e.scopes.patter);for(let[n,s]of Object.entries(e.sceneBags??{}))t[w.flowScene(r,n)]=s;return t}function ln(r,e){let t={scopes:{},sceneBags:{}},n=w.flow(r);for(let[s,i]of Object.entries(e)){if(!s.startsWith(n))continue;let o=s.slice(n.length);o==="patter"?t.scopes.patter=i:o.startsWith("scene/")&&(t.sceneBags[tn(o.slice(6))]=i)}return t}function gt(r){return typeof r=="boolean"?r:typeof r=="number"?r!==0:typeof r=="string"?r!=="":r.length>0}var vt="1.0.0",dn=/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/;function Ie(r){let e=typeof r=="string"?dn.exec(r):null;return e?{core:[e[1],e[2],e[3]],pre:e[4]?e[4].split("."):[]}:null}function wt(r,e){return r=r.replace(/^0+(?=\\d)/,""),e=e.replace(/^0+(?=\\d)/,""),r.length!==e.length?r.length<e.length?-1:1:r===e?0:r<e?-1:1}function bt(r,e){for(let t=0;t<3;t++){let n=wt(r.core[t],e.core[t]);if(n)return n}if(!r.pre.length||!e.pre.length)return e.pre.length-r.pre.length;for(let t=0;t<Math.min(r.pre.length,e.pre.length);t++){let n=r.pre[t],s=e.pre[t];if(n===s)continue;let i=/^\\d+$/.test(n),o=/^\\d+$/.test(s);if(i&&o){let a=wt(n,s);if(a)return a;continue}return i!==o?i?-1:1:n<s?-1:1}return r.pre.length-e.pre.length}function xt(r,e,t){let n=Ie(r),s=Ie(e),i=Ie(t);return!n||!s||!i?!1:bt(n,s)>=0&&bt(n,i)<0}var pn=(r,e)=>r.shared??e;function Ce(r,e){return{name:r.name,type:r.type,hasDefault:r.default!==void 0,...r.default!==void 0?{default:r.default}:{},shared:pn(r,e)}}function un(r){return{name:r.name,type:r.type,hasDefault:r.default!==void 0,...r.values?{values:[...r.values]}:{},...r.purpose?{purpose:r.purpose}:{}}}function gn(r,e){e.blocks++;let t=[...r.children];for(;t.length;){let n=t.pop();if(n.type==="group"){e.groups++,n.prompt&&e.prompts++,t.push(...n.children);continue}e.snippets++;for(let s of n.beats??[])e.beats++,s.kind==="gameEvent"&&e.gameEvents++}}function kt(r){let e={scenes:0,blocks:0,groups:0,snippets:0,beats:0,prompts:0,gameEvents:0,cast:r.cast?.length??0},t=[],n=[];for(let o of Object.values(r.scenes)){e.scenes++;let a=y(o);t.push({gameId:a,name:o.name,blocks:o.blocks.map(c=>({gameId:y(c),name:c.name}))});for(let c of o.blocks)gn(c,e);o.sceneProps?.length&&n.push({gameId:a,properties:o.sceneProps.map(c=>Ce(c,!1))})}let s=(r.scopeRegistry?.scopes??[]).map(o=>({token:o.token,writable:o.writable??!0,opaque:o.declarations===void 0,properties:(o.declarations??[]).map(a=>Ce(a,!0))})),i=Object.entries(r.gameDataFields??{}).filter(([,o])=>(o?.length??0)>0).map(([o,a])=>({kind:o,fields:(a??[]).map(un)}));return{identity:{schema:r.schema,project:r.content.project,...r.content.version!==void 0?{version:r.content.version}:{},...r.content.hash!==void 0?{hash:r.content.hash}:{},...r.content.structureHash!==void 0?{structureHash:r.content.structureHash}:{},voiced:r.voiced,defaultLocale:r.locales.default,locales:[...r.locales.included],localisation:r.localisation?.mode??"embedded",sourceDebug:r.localisation?.sourceDebug??!1},addresses:t,hostScopes:s,properties:{patter:(r.properties??[]).map(o=>Ce(o,!0)),scene:n},gameData:i,counts:e}}var Q=(r,e)=>Object.prototype.hasOwnProperty.call(r,e);function Et(r,e){return r.gameDataFields?.[e]??[]}function Re(r,e,t){return e&&Q(e,t)?e[t]:r.find(n=>n.name===t)?.default}function Dt(r,e){let t={};for(let n of r){let s=Re(r,e,n.name);s!==void 0&&(t[n.name]=s)}for(let[n,s]of Object.entries(e??{}))Q(t,n)||(t[n]=s);return t}function It(r,e,t){let n=r.extensions!==void 0&&Q(r.extensions,e)?r.extensions[e]:void 0;return n!==void 0&&Q(n.fields,t)?n.fields[t]??[]:[]}function Ct(r,e,t=""){let n=o=>({...o?.extensions??{}}),s=Object.values(r.scenes??{}),i=o=>(Q(r.scenes??{},o)?r.scenes[o]:void 0)??s.find(a=>y(a)===o);switch(e){case"project":{let o={};for(let[a,c]of Object.entries(r.extensions??{}))c.project!==void 0&&(o[a]=c.project);return o}case"scene":return n(i(t));case"block":{let o=t.indexOf("/");if(o<0)return{};let a=i(t.slice(0,o))?.blocks??[],c=t.slice(o+1);return n(a.find(l=>l.id===c)??a.find(l=>y(l)===c))}case"snippet":case"option":case"line":case"text":case"gameEvent":{let o,a=(c,l)=>{for(let d of c??[]){if(o!==void 0)return;if(d.type==="group"){if(l&&d.id===t&&e==="option"){o=d;return}if(l&&d.prompt?.id===t&&d.prompt.kind===e){o=d.prompt;return}a(d.children??[],d.selector==="choice");continue}if(d.id===t&&e==="snippet"){o=d;return}let g=(d.beats??[]).find(f=>f.id===t);if(g!==void 0){g.kind===e&&(o=g);return}}};for(let c of s)for(let l of c.blocks??[])o===void 0&&a(l.children??[],!1);return n(o)}default:return{}}}return Mt(fn);})();\n';
|
|
2709
|
+
var PLAYABLE_RUNTIME_JS = 'var Patterplay=(()=>{var ue=Object.defineProperty;var At=Object.getOwnPropertyDescriptor;var Ft=Object.getOwnPropertyNames;var Bt=Object.prototype.hasOwnProperty;var Tt=(r,e)=>{for(var t in e)ue(r,t,{get:e[t],enumerable:!0})},Lt=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Ft(e))!Bt.call(r,s)&&s!==t&&ue(r,s,{get:()=>e[s],enumerable:!(n=At(e,s))||n.enumerable});return r};var Mt=r=>Lt(ue({},"__esModule",{value:!0}),r);var hn={};Tt(hn,{Checkpoint:()=>J,DEFAULT_ESTIMATE_SPEED:()=>V,DEFAULT_PAD_AFTER:()=>O,Engine:()=>le,Flow:()=>A,LINE_DURATION_MAX:()=>xe,LINE_DURATION_MIN:()=>be,PATTERPLAY_VERSION:()=>xt,SUBTITLE_READING_MIN:()=>Ue,buildTagIndex:()=>ae,compareStages:()=>B,describeBundle:()=>kt,effectiveGameData:()=>Dt,estimateLineDuration:()=>We,extensionDecls:()=>It,extensionsOf:()=>Ct,gameDataFields:()=>Et,gameDataValue:()=>Re,nextStage:()=>T,resolveSceneRef:()=>se,sceneAddressIndex:()=>we,stageIndex:()=>F,versionInRange:()=>vt});function M(r,e){return r!==void 0&&Object.prototype.hasOwnProperty.call(r,e)?r[e]:void 0}function P(r){switch(r[0]){case"b":return{kind:"bool",value:r[1]};case"n":return{kind:"number",value:r[1]};case"s":return{kind:"string",value:r[1]};case"sv":return{kind:"scopedvar",scope:r[1],name:r[2]};case"u":return{kind:"unary",op:r[1],operand:P(r[2])};case"bin":return{kind:"binary",op:r[1],left:P(r[2]),right:P(r[3])};case"call":{let e=r.slice(2).map(P);return{kind:"call",name:r[1],args:e}}case"fd":return{kind:"flagdelta",sign:r[1],name:r[2]}}}var u=class extends Error{constructor(e){super(e),this.name="EvalError"}};function Z(r,e,t){let n=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=M(e.scopes,i.scope);if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):M(o,i.name);if(a===void 0){if(n.get(i.scope)==="throw")throw new u(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{if(i.name==="advance"&&!M(t.functions,i.name)){let a=i.args[0];if(i.args.length!==1||a===void 0)throw new u(`advance() takes exactly 1 argument, got ${i.args.length}`);let c=ge(a,e);if(c===void 0)throw new u("advance() needs a quality reference (@scope.name of a quality property)");let l=x(s(a),c,"advance");return c[Math.min(l+1,c.length-1)]}let o=M(t.functions,i.name);if(!o)throw new u(`unknown function \'${i.name}\'`);return o.eval(i.args,{evaluate:s,ctx:e})}case"flagdelta":throw new u("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 u(`\'not\' requires a boolean operand, got ${typeof a}`);return!a}let o=s(i.operand);if(typeof o!="number")throw new u(`unary \'-\' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let g=s(i.left);if(typeof g!="boolean")throw new u(`\'and\' requires boolean operands, left is ${typeof g}`);if(!g)return!1;let f=s(i.right);if(typeof f!="boolean")throw new u(`\'and\' requires boolean operands, right is ${typeof f}`);return f}if(i.op==="or"){let g=s(i.left);if(typeof g!="boolean")throw new u(`\'or\' requires boolean operands, left is ${typeof g}`);if(g)return!0;let f=s(i.right);if(typeof f!="boolean")throw new u(`\'or\' requires boolean operands, right is ${typeof f}`);return f}let o=s(i.left),a=s(i.right),c=ge(i.left,e),l=ge(i.right,e),d=c??l;if(d!==void 0){if(c&&l&&!$t(c,l)&&(i.op===">"||i.op===">="||i.op==="<"||i.op==="<="))throw new u(`\'${i.op}\' compares two different qualities, whose stage orders are unrelated`);switch(i.op){case">":return x(o,d,">")>x(a,d,">");case">=":return x(o,d,">=")>=x(a,d,">=");case"<":return x(o,d,"<")<x(a,d,"<");case"<=":return x(o,d,"<=")<=x(a,d,"<=");case"+":case"-":case"*":case"/":throw new u(`\'${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 Be(o,a);case"!=":return!Be(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=="string"||typeof a=="string")throw new u(jt);return E(o,a,"+"),o+a;case"-":return E(o,a,"-"),o-a;case"*":return E(o,a,"*"),o*a;case"/":if(E(o,a,"/"),a===0)throw new u("division by zero");return o/a}}}};return s(r)}function Be(r,e){if(Array.isArray(r)||Array.isArray(e)){if(!Array.isArray(r)||!Array.isArray(e)||r.length!==e.length)return!1;let t=[...r].sort(),n=[...e].sort();for(let s=0;s<t.length;s++)if(t[s]!==n[s])return!1;return!0}return r===e}var jt="\'+\' cannot join text: put the value into the text itself, so it can be translated";function E(r,e,t){if(typeof r!="number"||typeof e!="number")throw new u(`\'${t}\' requires numeric operands, got ${typeof r} and ${typeof e}`)}function ge(r,e){if(!(r.kind!=="scopedvar"||e.qualities===void 0))return e.qualities(r.scope,r.name)}function x(r,e,t){if(typeof r!="string")throw new u(`\'${t}\' on a quality compares stages, got ${typeof r}`);let n=e.indexOf(r);if(n<0)throw new u(`"${r}" is not a stage of this quality (stages: ${e.join(", ")})`);return n}var $t=(r,e)=>r.length===e.length&&r.every((t,n)=>t===e[n]);function j(r){if(Number.isNaN(r)||!Number.isFinite(r))return 0;let e=Math.trunc(r)%4294967296;return e<0?e+4294967296:e}function fe(r){let e=j(r);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 me=r=>Array.isArray(r)?r:r.stages??[],Gt=r=>Array.isArray(r)?"flags":r==null?"nothing":typeof r;function F(r,e){return typeof e=="string"?me(r).indexOf(e):-1}function he(r,e){if(typeof e!="string")throw new u(`a stage is a name, got ${Gt(e)}`);let t=r.indexOf(e);if(t<0)throw new u(`"${e}" is not a stage of this quality (stages: ${r.join(", ")})`);return t}function B(r,e,t){let n=me(r),s=he(n,e)-he(n,t);return s<0?-1:s>0?1:0}function T(r,e){let t=me(r);return t[Math.min(he(t,e)+1,t.length-1)]}function $(r,e,t){switch(r.type){case"boolean":return typeof e=="boolean";case"number":return typeof e=="number";case"string":case"text":case"multiline":return typeof e=="string";case"enum":return typeof e!="string"?!1:e===""&&t?.noneChosen?!0:!Array.isArray(r.values)||r.values.includes(e);case"flags":return Array.isArray(e)&&e.every(n=>typeof n=="string"&&(!Array.isArray(r.values)||r.values.includes(n)));case"quality":return typeof e=="string"&&(!Array.isArray(r.stages)||r.stages.includes(e));default:return!0}}var Vt={name:"check_flags",count:r=>Math.max(1,r.args.length-1)},_t=[Vt];function Te(r,e,t){let n=t?.countingCalls??_t;return ee(r,t?.want??!0,e,n)}function ee(r,e,t,n){if(r.kind==="binary"&&(r.op==="and"||r.op==="or")){let s=ee(r.left,e,t,n),i=ee(r.right,e,t,n);return r.op==="and"===e?s>0&&i>0?s+i:0:Math.max(s,i)}if(r.kind==="unary"&&r.op==="not")return ee(r.operand,!e,t,n);if(r.kind==="call"){let s=n.find(i=>i.name===r.name);if(s){let i=s.count(r),o=t(r);return e?o?i:0:o?0:1}}return t(r)===e?1:0}var D=class r{values=Object.create(null);decls=new Map;subscribers=new Set;auditors=new Set;norm;pathPrefix;constructor(e=[],t){this.norm=t?.normalise??(n=>n.toLowerCase()),this.pathPrefix=t?.pathPrefix??"",this.seed(e)}seed(e){for(let t of e){let n=this.norm(t.name);this.decls.set(n,t),this.values[n]=structuredClone(t.default??L(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,n){let s=this.norm(e);if(!n?.host&&!this.writable(s))throw new Error(`\'${e}\' is read-only`);let i={name:s,prev:this.values[s],next:t,silent:n?.silent??!1,reason:n?.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])=>Me(t,this.get(e),void 0,e,this.pathPrefix))}declarations(){return[...this.decls.values()]}clone(){let e=new r([],{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,t){let n=new Map;for(let[i,o]of Object.entries(e)){let a=this.norm(i);this.values[a]=structuredClone(o),n.set(a,o)}let s=[];if(!t?.refit)return s;for(let[i,o]of this.decls){if(!n.has(i))continue;let a=n.get(i);$(o,a,{noneChosen:o.type==="enum"&&o.default===""})||(this.values[i]=structuredClone(L(o)),s.push({name:i,value:a}))}return s}};function Me(r,e,t,n,s=""){let i=n??r.name.toLowerCase();return{name:i,path:s+i,type:r.type,value:e,default:r.default??L(r),...r.values!==void 0?{values:r.values}:{},...r.stages!==void 0?{stages:r.stages}:{},writable:t??r.writable??!0}}var qt=r=>r.toLowerCase(),ye=1,te=class{scopes=new Map;parked=new Map;parkedRefit=new Set;misfits=[];rev=0;get revision(){return this.rev}defineOwned(e,t,n){let s=typeof n=="string"?{pathPrefix:n}:n??{},i=new D(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,n){this.assertFree(e,n?.owner),this.scopes.set(e,{kind:"owned",bag:t,...n?.owner!==void 0?{owner:n.owner}:{}}),this.rev++;let s=this.parked.get(e);return s&&(this.note(e,t.load(s,{refit:this.parkedRefit.has(e)})),this.parked.delete(e),this.parkedRefit.delete(e)),this}remove(e,t){let n=this.scopes.get(e);if(!n)throw new Error(`unknown scope \'@${e}\'`);return t?.keep&&n.kind==="owned"&&(this.parked.set(e,n.bag.save()),this.parkedRefit.delete(e)),this.scopes.delete(e),this.rev++,this}discardParked(e){if(e===void 0)this.parked.clear(),this.parkedRefit.clear();else for(let t of[...this.parked.keys()])t.startsWith(e)&&(this.parked.delete(t),this.parkedRefit.delete(t));return this}takeMisfits(e){if(!e){let n=this.misfits;return this.misfits=[],n}let t=this.misfits.filter(n=>e(n.scope));return this.misfits=this.misfits.filter(n=>!e(n.scope)),t}note(e,t){for(let n of t)this.misfits.push({scope:e,name:n.name,value:n.value})}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,n=[],s=!0){let i=typeof s=="boolean"?{writable:s}:s;this.assertFree(e,i.owner);let o=i.normalise??qt,a=new Map;for(let c of n)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 n=this.scopes.get(e);if(n)return n.kind==="owned"?n.bag.get(t):n.resolver.get(n.norm(t))}set(e,t,n,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,n,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,n)}foreignWritable(e,t){return e.resolver.set?e.decls.get(t)?.writable??e.scopeWritable:!1}listProperties(){let e=[];for(let[t,n]of this.scopes){let s=n.owner!==void 0?{owner:n.owner}:{};if(n.kind==="owned")for(let i of n.bag.rows())e.push({scope:t,...s,...i});else for(let[i,o]of n.decls)e.push({scope:t,...s,...Me(o,n.resolver.get(i),this.foreignWritable(n,i),i,`${t}.`)})}return e}toEvalContext(e,t){let n=this.view(t?.aliases),s={};for(let[o,a]of n)s[o]=a.kind==="owned"?a.bag.values:a.resolver;let i=this.qualityLadders(n);return i.size===0?{scopes:s,host:e}:{scopes:s,host:e,qualities:(o,a)=>{let c=n.get(o);return c?i.get(o)?.get(Ht(c)(a)):void 0}}}view(e){let t=new Map(this.scopes);for(let[n,s]of Object.entries(e??{})){let i=this.scopes.get(s);if(!i)throw new Error(`alias \'@${n}\' names \'${s}\', which is not registered`);t.set(n,i)}return t}qualityLadders(e){let t=new Map;for(let[n,s]of e)for(let[i,o]of Le(s)){if(o.type!=="quality"||o.stages===void 0)continue;let a=t.get(n);a||(a=new Map,t.set(n,a)),a.set(i,o.stages)}return t}toSchema(e){let t=new Map;for(let[n,s]of this.view(e?.aliases)){let i=Le(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(n,o)}return{properties:t}}save(){let e={};for(let[t,n]of this.scopes)n.kind==="owned"&&(e[t]=n.bag.save());for(let[t,n]of this.parked)e[t]=structuredClone(n);return e}load(e,t){t?.keepParked||(this.parked.clear(),this.parkedRefit.clear());let n=t?.refit===!0;for(let[s,i]of Object.entries(e)){let o=this.scopes.get(s);o?.kind==="owned"?this.note(s,o.bag.load(i,{refit:n})):o||(this.parked.set(s,structuredClone(i)),n?this.parkedRefit.add(s):this.parkedRefit.delete(s))}}saveFragment(){return{version:ye,scopes:this.save()}}loadFragment(e){if(e.version!==ye)throw new Error(`unsupported owned-state fragment version ${e.version} (supported: ${ye})`);this.load(e.scopes)}assertFree(e,t){let n=this.scopes.get(e);if(!n)return;let s=n.owner!==void 0?` by ${n.owner}`:"",i=t!==void 0?` (wanted by ${t})`:"";throw new Error(`scope \'@${e}\' is already registered${s}${i}`)}};function Le(r){return r.kind==="foreign"?[...r.decls.entries()]:r.bag.declarations().map(e=>[r.bag.normalise(e.name),e])}function Ht(r){return r.kind==="foreign"?r.norm:e=>r.bag.normalise(e)}function L(r){if(r.default!==void 0)return r.default;switch(r.type){case"boolean":return!1;case"number":return 0;case"string":case"text":case"multiline":return"";case"enum":return r.values?.[0]??"";case"flags":return[];case"quality":return r.stages?.[0]??"";default:return!1}}var je=[{token:"patter",engine:"Patterplay",means:"Patter\'s shared globals"},{token:"story",engine:"Storylet Engine",means:"the Storylet Engine\'s shared @story properties"}];function G(r){return r.ctx.host??{}}var Se={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(r,e){if(r.length!==2)throw new u("random(a, b) requires exactly 2 arguments");let t=G(e).nextRandom;if(!t)throw new u("random() called without a PRNG in context");let n=e.evaluate(r[0]),s=e.evaluate(r[1]);if(typeof n!="number"||typeof s!="number")throw new u("random(a, b) arguments must be numbers");if(!Number.isInteger(n)||!Number.isInteger(s))throw new u("random(a, b) arguments must be integers");let i=Math.min(n,s),o=Math.max(n,s);return Math.floor(t()*(o-i+1))+i}},check_flags:{minArgs:1,returnType:"boolean",flagDeltaArgs:!0,validate:Ge("check_flags"),eval(r,e){let t=$e(r[0],e,"check_flags");for(let n=1;n<r.length;n++){let s=r[n];if(s.kind!=="flagdelta")throw new u("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:Ge("set_flags"),eval(r,e){let t=[...$e(r[0],e,"set_flags")];for(let n=1;n<r.length;n++){let s=r[n];if(s.kind!=="flagdelta")throw new u("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:re("visits"),eval:(r,e)=>G(e).visits?.(ne(r,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:re("seen"),eval:(r,e)=>(G(e).visits?.(ne(r,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:re("patter_visits"),eval:(r,e)=>G(e).patterVisits?.(ne(r,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:re("patter_seen"),eval:(r,e)=>(G(e).patterVisits?.(ne(r,e,"patter_seen"))??0)>0}}},qn=je.map(r=>r.token).filter(r=>r!=="patter"&&r!=="scene");function Ve(r,e){let t=r.replace(/^@/,"").split(".");return t.length===2&&e(t[0])?{scope:t[0],name:t[1].toLowerCase()}:{scope:"patter",name:t.join(".").toLowerCase()}}function ne(r,e,t){let n=e.evaluate(r[0]);if(typeof n!="string")throw new u(`${t}(id) requires a string node id`);return n}function re(r){return(e,t)=>{let n=e[0];n&&n.kind!=="string"&&t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${r}(id): the argument must be a string id literal (a scene / block / node id)`})}}function $e(r,e,t){if(!r)throw new u(`${t}() requires at least one argument (the flags variable)`);let n=e.evaluate(r);if(Array.isArray(n))return n;if(n===!1||n===null||n===void 0)return[];throw new u(`${t}() first argument must be a flags property`)}function Ge(r){return(e,t)=>{if(e.length===0)return;let n=e[0];if(n.kind!=="scopedvar"){t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${r}(): first argument must be a flags property reference (@name or @scope.name)`});return}let s=t.schema.properties.get(n.scope)?.get(n.name);if(s&&s.type!=="flags"){let i=n.scope===t.defaultScope?n.name:`${n.scope}.${n.name}`;t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${r}(): \'@${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:`${r}(): 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:`${r}(): unknown flag \'${o.name}\'`,reference:o.name})}}}var Ut=/^@[A-Za-z0-9_.]+$/;function*Wt(r){let e="",t=0;for(;t<r.length;){let n=r[t];if(n==="{"&&r[t+1]==="{"){e+="{",t+=2;continue}if(n==="}"&&r[t+1]==="}"){e+="}",t+=2;continue}if(n==="{"){let s=r.indexOf("}",t+1);if(s!==-1){let i=r.slice(t,s+1),o=r.slice(t+1,s).trim();if(o.startsWith("@")){e&&(yield{kind:"text",value:e},e=""),yield{kind:"slot",raw:i,inner:o,ref:Ut.test(o)?o:void 0},t=s+1;continue}e+=i,t=s+1;continue}}e+=n,t+=1}e&&(yield{kind:"text",value:e})}function Kt(r){return Array.isArray(r)?r.join(", "):typeof r=="boolean"?r?"true":"false":String(r)}function Jt(r){return r===" "||r===" "||r===`\n`||r==="\\r"||r==="\\f"||r==="\\v"}function Qt(r){let e="",t=!1;for(let n of r){if(Jt(n)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=n}return e}function _e(r,e,t){if(e.length===0||r.indexOf(e)<0)return r;let n="",s=0,i=!1;for(;s<r.length;){if(r.startsWith(e,s)){let o=r.indexOf(t,s+e.length);if(o>=0){s=o+t.length,i=!0;continue}n+=r.slice(s);break}n+=r[s],s+=1}return i?Qt(n):r}function qe(r,e){if(r.indexOf("{")<0)return r;let t="";for(let n of Wt(r)){if(n.kind==="text"){t+=n.value;continue}if(!n.ref){t+=n.raw;continue}let s=e(n.ref);t+=s===void 0?"":Kt(s)}return t}function He(r){return r.toLowerCase().replace(/[\'\u2019]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function I(r,e){for(let t of r){e(t);let n=t.children;n&&I(n,e)}}function y(r){let e=r.gameId?.trim();return e||He(r.name)}function we(r){let e=new Map;for(let[t,n]of Object.entries(r))e.set(y(n),t);return e}function se(r,e,t){return(t??we(r)).get(e)??(Object.hasOwn(r,e)?e:void 0)}var O=.6;var V=1;var zt=14,be=.5,xe=18,Ue=1.5;var Xt=[[173,173,0],[12352,12543,2],[12784,12799,2],[13312,19903,3],[19968,40959,3],[44032,55203,2.5],[63744,64255,3],[65382,65439,2],[131072,201551,3]];function We(r,e,t){let n=typeof t=="number"&&Number.isFinite(t)&&t>0?t:V,s=0;for(let i of r??""){let o=i.codePointAt(0),a=1;for(let[c,l,d]of Xt){if(o<c)break;if(o<=l){a=d;break}}s+=a}return Math.min(Math.max(s/(zt*n),be),xe)}function ie(r){return`cast:${r}`}function oe(r){return`qualifier:${r}`}function Ke(r,e){return`speaker:${r}:${e}`}var Je="speaker:pattern",Qe="{name} ({qualifier})";function ze(r,e,t){return r.split("{name}").map(n=>n.split("{qualifier}").join(t)).join(e)}var ve={open:"[",close:"]"},Xe="SFX";var _=4;function q(r){let e=new Set,t=[];for(let n of r)e.has(n)||(e.add(n),t.push(n));return t}function ae(r){let e=new Map,t=(n,s)=>{let i=q([...s,...n.tags??[]]);if(e.set(n.id,i),n.type==="group"&&n.prompt&&e.set(n.prompt.id,q([...i,...n.prompt.tags??[]])),n.type==="group")for(let o of n.children)t(o,i);else for(let o of n.beats??[])e.set(o.id,q([...i,...o.tags??[]]))};for(let n of Object.values(r.scenes)){let s=q(n.tags??[]);e.set(n.id,s);for(let i of n.blocks){let o=q([...s,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var Ye=r=>r.kind==="line"||r.kind==="text",H=r=>typeof r=="number"&&Number.isFinite(r)?r:void 0;function Ze(r){let e=new Map,t=(i,o,a)=>{let c=i.kind==="gameEvent"?void 0:H(i.padAfter),l=c??o;a&&l<0&&(l=0),e.set(i.id,c!==void 0?{own:c,resolved:l}:{resolved:l})},n=(i,o)=>{let a=H(i.padAfterDefault)??o;if(i.type==="group"){i.prompt&&t(i.prompt,a,!1);for(let d of i.children)n(d,a);return}let c=i.beats??[],l=-1;c.forEach((d,g)=>{Ye(d)&&(l=g)}),c.forEach((d,g)=>{Ye(d)&&t(d,a,g===l)})},s=H(r.padAfterDefault)??O;for(let i of Object.values(r.scenes)){let o=H(i.padAfterDefault)??s;for(let a of i.blocks){let c=H(a.padAfterDefault)??o;for(let l of a.children)n(l,c)}}return e}var et=new WeakMap,tt=new WeakMap;function Yt(r){let e=tt.get(r);return e||(e=ae(r),tt.set(r,e)),e}var nt=new WeakMap;function Zt(r){let e=nt.get(r);return e||(e=Ze(r),nt.set(r,e)),e}var rt=new WeakMap;function en(r){let e=rt.get(r);if(e)return e;e=new Map;for(let t of Object.values(r.scenes))for(let n of t.blocks)I(n.children,s=>{if(s.type==="group"&&s.selector==="choice")for(let i of s.children)e.set(i.id,s.id)});return rt.set(r,e),e}var st=new WeakMap;function tn(r){let e=st.get(r);if(e)return e;e=new Map;for(let t of Object.values(r.scenes))for(let n of t.blocks)I(n.children,s=>{if(s.type==="group"){s.prompt&&e.set(s.prompt.id,s.prompt);return}for(let i of s.beats??[])e.set(i.id,i)});return st.set(r,e),e}function b(r){if(r===void 0)return;let e={};for(let[t,n]of Object.entries(r))e[t]=Array.isArray(n)?[...n]:n;return e}function N(r,e){return r.tagIndex.get(e)?.slice()}var W="Patter",U=r=>r.replace(/%/g,"%25").replace(/\\//g,"%2F"),nn=r=>r.replace(/%2F/g,"/").replace(/%25/g,"%"),it=Symbol("ownsRegistry"),ot=Symbol("setupReported"),w={stage:r=>`patter/scene/${U(r)}`,flow:r=>`patter/flow/${U(r)}/`,flowGlobals:r=>`patter/flow/${U(r)}/patter`,flowScene:(r,e)=>`patter/flow/${U(r)}/scene/${U(e)}`},J=class{constructor(e){this.journal=e}journal},le=class r{host;defaultSeed;flowsById=new Map;allStrings;currentLocale;requestedLocale;sourceDebug;sceneGameIdToId=new Map;blockGameIdToId=new Map;creationOptions;engineLog=[];engineSeq=0;engineTraceHandlers=new Set;constructor(e,t={}){this.creationOptions=t;let n=[];for(let p of Object.keys(t))sn.has(p)||n.push({node:p,message:p==="world"?\'the engine option "world" has gone: bind the scope as hostScopes: { world }\':`"${p}" isn\'t an engine option, so it\'s ignored`});let s=e.strings;this.allStrings=s,this.requestedLocale=t.locale,this.currentLocale=ke(e,t.locale),this.currentLocale.problem&&n.push({node:t.locale,message:this.currentLocale.problem});let i=ut(s,this.currentLocale),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 p of e.cast??[])p.displayName&&l.set(p.name,p.displayName);let d=new Map;for(let p of e.qualifiers??[])p?.gameId&&d.set(p.gameId,p.name);let g=new Map;for(let p of e.cast??[])for(let[m,h]of Object.entries(p.qualifierLabels??{}))typeof h=="string"&&g.set(`${p.name}\\0${m}`,h);let f=e.speakerPattern??Qe;this.defaultSeed=(t.seed??2654435769)>>>0;let R=new Map,z=new Map,Pe=new Map;for(let[p,m]of Object.entries(e.scenes)){this.sceneGameIdToId.set(y(m),p);let h=new Map;for(let S of m.blocks)z.set(S.id,{sceneId:p}),Pe.set(S.id,S),h.set(y(S),S.id),I(S.children,k=>R.set(k.id,k));this.blockGameIdToId.set(p,h)}let Oe=e.properties??[],de=Oe.filter(p=>p.shared??!0).map(dt),Rt=Oe.filter(p=>!(p.shared??!0)).map(dt),Pt=new Set(de.map(p=>p.name.toLowerCase())),v=t.registry??new te,Ne=!t.registry||t[it]===!0,Ae=new D(de,{pathPrefix:"@patter."}),pe=[],X=[];try{v.mountOwned("patter",Ae,{owner:W}),X.push("patter");let p=new Set,m=e.scopeRegistry?.scopes??[];for(let[h,S]of Object.entries(t.hostScopes??{})){let k=m.find(Y=>Y.token===h);if(!k&&!(e.externalScopes??[]).includes(h)){let Y=m.find(Nt=>Nt.token.toLowerCase()===h.toLowerCase());n.push({node:h,message:Y?`hostScopes binds "${h}", which this bundle doesn\'t declare: it declares "${Y.token}", and a scope\'s token is case-sensitive`:`hostScopes binds "${h}", which this bundle doesn\'t declare`})}let Ot=(k?.declarations??[]).map(yt);v.defineForeign(h,S,Ot,{writable:k?.writable??!0,owner:W}),X.push(h),p.add(h)}for(let h of Ne?e.scopeRegistry?.scopes??[]:[]){if(p.has(h.token)||v.has(h.token))continue;let S=(h.declarations??[]).map(k=>cn(k,h.writable));v.defineOwned(h.token,S,{owner:W}),X.push(h.token),pe.push(h.token)}}catch(p){for(let m of X)v.remove(m,{keep:!0});throw p}let Fe=new Map;for(let[p,m]of Object.entries(e.scenes)){let h=new Set((m.sceneProps??[]).filter(S=>S.shared??!1).map(S=>S.name.toLowerCase()));Fe.set(p,h)}if(this.host={logEnabled:t.log??!1,tracing:t.log??!1,emitEngine:(p,m,h)=>this.emitEngine(p,m,h),bundle:e,emitIds:c,strings:i,defaultStrings:o,castDisplay:l,qualifierDisplay:d,speakerLabels:g,speakerPattern:f,nodeIndex:R,blockIndex:z,blockById:Pe,sceneGameIdToId:this.sceneGameIdToId,blockGameIdToId:this.blockGameIdToId,tagIndex:Yt(e),padIndex:Zt(e),registry:v,ownsRegistry:Ne,patterBag:Ae,hostScopes:pe,patterSharedDecls:de,patterLocalDecls:Rt,patterSharedNames:Pt,sceneSharedNames:Fe,sharedVisits:new Map,qualityLadders:new Map,sharedSelectors:new Map,stageBags:new Map,journal:null,customRng:t.rng,onDryChoice:t.onDryChoice,steer:pt(t.steer,n),onError:t.onError??(p=>console.warn(p.kind==="setup"?`Patterplay: ${p.message}`:p.kind==="save"?`Patterplay: flow \'${p.flow}\': ${p.message}`:`Patterplay: ${p.kind} on ${p.node} in flow \'${p.flow}\' failed, played through: ${p.message}`)),reportRefits:()=>{let p=v.takeMisfits(m=>m==="patter"||m.startsWith("patter/")||pe.includes(m));if(p.length!==0)if(t.onRefit)t.onRefit(p);else for(let m of p)console.warn(`Patterplay: the save\'s ${m.scope}.${m.name} was ${JSON.stringify(m.value)}, which no longer fits its declaration; it is back at its default`)},replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??ve).open,captionClose:(e.closedCaptions??ve).close,captionCharacter:e.closedCaptions?.character||Xe,refSplitCache:new Map,refSplitRevision:v.revision},this.host.reportRefits(),t[ot]!==!0)for(let p of n)this.reportSetup(p.node,p.message)}reportSetup(e,t){this.host.onError({flow:"",kind:"setup",node:e,message:t}),this.host.tracing&&this.emitEngine("",{type:"diagnostic",kind:"setup",node:e,message:t})}get locale(){return this.currentLocale.locale}get locales(){let{default:e,included:t}=this.host.bundle.locales;return{default:e,included:[...t]}}get isSourceDebug(){return this.sourceDebug}get buildId(){return this.host.bundle.content?.hash??""}setLocale(e){this.requestedLocale=e,this.useLocale(ke(this.host.bundle,e)),this.currentLocale.problem&&this.reportSetup(e,this.currentLocale.problem)}useLocale(e){this.currentLocale=e,this.host.strings=ut(this.allStrings,e)}replaceStrings(e){this.allStrings=e.strings;let t=this.currentLocale.problem;this.useLocale(ke(e,this.requestedLocale)),this.host.defaultStrings=this.allStrings[this.host.bundle.locales.default]??{};let n=this.currentLocale.problem;n&&n!==t&&this.reportSetup(this.requestedLocale,n)}hotSwap(e){this.refuseInCheckpoint("hotSwap");let t=this.saveGame(),n=l=>(l.setClosedCaptions(this.host.captionsOn),l),s=this.requestedLocale,i=(l=!1)=>new r(e,{...this.creationOptions,...s!==void 0?{locale:s}:{},steer:this.host.steer,registry:this.host.registry,[it]:this.host.ownsRegistry,[ot]:l}),o=new Set(["patter",...this.host.hostScopes]),a=this.host.ownsRegistry?void 0:Object.fromEntries(Object.entries(this.host.registry.save()).filter(([l])=>o.has(l)||l.startsWith("patter/")));this.release(!0),a&&this.host.registry.load(a,{keepParked:!0,refit:!0});let c=i();try{return c.loadGame(t),n(c)}catch{c.release(!0);let l=this.host.ownsRegistry?t.registry:a;l&&this.host.registry.load(l,{keepParked:!0,refit:!0});let d=i(!0);for(let[g,f]of Object.entries(t.flows)){let R=f.cursor.currentSceneId;try{d.openFlow(g,R!==null?{scene:R}:{})}catch{}}return n(d)}}get closedCaptions(){return this.host.captionsOn}setClosedCaptions(e){this.host.captionsOn=e}setSteer(e){if(e==null){this.host.steer=void 0;return}let t=[];this.host.steer=pt(e,t,"setSteer was given something that isn\'t a steerer (an object with gate and pick methods), so the engine is left unsteered");for(let{node:n,message:s}of t)this.reportSetup(n,s)}openFlow(e,t={}){this.assertExternalScopes();let{sceneId:n,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 A(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(n,s),a}runFlow(e,t,n){let s=this.flowsById.get(e);if(!s)return this.openFlow(e,{scene:t,block:n}).advanceToStop().played;if(!s.goto(t,n))throw new Error(`runFlow: address not found: ${t}${n===void 0?"":` / ${n}`}`);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 n=Ee(this.host,e);if(n===void 0)throw new Error(`unknown scene: ${e}`);if(t===void 0)return{sceneId:n};let s=De(this.host,n,t);if(s===void 0)throw new Error(`unknown block: ${t}`);return{sceneId:n,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:De(this.host,e,t)}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?y(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?y(t):void 0}tagsForBeat(e){return N(this.host,e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?N(this.host,t):void 0)??[]}tagsForBlock(e,t){let n=this.resolveSceneRef(e),s=this.resolveBlockRef(n,t);return(s!=null?N(this.host,s):void 0)??[]}gameDataForScene(e){let t=this.resolveSceneRef(e),n=t!=null?this.host.bundle.scenes[t]:void 0;return b(n?.gameData)??{}}gameDataForBlock(e,t){let n=this.resolveBlockRef(this.resolveSceneRef(e),t),s=n!=null?this.host.blockById.get(n):void 0;return b(s?.gameData)??{}}extensionsForScene(e){let t=this.resolveSceneRef(e);return{...(t!=null?this.host.bundle.scenes[t]:void 0)?.extensions}}extensionsForBlock(e,t){let n=this.resolveBlockRef(this.resolveSceneRef(e),t);return{...(n!=null?this.host.blockById.get(n):void 0)?.extensions}}extensionsForSnippet(e){let t=this.host.nodeIndex.get(e);return t?.type==="snippet"?{...t.extensions}:{}}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),n=t!=null?this.host.bundle.scenes[t]:void 0;if(!n)return[];let s=new Set;for(let i of n.blocks)at(i.children,s);return[...s]}castForBlock(e,t){let n=this.resolveSceneRef(e),s=this.resolveBlockRef(n,t),i=s!=null?this.host.blockById.get(s):void 0;if(!i)return[];let o=new Set;return at(i.children,o),[...o]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...y(e)?{gameId:y(e)}:{},name:e.name,...ct(e.gameData),...C(e.extensions),...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...y(t)?{gameId:y(t)}:{},name:t.name,...ct(t.gameData),...C(t.extensions),...this.tagsField(t.id),children:t.children.map(n=>this.outlineNode(n))}))}))}getBeatSequence(){let e=[];for(let t of Object.values(this.host.bundle.scenes))for(let n of t.blocks)I(n.children,s=>{if(s.type==="snippet")for(let i of s.beats??[])e.push({sceneId:t.id,blockId:n.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=N(this.host,e.id),n={id:e.id,kind:e.kind};if(e.kind==="line"){if(e.character!==void 0){n.character=e.character;let i=this.host.defaultStrings[ie(e.character)]??this.host.castDisplay.get(e.character);i!==void 0&&(n.characterName=i)}if(e.direction!==void 0&&(n.direction=e.direction),e.qualifier!==void 0){n.qualifier=e.qualifier;let i=this.host.defaultStrings[oe(e.qualifier)]??this.host.qualifierDisplay.get(e.qualifier);i!==void 0&&(n.qualifierName=i)}let s=ce(this.host,e.character,e.qualifier,!0);s!==void 0&&(n.speakerLabel=s)}if(e.kind==="line"||e.kind==="text"){let s=this.host.padIndex.get(e.id);n.padAfter=s?.resolved??O,s?.own!==void 0&&(n.ownPadAfter=s.own);let i=this.host.defaultStrings[e.id];i!==void 0&&(n.text=i)}return e.gameData&&Object.keys(e.gameData).length&&(n.gameData=b(e.gameData)),e.extensions&&Object.keys(e.extensions).length&&(n.extensions=e.extensions),t&&t.length&&(n.tags=t),n}tagsField(e){let t=N(this.host,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,n]of this.host.stageBags)e.push({bag:n,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 J(e)}rollback(e){this.endCheckpoint(e);let t=e.journal.undo;for(let n=t.length-1;n>=0;n--)t[n]();r.forget(e.journal)}commit(e){this.endCheckpoint(e),r.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`)}captureFlow(e){let t=this.flowsById.get(e);if(!t)throw new Error(`no open flow \'${e}\' to capture`);return{version:_,...t.snapshot(),...dn(e,this.host.registry.save())}}restoreFlow(e,t){this.refuseInCheckpoint("restoreFlow");let n=t.version;if(n!==3&&n!==_)throw new Error(`unsupported flow state version: ${String(n)}`);let s=t.cursor;if(typeof s!="object"||s===null)throw new Error("malformed flow state: no cursor");if(this.flowsById.has(e))throw new Error(`a flow \'${e}\' is already open; close it before restoring another under that id`);this.assertExternalScopes();let i=w.flow(e);this.host.registry.discardParked(i),this.host.registry.load(ln(e,t),{keepParked:!0,refit:!0});let o=new A(e,this.host,this.defaultSeed);try{o.restore(t)}catch(a){throw o.close(),this.host.registry.discardParked(i),a}return this.flowsById.set(e,o),this.host.reportRefits(),o}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(w.stage(e));this.host.stageBags.clear(),this.host.registry.discardParked("patter/")}release(e){for(let n of this.flowsById.values())n.releaseBags(e),n.close();this.flowsById.clear();let t=this.host.registry;for(let n of this.host.stageBags.keys())t.remove(w.stage(n),{keep:e});this.host.stageBags.clear();for(let n of["patter",...this.host.hostScopes])t.has(n)&&t.remove(n,{keep:e});for(let n of Object.keys(this.creationOptions.hostScopes??{}))t.has(n)&&t.remove(n)}getProperty(e){let{scope:t,name:n}=this.splitShared(e);return this.host.registry.get(t,n)}setProperty(e,t){let{scope:n,name:s}=this.splitShared(e);mt(this.host,n,s,t,null);let i=this.host.journal?this.host.registry.get(n,s):void 0;this.host.registry.set(n,s,t,{host:!0}),this.host.journal&&i!==void 0&&this.host.journal.undo.push(()=>this.host.registry.set(n,s,i,{host:!0}))}stageIndex(e,t){return F(this.ladderOf(e),t)}compareStages(e,t,n){return B(this.ladderOf(e),t,n)}nextStage(e,t){return T(this.ladderOf(e),t)}ladderOf(e){let{scope:t,name:n}=this.splitShared(e),s=an(this.host,t,n);if(!s)throw new Error(`\'${e}\' is not a quality`);return s}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,n){for(let s of this.engineTraceHandlers)s(e,t);this.host.logEnabled&&this.engineLog.push({...t,flow:e,seq:this.engineSeq++,...n?{scene:n}:{}})}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:L(e),writable:e.writable??!0}))}splitShared(e){let t=St(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}saveGame(){let e={};for(let[t,n]of this.flowsById)e[t]=n.snapshot();return{version:_,...this.host.ownsRegistry?{registry:this.host.registry.save()}:{},sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:ft(this.host.sharedSelectors),flows:e}}loadGame(e){this.refuseInCheckpoint("loadGame");let t=e.version;if(t!==3&&t!==_)throw new Error(`unsupported save version: ${String(t)}`);let n=e.flows;if(typeof n!="object"||n===null||Array.isArray(n))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(w.stage(o),{keep:!0});this.host.stageBags.clear();let i=e.registry;i&&(this.host.ownsRegistry?s.load(i,{refit:!0}):s.load(i,{keepParked:!0,refit:!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 ht(e.sharedSelectors))this.host.sharedSelectors.set(o,a);for(let[o,a]of Object.entries(e.flows)){let c=new A(o,this.host,this.defaultSeed);c.restore(a),this.flowsById.set(o,c)}this.host.reportRefits()}},A=class{id;host;local;registered=new Set;rngState;started=!1;flowEnded=!1;dryChoice=null;ranDry=null;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 n=this.currentSceneId;if(n===null)return;let s=this.sceneBagFor(n,e);s&&s.set(e,t)}};evalCtx;ctxRevision=-1;registryQualities;flowLog=[];flowSeq=0;constructor(e,t,n){this.id=e,this.host=t,this.rngState=j(n),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(),n=this.evalCtx.scopes;for(let s of Object.keys(n))delete n[s];Object.assign(n,t.scopes),n.patter=this.patterResolver,n.scene=this.sceneResolver,this.registryQualities=t.qualities,this.ctxRevision=e.revision}return this.evalCtx}stagesFor(e,t){let n=t.toLowerCase();if(e==="patter")return K(this.host,"patter",()=>[...this.host.patterSharedDecls,...this.host.patterLocalDecls]).get(n);if(e==="scene"){let s=this.currentSceneId;return s==null?void 0:K(this.host,`scene/${s}`,()=>this.host.bundle.scenes[s]?.sceneProps).get(n)}return this.registryQualities?.(e,t)??K(this.host,`host/${e}`,()=>this.host.bundle.scopeRegistry?.scopes.find(s=>s.token===e)?.declarations).get(n)}begin(e,t){let n=this.host.bundle.start;if(e===void 0&&t===void 0&&n&&this.host.bundle.scenes[n.scene]&&(e=n.scene,n.block!==void 0&&this.host.blockIndex.get(n.block)?.sceneId===n.scene&&(t=n.block)),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(w.flow(this.id)),this.mountLocal(),this.selectors.clear(),this.visitCounts.clear(),this.stack=[],this.currentSceneId=null,this.flowEnded=!1,this.dryChoice=null,this.ranDry=null,this.activeSnippet=null,this.beatIndex=0,this.clearPending(),this.started=!0,t){let s=this.host.blockIndex.get(t);if(!s)throw new Error(`unknown block: ${t}`);this.enterSceneSetup(s.sceneId),this.stack=[{sceneId:s.sceneId,containerId:t,index:0}],this.enter(t)}else{let s=e??Object.keys(this.host.bundle.scenes)[0],i=s?this.host.bundle.scenes[s]:void 0;if(!i)throw new Error(s?`unknown scene: ${s}`:"no scenes in bundle");this.enterSceneSetup(s);let o=i.blocks[0];o&&(this.stack=[{sceneId:s,containerId:o.id,index:0}],this.enter(o.id))}this.settle()}reset(e,t){this.begin(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=[],this.dryChoice=null,this.ranDry=null,!0;let n=Ee(this.host,e);if(n===void 0)return!1;let s;return t!==void 0&&(s=De(this.host,n,t),s===void 0)?!1:this.started?(this.clearPending(),this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!1,this.dryChoice=null,this.ranDry=null,this.enterTarget(s??n,"jump"),this.settle(),!0):(this.begin(n,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:n,flowEnded:s,dryChoice:i,ranDry:o,currentSceneId:a,activeSnippet:c,beatIndex:l,pendingChoice:d,pendingPrompt:g,pendingPromptOwnerId:f}=this,R=this.stack.map(z=>({...z}));e.undo.push(()=>{Object.assign(this,{rngState:t,started:n,flowEnded:s,dryChoice:i,ranDry:o,currentSceneId:a,activeSnippet:c,beatIndex:l,pendingChoice:d,pendingPrompt:g,pendingPromptOwnerId:f,stack:R})})}get isClosed(){return this.closed}get currentScene(){return this.currentSceneId}advance(){if(this.closed)return{type:"end",reason:"ended"};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&&!this.activeSnippet&&!this.pendingChoice&&(this.flowEnded=!0),this.flowEnded?this.endResult():(this.dryChoice=null,this.pendingChoice?{type:"choice",groupId:this.pendingChoice.groupId,options:this.offer(this.pendingChoice)}:this.beatResult(this.activeSnippet.beats[this.beatIndex++]))}endResult(){if(this.dryChoice!==null){let e=this.dryChoice;this.dryChoice=null,this.ranDry=e,this.report({flow:this.id,kind:"dry-choice",node:e,message:`choice \'${e}\' ran dry (no option left to take, and no fallback) with nothing after it, so the flow ended there`})}return{type:"end",reason:this.ranDry!==null?"ran-dry":"ended"}}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 n=this.childrenOf(t.containerId);if(!n){this.stack.pop();continue}let s=t.index;for(;t.index<n.length&&!this.eligible(n[t.index],"run");)t.index++;if(this.host.tracing&&t.index!==s&&this.emit({type:"select",group:t.containerId,selector:"run",children:n.slice(s,t.index+1).map((i,o)=>({id:i.id,eligible:s+o===t.index})),picked:n[t.index]?.id??null}),t.index>=n.length){this.stack.pop();continue}this.enterChild(n[t.index++])}}listBags(){let e=[{bag:this.local,pathPrefix:`${this.id}/@patter.`}];for(let[t,n]of this.sceneBags)e.push({bag:n,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)}stepFor(e){let t=tn(this.host.bundle).get(e);return t?this.beatResult(t):void 0}getChoices(){return this.pendingChoice?this.offer(this.pendingChoice):[]}offer(e){return e.options.map(t=>{let n=e.byId.get(t.id),s=this.promptFor(n);return e.shown.set(t.id,s),{id:t.id,prompt:s,eligible:t.eligible,gameData:b(t.gameData),...C(n.extensions)}})}choose(e){let t=this.pendingChoice;if(!t)throw new Error("no choice is pending");let n=t.options.find(a=>a.id===e);if(!n)throw new Error(`unknown choice option: ${e}`);if(!n.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,o=i?t.shown.has(e)?t.shown.get(e):this.promptFor(s):void 0;this.pendingPrompt=i&&o?{beat:i,shown:{...o}}:null,this.pendingPromptOwnerId=this.pendingPrompt?s.id:null,this.enterChild(s)}isEnded(){return this.flowEnded}getProperty(e){let{scope:t,name:n}=this.splitRef(e);return t==="patter"?this.patterResolver.get(n):t==="scene"?this.sceneResolver.get(n):this.host.registry.get(t,n)}setProperty(e,t){this.writeProperty(e,t,!0)}stageIndex(e,t){return F(this.ladderOf(e),t)}compareStages(e,t,n){return B(this.ladderOf(e),t,n)}nextStage(e,t){return T(this.ladderOf(e),t)}ladderOf(e){let{scope:t,name:n}=this.splitRef(e);this.context();let s=this.stagesFor(t,n);if(!s)throw new Error(`\'${e}\' is not a quality`);return s}writeProperty(e,t,n){let{scope:s,name:i}=this.splitRef(e);if(n){if(s==="scene"&&this.currentSceneId===null)throw new Error(`\'${e}\': the flow has not entered a scene yet`);mt(this.host,s,i,t,this.currentSceneId)}let 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,n?{host:!0}:void 0),o&&a!==void 0&&o.undo.push(()=>this.host.registry.set(s,i,a,{host:!0}))}}snapshot(){let e=en(this.host.bundle),t=this.activeSnippet?.beats?.[this.beatIndex]?.id;return{rngState:this.rngState,visits:Object.fromEntries(this.visitCounts),cursor:{flowEnded:this.flowEnded,...this.ranDry!==null?{ranDry:this.ranDry}:{},currentSceneId:this.currentSceneId,stack:this.stack.map(n=>{let s=this.childrenOf(n.containerId)?.[n.index],i=e.get(n.containerId);return{...n,...s?{nextId:s.id}:{},...i!==void 0?{choiceId:i}:{}}}),activeSnippetId:this.activeSnippet?.id??null,...t!==void 0?{beatId:t}:{},pendingChoice:this.pendingChoice?{groupId:this.pendingChoice.groupId,options:this.pendingChoice.options.map(n=>({id:n.id,eligible:n.eligible,...n.gameData!==void 0?{gameData:b(n.gameData)}:{}}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,...this.pendingPrompt?.shown?{pendingPrompt:rn(this.pendingPrompt.shown)}:{},selectors:ft(this.selectors)}}}restore(e){if(this.host.journal)throw new Error("a flow can\'t be restored while a checkpoint is open");let t=this.restoreCursor(e);this.releaseBags(!0),this.mountLocal();for(let n of new Set([this.currentSceneId,...this.stack.map(s=>s.sceneId)]))n!==null&&this.host.bundle.scenes[n]&&this.ensureSceneBags(n);t&&(this.report({flow:this.id,kind:"save",node:t.node,message:`the save\'s place has gone from this build: ${t.instead}`}),t.reoffer&&this.setupChoice(t.reoffer))}restoreCursor(e){this.rngState=j(e.rngState),this.visitCounts=new Map(Object.entries(e.visits??{}));let t=e.cursor;this.started=!0,this.flowEnded=t.flowEnded,this.dryChoice=null,this.ranDry=t.flowEnded&&typeof t.ranDry=="string"?t.ranDry:null,this.currentSceneId=t.currentSceneId;let n=null;this.stack=[];for(let s of t.stack){let{nextId:i,choiceId:o,...a}=s,c=this.childrenOf(a.containerId),l=!c&&o!==void 0?this.host.nodeIndex.get(o):void 0;if(l?.type==="group"&&l.selector==="choice"){n={node:t.activeSnippetId??t.pendingChoice?.groupId??a.containerId,instead:`option ${a.containerId} has gone, so choice ${l.id} is offered again`,reoffer:l};break}let d=i!==void 0?c?.findIndex(g=>g.id===i)??-1:-1;this.stack.push(d>=0?{...a,index:d}:{...a})}if(this.activeSnippet=null,this.beatIndex=0,!n?.reoffer&&t.activeSnippetId!==null){let s=this.host.nodeIndex.get(t.activeSnippetId);if(s&&s.type==="snippet"){let i=s.beats??[];if(this.activeSnippet=s,t.beatId!==void 0){let o=i.findIndex(a=>a.id===t.beatId);this.beatIndex=o>=0?o:i.length,o<0&&(n={node:t.activeSnippetId,instead:`beat ${t.beatId} has gone from snippet ${t.activeSnippetId}, so the snippet ends there`})}else this.beatIndex=t.beatIndex??i.length}else n={node:t.activeSnippetId,instead:`snippet ${t.activeSnippetId} has gone, so play carries on after it`}}if(this.selectors=ht(t.selectors),this.pendingChoice=null,!n?.reoffer&&t.pendingChoice!==null){let s=new Map,i=[];for(let o of t.pendingChoice.options){let a=this.host.nodeIndex.get(o.id);a&&(s.set(o.id,a),i.push({id:o.id,eligible:o.eligible,...o.gameData!==void 0?{gameData:o.gameData}:{}}))}if(i.length>0)this.pendingChoice={groupId:t.pendingChoice.groupId,options:i,byId:s,shown:new Map};else{let o=this.host.nodeIndex.get(t.pendingChoice.groupId);n=o?.type==="group"&&o.selector==="choice"?{node:t.pendingChoice.groupId,instead:`none of choice ${o.id}\'s options is left, so it\'s offered again`,reoffer:o}:{node:t.pendingChoice.groupId,instead:`choice ${t.pendingChoice.groupId} has gone, so play carries on after it`}}}if(this.pendingPrompt=null,this.pendingPromptOwnerId=n?.reoffer?null:t.pendingPromptOwnerId??null,this.pendingPromptOwnerId){let s=this.host.nodeIndex.get(this.pendingPromptOwnerId),i=s?this.authoredPromptOf(s):void 0,o=t.pendingPrompt,a=o?.kind==="line"&&o.speakerLabel===void 0?ce(this.host,o.character,o.qualifier):void 0;i?this.pendingPrompt={beat:i,...o?{shown:{...o,padAfter:o.padAfter??this.padOf(i.id),...a!==void 0?{speakerLabel:a}:{}}}:{}}:this.pendingPromptOwnerId=null}return n}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 n=this.selectChild(e);n&&this.enterChild(n)}childrenOf(e){let t=this.host.blockById.get(e);if(t)return t.children;let n=this.host.nodeIndex.get(e);if(n&&n.type==="group")return n.children}beginSnippet(e){this.runEffects(e.onEnter,e.id),this.activeSnippet=e,this.beatIndex=0}setupChoice(e){let t=[],n=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,"option"),c=o.secretUntilEligible===!0;!a&&c||(t.push({id:o.id,eligible:a,...o.gameData!==void 0?{gameData:o.gameData}:{}}),n.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:n,shown:new Map};return}let i=s.find(o=>this.eligible(o,"fallback"));if(i){this.enterChild(i);return}this.host.tracing&&this.emit({type:"dry",group:e.id}),this.host.onDryChoice?.(e.id),this.dryChoice=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 n,s,i=this.host.bundle.scenes[e];if(i){this.enterSceneSetup(e);let a=i.blocks[0];if(!a){t==="jump"&&(this.stack=[]);return}n=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),n=a.sceneId,s=e}this.enter(s);let o={sceneId:n,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.holds(c)})),n=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),a=null;if(n.length>0){let c=this.selectorState(e);switch(e.selector){case"branch":a=n[0];break;case"sequence":a=s==="shuffle"?this.pickShuffle(n,i,c):s==="specificity"?this.pickSpecificity(n,i,c):this.pickSequential(n,i,c);break;default:return null}}return this.host.steer?.pick&&(e.selector==="branch"||e.selector==="sequence")&&(a=this.steerPick(e,e.selector,t,a)),o(a)}steerPick(e,t,n,s){let i=s?.id??"",o=this.host.steer.pick({flow:this.id,group:e.id,selector:t,children:n.map(c=>({...c})),default:i});if(typeof o!="string")throw new Error(`steer: pick for ${e.id} answered ${String(o)}, not a child id or ""`);if(o===i)return s;let a=o===""?null:e.children.find(c=>c.id===o);if(a===void 0)throw new Error(`steer: pick for ${e.id} answered "${o}", which isn\'t one of its children`);return this.host.tracing&&this.emit({type:"steered",node:e.id,kind:"pick",default:i,answer:o}),a}pickSequential(e,t,n){let s=e.length,i=n.seq??0;return n.seq=i+1,t==="repeat"?e[i%s]:i<s?e[i]:t==="stick"?e[s-1]:null}pickShuffle(e,t,n){let s=e.length,i=t==="stick",o=()=>(i?e.slice(0,s-1):e).map(f=>f.id),a=new Set(e.map(f=>f.id));if(n.bag===void 0&&(n.bag=o()),!n.bag.some(f=>a.has(f))){if(t==="once")return null;if(i){let f=e[s-1];return n.last=f.id,f}if(n.bag=o(),n.bag.length===0)return null}let c=n.bag.filter(f=>a.has(f)),l=n.last!==void 0&&c.length>1?c.indexOf(n.last):-1,d=Math.floor(this.rng()*(l>=0?c.length-1:c.length));l>=0&&d>=l&&d++;let g=c[d];return n.bag.splice(n.bag.indexOf(g),1),n.last=g,e.find(f=>f.id===g)}pickSpecificity(e,t,n){let s=e;if(t!=="repeat"){n.bag===void 0&&(n.bag=e.map(d=>d.id));let l=new Set(n.bag);if(s=e.filter(d=>l.has(d.id)),s.length===0)return t==="stick"&&n.last!==void 0?e.find(d=>d.id===n.last)??null:null}let i=-1,a=s.map(l=>{let d=this.specScore(l);return d>i&&(i=d),{c:l,s:d}}).filter(l=>l.s===i).map(l=>l.c),c;if(a.length===1)c=a[0];else{let l=n.last!==void 0?a.findIndex(g=>g.id===n.last):-1,d=Math.floor(this.rng()*(l>=0?a.length-1:a.length));l>=0&&d>=l&&d++,c=a[d]}return t!=="repeat"&&(n.bag=n.bag.filter(l=>l!==c.id)),n.last=c.id,c}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0,e):0}matchedSpec(e,t,n){return Te(e,i=>{try{return gt(Z(i,this.context(),Se))}catch(o){return this.reportError("best-match",n.id,n.condition,o),!1}},{want:t})}selectorState(e){let t=e.shared?this.host.sharedSelectors:this.selectors,n=this.host.journal,s;if(n&&(s=e.shared?n.selectors:n.flowSelectors.get(this),s||(s=new Set,n.flowSelectors.set(this,s))),n&&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;n.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 n of e??[]){let s;try{s=this.evalExpr(n.value);let i=this.host.tracing?this.getProperty(n.target):void 0;this.writeProperty(n.target,s,!1),this.host.tracing&&this.emit({type:"write",target:n.target,value:s,...i!==void 0?{prev:i}:{}})}catch(i){this.reportError("effect",t,n.value,i)}}}holds(e){if(!e.condition)return!0;try{return gt(this.evalExpr(e.condition))}catch(t){return this.reportError("condition",e.id,e.condition,t),!1}}eligible(e,t){let n=this.holds(e),s=this.host.steer?.gate;if(!s||!e.condition)return n;let i=s({flow:this.id,node:e.id,where:t,source:e.condition.src??"",default:n});if(typeof i!="boolean")throw new Error(`steer: gate for ${e.id} answered ${String(i)}, not true or false`);return i!==n&&this.host.tracing&&this.emit({type:"steered",node:e.id,kind:"gate",default:n,answer:i}),i}reportError(e,t,n,s){let i=s instanceof Error?s.message:String(s),o=n?.src;this.report({flow:this.id,kind:e,node:t,...o?{source:o}:{},message:i})}report(e){this.host.onError(e),this.host.tracing&&this.emit({type:"diagnostic",kind:e.kind,node:e.node,...e.source?{source:e.source}:{},message:e.message})}evalExpr(e){return Z(this.conditionAst(e),this.context(),Se)}conditionAst(e){let t=et.get(e);return t||(t=P(e.ast),et.set(e,t)),t}enter(e){let t=this.visitCounts,n=t.get(e);t.set(e,(n??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(()=>{n===void 0?t.delete(e):t.set(e,n),i===void 0?s.delete(e):s.set(e,i)})}rng=()=>{if(this.host.customRng)return this.host.customRng();let e=fe(this.rngState),t=e.next();return this.rngState=e.state(),t};beatResult(e){let t=N(this.host,e.id),n=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:b(e.gameData),...C(e.extensions),...n};case"text":return{type:"text",id:e.id,text:this.interpolate(this.resolveString(e.id)),padAfter:this.padOf(e.id),...e.action?{action:!0}:{},...this.spokenOf(e),gameData:b(e.gameData),...C(e.extensions),...n};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,qualifier:c?void 0:e.qualifier,qualifierName:c?void 0:this.resolveQualifierName(e.qualifier),speakerLabel:c?void 0:ce(this.host,e.character,e.qualifier),padAfter:this.padOf(e.id),...this.spokenOf(e),gameData:b(e.gameData),...C(e.extensions),...n}}}}interpolate(e){return qe(e,t=>this.getProperty(t))}stripCaptions(e){return _e(e,this.host.captionOpen,this.host.captionClose)}captionLine(e){return this.host.captionsOn?e:this.stripCaptions(e)}spokenOf(e){let t=this.host.bundle.estimateSpeed??V,n=this.host.emitIds?void 0:this.host.defaultStrings[e.id];if(n===void 0)return{estimateSpeed:t};let s;return e.kind==="text"?s=this.interpolate(n):e.character===this.host.captionCharacter?s="":s=this.stripCaptions(this.host.bundle.voiced?n:this.interpolate(n)),{spokenText:s,spokenLocale:this.host.bundle.locales.default,estimateSpeed:t}}promptFor(e){let t=this.promptBeatOf(e);if(!t)return;let n=this.interpolate(this.resolveString(t.id)),s=this.padOf(t.id);return t.kind==="line"?{kind:"line",text:this.captionLine(n),character:t.character,characterName:this.resolveCharacterName(t.character),direction:t.direction,qualifier:t.qualifier,qualifierName:this.resolveQualifierName(t.qualifier),speakerLabel:ce(this.host,t.character,t.qualifier),padAfter:s}:{kind:"text",text:n,padAfter:s}}authoredPromptOf(e){return e.type==="group"?e.prompt:void 0}promptResult(e,t){let n=N(this.host,e.id),s=n&&n.length?{tags:n}:{};return t.kind==="text"?{type:"text",id:e.id,text:t.text,padAfter:this.padOf(e.id),...this.spokenOf(e),gameData:b(e.gameData),...C(e.extensions),...s}:{type:"line",id:e.id,text:t.text,character:t.character,characterName:t.characterName,direction:t.direction,qualifier:t.qualifier,qualifierName:t.qualifierName,speakerLabel:t.speakerLabel,padAfter:this.padOf(e.id),...this.spokenOf(e),gameData:b(e.gameData),...C(e.extensions),...s}}promptBeatOf(e){return e.type==="group"&&e.prompt?e.prompt:((e.type==="snippet"?e:this.firstTextSnippetIn(e.children))?.beats??[]).find(n=>n.kind==="line"||n.kind==="text")}firstTextSnippetIn(e){let t;return I(e,n=>{!t&&n.type==="snippet"&&(n.beats??[]).some(s=>s.kind==="line"||s.kind==="text")&&(t=n)}),t}resolveString(e){if(this.host.emitIds)return e;let t=this.host.strings[e];if(t!==void 0)return t;let n=this.host.defaultStrings[e];return n!==void 0?`<Untranslated: ${e}> ${n}`:e}resolveCharacterName(e){if(e===void 0||this.host.emitIds)return;let t=ie(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}padOf(e){return this.host.padIndex.get(e)?.resolved??O}resolveQualifierName(e){if(e===void 0||this.host.emitIds)return;let t=oe(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.qualifierDisplay.get(e)}splitRef(e){return St(this.host,e)}newLocal(){return new D(this.host.patterLocalDecls,{pathPrefix:"@patter."})}mountLocal(){this.local=this.newLocal();let e=w.flowGlobals(this.id);this.host.registry.mountOwned(e,this.local,{owner:W}),this.registered.add(e),this.host.reportRefits()}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,n=this.host.bundle.scenes[e]?.sceneProps??[],s=this.host.journal,i=!this.sceneBags.has(e)||!this.host.stageBags.has(e);if(!this.sceneBags.has(e)){let o=new D(n.filter(l=>!t.has(l.name.toLowerCase())),{pathPrefix:"@scene."}),a=w.flowScene(this.id,e),c=lt(this.host.registry,a,o,s!==null);this.registered.add(a),this.sceneBags.set(e,o),s&&s.undo.push(()=>{this.sceneBags.get(e)===o&&(this.host.registry.remove(a,c?{keep:!0}:void 0),this.registered.delete(a),this.sceneBags.delete(e))})}if(!this.host.stageBags.has(e)){let o=new D(n.filter(c=>t.has(c.name.toLowerCase())),{pathPrefix:"@scene."}),a=lt(this.host.registry,w.stage(e),o,s!==null);this.host.stageBags.set(e,o),s&&s.undo.push(()=>{this.host.stageBags.get(e)===o&&(this.host.registry.remove(w.stage(e),a?{keep:!0}:void 0),this.host.stageBags.delete(e))})}i&&this.host.reportRefits()}seedScene(e){let t=this.host.sceneSharedNames.get(e.id)??new Set;this.ensureSceneBags(e.id);for(let n of e.sceneProps??[]){if(!n.temporary)continue;let s=n.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,L(n))}}};function at(r,e){I(r,t=>{if(t.type==="group"){t.prompt?.kind==="line"&&t.prompt.character&&e.add(t.prompt.character);return}for(let n of t.beats??[])n.kind==="line"&&n.character&&e.add(n.character)})}function ce(r,e,t,n=!1){if(!e||r.emitIds)return;let s=c=>(n?void 0:r.strings[c])??r.defaultStrings[c],i=s(ie(e))??r.castDisplay.get(e)??e;if(t===void 0)return i;let o=r.speakerLabels.get(`${e}\\0${t}`);if(o!==void 0)return s(Ke(e,t))??o;let a=s(oe(t))??r.qualifierDisplay.get(t)??t;return ze(s(Je)??r.speakerPattern,i,a)}function ct(r){return r&&Object.keys(r).length?{gameData:b(r)}:{}}function C(r){return r&&Object.keys(r).length?{extensions:r}:{}}function rn(r){let e={kind:r.kind,text:r.text};return r.character!==void 0&&(e.character=r.character),r.characterName!==void 0&&(e.characterName=r.characterName),r.direction!==void 0&&(e.direction=r.direction),r.qualifier!==void 0&&(e.qualifier=r.qualifier),r.qualifierName!==void 0&&(e.qualifierName=r.qualifierName),r.speakerLabel!==void 0&&(e.speakerLabel=r.speakerLabel),typeof r.padAfter=="number"&&(e.padAfter=r.padAfter),e}function ft(r){let e={};for(let[t,n]of r){let s={};n.seq!==void 0&&(s.seq=n.seq),n.bag&&(s.bag=[...n.bag]),n.last!==void 0&&(s.last=n.last),e[t]=s}return e}function ht(r){let e=new Map;for(let[t,n]of Object.entries(r??{})){let s={};n.seq!==void 0&&(s.seq=n.seq),n.bag&&(s.bag=[...n.bag]),n.last!==void 0&&(s.last=n.last),e.set(t,s)}return e}function lt(r,e,t,n){let s=n?JSON.stringify(t.save()):"";return r.mountOwned(e,t,{owner:W}),n&&JSON.stringify(t.save())!==s}function dt(r){return{name:r.name,type:r.type,values:r.values,stages:r.stages,default:r.default}}var sn=new Set(["rng","seed","locale","hostScopes","registry","replayPromptOnChoose","closedCaptions","onDryChoice","steer","onError","onRefit","log"]);function pt(r,e,t=`the engine option "steer" isn\'t a steerer (an object with gate and pick methods), so it\'s ignored`){if(r==null)return;let n=r;if(typeof r=="object"&&(n.gate===void 0||typeof n.gate=="function")&&(n.pick===void 0||typeof n.pick=="function"))return r;e.push({node:"steer",message:t})}function ke(r,e){let t=r.locales.default;if(e===void 0)return{locale:t,table:t};if(r.localisation?.mode==="ids")return{locale:e,table:e};let n=[...new Set([t,...r.locales.included,...Object.keys(r.strings)])];if(n.includes(e))return{locale:e,table:e};let s=c=>c.toLowerCase().replace(/_/g,"-"),i=n.find(c=>s(c)===s(e));if(i!==void 0)return{locale:i,table:i,problem:`the locale "${e}" is spelled "${i}" in this bundle, so it\'s using "${i}"`};let o=s(e).split("-")[0],a=n.find(c=>s(c)===o);return a!==void 0?{locale:a,table:a,problem:`this bundle has no locale "${e}", so it\'s using its language, "${a}"`}:{locale:t,problem:`this bundle has no locale "${e}", so it\'s using the default, "${t}", with every string marked untranslated`}}function ut(r,e){return e.table!==void 0?r[e.table]??{}:{}}function mt(r,e,t,n,s){let i=c=>c?.find(l=>l.name.toLowerCase()===t),o;if(e==="patter")o=i(r.bundle.properties);else if(e==="scene")o=i(s!==null?r.bundle.scenes[s]?.sceneProps:void 0);else{let c=r.bundle.scopeRegistry?.scopes.find(l=>l.token===e);if(!c||c.declarations===void 0)return;o=i(c.declarations)}let a=`@${e}.${t}`;if(o===void 0)throw new Error(`no property at "${a}": the content declares no ${a}`);if(!$(o,n,{noneChosen:o.type==="enum"&&o.default===""}))throw new Error(`"${a}" takes ${on(o)}; ${JSON.stringify(n)} doesn\'t fit`)}function on(r){let e=t=>(t??[]).map(n=>JSON.stringify(n)).join(", ");switch(r.type){case"number":return"a number";case"boolean":return"true or false";case"enum":return`one of ${e(r.values)}`;case"flags":return r.values!==void 0&&r.values.length>0?`a list of flags from ${e(r.values)}`:"a list of flags";case"quality":return`one of its stages ${e(r.stages)}`;default:return"text"}}function K(r,e,t){let n=r.qualityLadders.get(e);if(!n){n=new Map;for(let s of t()??[]){let i=s.name.toLowerCase();s.type==="quality"&&s.stages&&!n.has(i)&&n.set(i,s.stages)}r.qualityLadders.set(e,n)}return n}function an(r,e,t){let n=t.toLowerCase();return e==="patter"?K(r,"patter",()=>[...r.patterSharedDecls,...r.patterLocalDecls]).get(n):r.registry.toEvalContext().qualities?.(e,t)??K(r,`host/${e}`,()=>r.bundle.scopeRegistry?.scopes.find(s=>s.token===e)?.declarations).get(n)}function yt(r){return{name:r.name,type:r.type,values:r.values,stages:r.stages,default:r.default,writable:r.writable}}function cn(r,e){let t=yt(r),n=r.writable??e;return n===void 0?t:{...t,writable:n}}function Ee(r,e){return se(r.bundle.scenes,e,r.sceneGameIdToId)}function De(r,e,t){return r.blockGameIdToId.get(e)?.get(t)??(r.blockIndex.get(t)?.sceneId===e?t:void 0)}function St(r,e){r.refSplitRevision!==r.registry.revision&&(r.refSplitCache.clear(),r.refSplitRevision=r.registry.revision);let t=r.refSplitCache.get(e);return t||(t=Ve(e,n=>n==="scene"||r.registry.has(n)||(r.bundle.externalScopes?.includes(n)??!1)),r.refSplitCache.set(e,t)),t}function ln(r,e){let t={};e.scopes?.patter&&(t[w.flowGlobals(r)]=e.scopes.patter);for(let[n,s]of Object.entries(e.sceneBags??{}))t[w.flowScene(r,n)]=s;return t}function dn(r,e){let t={scopes:{},sceneBags:{}},n=w.flow(r);for(let[s,i]of Object.entries(e)){if(!s.startsWith(n))continue;let o=s.slice(n.length);o==="patter"?t.scopes.patter=i:o.startsWith("scene/")&&(t.sceneBags[nn(o.slice(6))]=i)}return t}function gt(r){return typeof r=="boolean"?r:typeof r=="number"?r!==0:typeof r=="string"?r!=="":r.length>0}var xt="1.0.1",pn=/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/;function Ie(r){let e=typeof r=="string"?pn.exec(r):null;return e?{core:[e[1],e[2],e[3]],pre:e[4]?e[4].split("."):[]}:null}function wt(r,e){return r=r.replace(/^0+(?=\\d)/,""),e=e.replace(/^0+(?=\\d)/,""),r.length!==e.length?r.length<e.length?-1:1:r===e?0:r<e?-1:1}function bt(r,e){for(let t=0;t<3;t++){let n=wt(r.core[t],e.core[t]);if(n)return n}if(!r.pre.length||!e.pre.length)return e.pre.length-r.pre.length;for(let t=0;t<Math.min(r.pre.length,e.pre.length);t++){let n=r.pre[t],s=e.pre[t];if(n===s)continue;let i=/^\\d+$/.test(n),o=/^\\d+$/.test(s);if(i&&o){let a=wt(n,s);if(a)return a;continue}return i!==o?i?-1:1:n<s?-1:1}return r.pre.length-e.pre.length}function vt(r,e,t){let n=Ie(r),s=Ie(e),i=Ie(t);return!n||!s||!i?!1:bt(n,s)>=0&&bt(n,i)<0}var un=(r,e)=>r.shared??e;function Ce(r,e){return{name:r.name,type:r.type,hasDefault:r.default!==void 0,...r.default!==void 0?{default:r.default}:{},shared:un(r,e)}}function gn(r){return{name:r.name,type:r.type,hasDefault:r.default!==void 0,...r.values?{values:[...r.values]}:{},...r.purpose?{purpose:r.purpose}:{}}}function fn(r,e){e.blocks++;let t=[...r.children];for(;t.length;){let n=t.pop();if(n.type==="group"){e.groups++,n.prompt&&e.prompts++,t.push(...n.children);continue}e.snippets++;for(let s of n.beats??[])e.beats++,s.kind==="gameEvent"&&e.gameEvents++}}function kt(r){let e={scenes:0,blocks:0,groups:0,snippets:0,beats:0,prompts:0,gameEvents:0,cast:r.cast?.length??0},t=[],n=[];for(let o of Object.values(r.scenes)){e.scenes++;let a=y(o);t.push({gameId:a,name:o.name,blocks:o.blocks.map(c=>({gameId:y(c),name:c.name}))});for(let c of o.blocks)fn(c,e);o.sceneProps?.length&&n.push({gameId:a,properties:o.sceneProps.map(c=>Ce(c,!1))})}let s=(r.scopeRegistry?.scopes??[]).map(o=>({token:o.token,writable:o.writable??!0,opaque:o.declarations===void 0,properties:(o.declarations??[]).map(a=>Ce(a,!0))})),i=Object.entries(r.gameDataFields??{}).filter(([,o])=>(o?.length??0)>0).map(([o,a])=>({kind:o,fields:(a??[]).map(gn)}));return{identity:{schema:r.schema,project:r.content.project,...r.content.version!==void 0?{version:r.content.version}:{},...r.content.hash!==void 0?{hash:r.content.hash}:{},...r.content.structureHash!==void 0?{structureHash:r.content.structureHash}:{},voiced:r.voiced,defaultLocale:r.locales.default,locales:[...r.locales.included],localisation:r.localisation?.mode??"embedded",sourceDebug:r.localisation?.sourceDebug??!1},addresses:t,hostScopes:s,properties:{patter:(r.properties??[]).map(o=>Ce(o,!0)),scene:n},gameData:i,counts:e}}var Q=(r,e)=>Object.prototype.hasOwnProperty.call(r,e);function Et(r,e){return r.gameDataFields?.[e]??[]}function Re(r,e,t){return e&&Q(e,t)?e[t]:r.find(n=>n.name===t)?.default}function Dt(r,e){let t={};for(let n of r){let s=Re(r,e,n.name);s!==void 0&&(t[n.name]=s)}for(let[n,s]of Object.entries(e??{}))Q(t,n)||(t[n]=s);return t}function It(r,e,t){let n=r.extensions!==void 0&&Q(r.extensions,e)?r.extensions[e]:void 0;return n!==void 0&&Q(n.fields,t)?n.fields[t]??[]:[]}function Ct(r,e,t=""){let n=o=>({...o?.extensions??{}}),s=Object.values(r.scenes??{}),i=o=>(Q(r.scenes??{},o)?r.scenes[o]:void 0)??s.find(a=>y(a)===o);switch(e){case"project":{let o={};for(let[a,c]of Object.entries(r.extensions??{}))c.project!==void 0&&(o[a]=c.project);return o}case"scene":return n(i(t));case"block":{let o=t.indexOf("/");if(o<0)return{};let a=i(t.slice(0,o))?.blocks??[],c=t.slice(o+1);return n(a.find(l=>l.id===c)??a.find(l=>y(l)===c))}case"snippet":case"option":case"line":case"text":case"gameEvent":{let o,a=(c,l)=>{for(let d of c??[]){if(o!==void 0)return;if(d.type==="group"){if(l&&d.id===t&&e==="option"){o=d;return}if(l&&d.prompt?.id===t&&d.prompt.kind===e){o=d.prompt;return}a(d.children??[],d.selector==="choice");continue}if(d.id===t&&e==="snippet"){o=d;return}let g=(d.beats??[]).find(f=>f.id===t);if(g!==void 0){g.kind===e&&(o=g);return}}};for(let c of s)for(let l of c.blocks??[])o===void 0&&a(l.children??[],!1);return n(o)}default:return{}}}return Mt(hn);})();\n';
|
|
2710
2710
|
|
|
2711
2711
|
// src/play-timeline.ts
|
|
2712
2712
|
function createTimeline(defaultPad) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patterkit/ops",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "The shared operations layer: every project operation (load, validate, export, format, play, ...) as a pure function, consumed by the patter CLI and Patterpad alike.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"patter",
|
|
@@ -45,13 +45,13 @@
|
|
|
45
45
|
"@fontsource/noto-sans": "^5.3.0",
|
|
46
46
|
"@fontsource/noto-sans-math": "^5.3.0",
|
|
47
47
|
"@ibm/plex-mono": "1.0.0",
|
|
48
|
-
"@patterkit/compiler": "1.0.
|
|
49
|
-
"@patterkit/core": "1.0.
|
|
50
|
-
"@patterkit/dialect": "1.0.
|
|
51
|
-
"@patterkit/model": "1.0.
|
|
52
|
-
"@patterkit/runtime": "1.0.
|
|
53
|
-
"@wildwinter/expr": "^1.0.
|
|
54
|
-
"@wildwinter/toolkit": "^1.
|
|
48
|
+
"@patterkit/compiler": "1.0.1",
|
|
49
|
+
"@patterkit/core": "1.0.1",
|
|
50
|
+
"@patterkit/dialect": "1.0.1",
|
|
51
|
+
"@patterkit/model": "1.0.1",
|
|
52
|
+
"@patterkit/runtime": "1.0.1",
|
|
53
|
+
"@wildwinter/expr": "^1.0.1",
|
|
54
|
+
"@wildwinter/toolkit": "^1.1.0",
|
|
55
55
|
"@xmldom/xmldom": "^0.8.15",
|
|
56
56
|
"docx": "^9.7.1",
|
|
57
57
|
"exceljs": "^4.4.0",
|