@patterkit/play-helpers 0.13.2 → 0.14.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.
@@ -1,5 +1,5 @@
1
- "use strict";var Patterplay=(()=>{var Le=Object.defineProperty;var En=Object.getOwnPropertyDescriptor;var Cn=Object.getOwnPropertyNames;var Rn=Object.prototype.hasOwnProperty;var Dn=(r,e)=>{for(var t in e)Le(r,t,{get:e[t],enumerable:!0})},In=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Cn(e))!Rn.call(r,s)&&s!==t&&Le(r,s,{get:()=>e[s],enumerable:!(n=En(e,s))||n.enumerable});return r};var Pn=r=>In(Le({},"__esModule",{value:!0}),r);var kr={};Dn(kr,{Checkpoint:()=>fe,DEFAULT_ESTIMATE_SPEED:()=>oe,DEFAULT_PAD_AFTER:()=>_,Engine:()=>Re,Flow:()=>U,LINE_DURATION_MAX:()=>qe,LINE_DURATION_MIN:()=>Ge,PATTERPLAY_VERSION:()=>zt,Runner:()=>Ne,SAVE_SCHEMA:()=>Q,SUBTITLE_READING_MIN:()=>bt,applyLiveBundle:()=>ln,buildTagIndex:()=>Ee,compareStages:()=>J,createAudioResolver:()=>wn,createBundleInspector:()=>vn,createDebugLink:()=>an,createPropertyInspector:()=>bn,createStateLogger:()=>on,describeBundle:()=>De,deserializeState:()=>Pe,diffState:()=>se,effectiveGameData:()=>Yt,estimateLineDuration:()=>St,extensionDecls:()=>Xt,extensionsOf:()=>Zt,gameDataFields:()=>Qt,gameDataValue:()=>Ke,getProperty:()=>en,loadState:()=>Ye,nextStage:()=>z,resolveSceneRef:()=>we,saveState:()=>Qe,sceneAddressIndex:()=>Ve,serializeState:()=>Ie,setProperties:()=>nn,setProperty:()=>tn,snapshotState:()=>Ze,stageIndex:()=>W,versionInRange:()=>Kt});function te(r,e){return r!==void 0&&Object.prototype.hasOwnProperty.call(r,e)?r[e]:void 0}function G(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:G(r[2])};case"bin":return{kind:"binary",op:r[1],left:G(r[2]),right:G(r[3])};case"call":{let e=r.slice(2).map(G);return{kind:"call",name:r[1],args:e}}case"fd":return{kind:"flagdelta",sign:r[1],name:r[2]}}}var b=class extends Error{constructor(e){super(e),this.name="EvalError"}};function me(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=te(e.scopes,i.scope);if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):te(o,i.name);if(a===void 0){if(n.get(i.scope)==="throw")throw new b(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{if(i.name==="advance"&&!te(t.functions,i.name)){let a=i.args[0];if(i.args.length!==1||a===void 0)throw new b(`advance() takes exactly 1 argument, got ${i.args.length}`);let l=Ae(a,e);if(l===void 0)throw new b("advance() needs a quality reference (@scope.name of a quality property)");let c=B(s(a),l,"advance");return l[Math.min(c+1,l.length-1)]}let o=te(t.functions,i.name);if(!o)throw new b(`unknown function '${i.name}'`);return o.eval(i.args,{evaluate:s,ctx:e})}case"flagdelta":throw new b("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 b(`'not' requires a boolean operand, got ${typeof a}`);return!a}let o=s(i.operand);if(typeof o!="number")throw new b(`unary '-' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let f=s(i.left);if(typeof f!="boolean")throw new b(`'and' requires boolean operands, left is ${typeof f}`);if(!f)return!1;let u=s(i.right);if(typeof u!="boolean")throw new b(`'and' requires boolean operands, right is ${typeof u}`);return u}if(i.op==="or"){let f=s(i.left);if(typeof f!="boolean")throw new b(`'or' requires boolean operands, left is ${typeof f}`);if(f)return!0;let u=s(i.right);if(typeof u!="boolean")throw new b(`'or' requires boolean operands, right is ${typeof u}`);return u}let o=s(i.left),a=s(i.right),l=Ae(i.left,e),c=Ae(i.right,e),d=l??c;if(d!==void 0){if(l&&c&&!On(l,c)&&(i.op===">"||i.op===">="||i.op==="<"||i.op==="<="))throw new b(`'${i.op}' compares two different qualities, whose stage orders are unrelated`);switch(i.op){case">":return B(o,d,">")>B(a,d,">");case">=":return B(o,d,">=")>=B(a,d,">=");case"<":return B(o,d,"<")<B(a,d,"<");case"<=":return B(o,d,"<=")<=B(a,d,"<=");case"+":case"-":case"*":case"/":throw new b(`'${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 it(o,a);case"!=":return!it(o,a);case">":return q(o,a,">"),o>a;case">=":return q(o,a,">="),o>=a;case"<":return q(o,a,"<"),o<a;case"<=":return q(o,a,"<="),o<=a;case"+":if(typeof o=="number"&&typeof a=="number"||typeof o=="string"&&typeof a=="string")return o+a;throw new b(`'+' requires two numbers or two strings, got ${typeof o} and ${typeof a}`);case"-":return q(o,a,"-"),o-a;case"*":return q(o,a,"*"),o*a;case"/":if(q(o,a,"/"),a===0)throw new b("division by zero");return o/a}}}};return s(r)}function it(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 q(r,e,t){if(typeof r!="number"||typeof e!="number")throw new b(`'${t}' requires numeric operands, got ${typeof r} and ${typeof e}`)}function Ae(r,e){if(!(r.kind!=="scopedvar"||e.qualities===void 0))return e.qualities(r.scope,r.name)}function B(r,e,t){if(typeof r!="string")throw new b(`'${t}' on a quality compares stages, got ${typeof r}`);let n=e.indexOf(r);if(n<0)throw new b(`"${r}" is not a stage of this quality (stages: ${e.join(", ")})`);return n}var On=(r,e)=>r.length===e.length&&r.every((t,n)=>t===e[n]);function ne(r){if(Number.isNaN(r)||!Number.isFinite(r))return 0;let e=Math.trunc(r)%4294967296;return e<0?e+4294967296:e}function Be(r){let e=ne(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 Fe=r=>Array.isArray(r)?r:r.stages??[],Nn=r=>Array.isArray(r)?"flags":r==null?"nothing":typeof r;function W(r,e){return typeof e=="string"?Fe(r).indexOf(e):-1}function Te(r,e){if(typeof e!="string")throw new b(`a stage is a name, got ${Nn(e)}`);let t=r.indexOf(e);if(t<0)throw new b(`"${e}" is not a stage of this quality (stages: ${r.join(", ")})`);return t}function J(r,e,t){let n=Fe(r),s=Te(n,e)-Te(n,t);return s<0?-1:s>0?1:0}function z(r,e){let t=Fe(r);return t[Math.min(Te(t,e)+1,t.length-1)]}function re(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 Ln={name:"check_flags",count:r=>Math.max(1,r.args.length-1)},An=[Ln];function ot(r,e,t){let n=t?.countingCalls??An;return ye(r,t?.want??!0,e,n)}function ye(r,e,t,n){if(r.kind==="binary"&&(r.op==="and"||r.op==="or")){let s=ye(r.left,e,t,n),i=ye(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 ye(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}function se(r,e){let t=[],n=new Set([...Object.keys(r),...Object.keys(e)]);for(let s of[...n].sort()){let i=r[s],o=e[s];JSON.stringify(i)!==JSON.stringify(o)&&t.push({path:s,from:i,to:o})}return t}var at=r=>r===void 0?"<unset>":JSON.stringify(r),lt=r=>r.pathPrefix??r.bag.pathPrefix;function $e(r,e={}){let t=e.sink??(f=>console.log(f)),n=e.label??"",s=f=>{t(`${n}${f.path}: ${at(f.from)} -> ${at(f.to)}`)},i=()=>{let f={};for(let u of r.mounts()){let p=lt(u);for(let[y,g]of Object.entries(u.bag.values))f[p+y]=g}return Object.assign(f,r.extra?.()??{}),structuredClone(f)},o=i(),a=[],l=[],c=(f,u)=>u.onAudit(p=>{let y=structuredClone({path:f+p.name,from:p.prev,to:p.next});s(y),a.push(y),o[y.path]=structuredClone(p.next)}),d=()=>{let f=r.mounts();if(!(l.length===f.length&&f.every((p,y)=>l[y].bag===p.bag))){for(let p of l)p.off();l=f.map(p=>({bag:p.bag,off:c(lt(p),p.bag)}))}};return d(),{snapshot:i,capture(){let f=i(),u=se(o,f);for(let y of u)s(y);let p=[...a,...u];return a=[],o=f,d(),p},dispose(){for(let f of l)f.off();l=[],a=[]}}}var M=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??K(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])=>dt(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);re(o,a,{noneChosen:o.type==="enum"&&o.default===""})||(this.values[i]=structuredClone(K(o)),s.push({name:i,value:a}))}return s}};function dt(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??K(r),...r.values!==void 0?{values:r.values}:{},...r.stages!==void 0?{stages:r.stages}:{},writable:t??r.writable??!0}}var Bn=r=>r.toLowerCase(),Me=1,be=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 M(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??Bn,a=new Map;for(let l of n)a.set(o(l.name),l);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,...dt(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 l=n.get(o);return l?i.get(o)?.get(Tn(l)(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 ct(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=ct(s);if(i.length===0)continue;let o=new Map;for(let[a,l]of i)o.set(a,{type:l.type,enumValues:l.values,...l.stages!==void 0?{stages:l.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:Me,scopes:this.save()}}loadFragment(e){if(e.version!==Me)throw new Error(`unsupported owned-state fragment version ${e.version} (supported: ${Me})`);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 ct(r){return r.kind==="foreign"?[...r.decls.entries()]:r.bag.declarations().map(e=>[r.bag.normalise(e.name),e])}function Tn(r){return r.kind==="foreign"?r.norm:e=>r.bag.normalise(e)}function K(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 pt=[{token:"patter",engine:"Patterplay",means:"Patter's shared globals"},{token:"story",engine:"Storylet Engine",means:"the Storylet Engine's shared @story properties"}];function ie(r){return r.ctx.host??{}}var je={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(r,e){if(r.length!==2)throw new b("random(a, b) requires exactly 2 arguments");let t=ie(e).nextRandom;if(!t)throw new b("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 b("random(a, b) arguments must be numbers");if(!Number.isInteger(n)||!Number.isInteger(s))throw new b("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:ft("check_flags"),eval(r,e){let t=ut(r[0],e,"check_flags");for(let n=1;n<r.length;n++){let s=r[n];if(s.kind!=="flagdelta")throw new b("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:ft("set_flags"),eval(r,e){let t=[...ut(r[0],e,"set_flags")];for(let n=1;n<r.length;n++){let s=r[n];if(s.kind!=="flagdelta")throw new b("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:ve("visits"),eval:(r,e)=>ie(e).visits?.(Se(r,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:ve("seen"),eval:(r,e)=>(ie(e).visits?.(Se(r,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:ve("patter_visits"),eval:(r,e)=>ie(e).patterVisits?.(Se(r,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:ve("patter_seen"),eval:(r,e)=>(ie(e).patterVisits?.(Se(r,e,"patter_seen"))??0)>0}}},Zr=pt.map(r=>r.token).filter(r=>r!=="patter"&&r!=="scene");function gt(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 Se(r,e,t){let n=e.evaluate(r[0]);if(typeof n!="string")throw new b(`${t}(id) requires a string node id`);return n}function ve(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 ut(r,e,t){if(!r)throw new b(`${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 b(`${t}() first argument must be a flags property`)}function ft(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 Fn=/^@[A-Za-z0-9_.]+$/;function*$n(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:Fn.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 Mn(r){return Array.isArray(r)?r.join(", "):typeof r=="boolean"?r?"true":"false":String(r)}function jn(r){return r===" "||r===" "||r===`
2
- `||r==="\r"||r==="\f"||r==="\v"}function Vn(r){let e="",t=!1;for(let n of r){if(jn(n)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=n}return e}function ht(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?Vn(n):r}function mt(r,e){if(r.indexOf("{")<0)return r;let t="";for(let n of $n(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?"":Mn(s)}return t}function yt(r){return r.toLowerCase().replace(/['’]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function j(r,e){for(let t of r){e(t);let n=t.children;n&&j(n,e)}}function E(r){let e=r.gameId?.trim();return e||yt(r.name)}function Ve(r){let e=new Map;for(let[t,n]of Object.entries(r))e.set(E(n),t);return e}function we(r,e,t){return(t??Ve(r)).get(e)??(Object.hasOwn(r,e)?e:void 0)}var _=.6;var oe=1;var Gn=14,Ge=.5,qe=18,bt=1.5;var qn=[[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 St(r,e,t){let n=typeof t=="number"&&Number.isFinite(t)&&t>0?t:oe,s=0;for(let i of r??""){let o=i.codePointAt(0),a=1;for(let[l,c,d]of qn){if(o<l)break;if(o<=c){a=d;break}}s+=a}return Math.min(Math.max(s/(Gn*n),Ge),qe)}function xe(r){return`cast:${r}`}function ke(r){return`qualifier:${r}`}function vt(r,e){return`speaker:${r}:${e}`}var wt="speaker:pattern",xt="{name} ({qualifier})";function kt(r,e,t){return r.split("{name}").map(n=>n.split("{qualifier}").join(t)).join(e)}var _e={open:"[",close:"]"},Et="SFX",Q="patter/save@0",ae=4;function le(r){let e=new Set,t=[];for(let n of r)e.has(n)||(e.add(n),t.push(n));return t}function Ee(r){let e=new Map,t=(n,s)=>{let i=le([...s,...n.tags??[]]);if(e.set(n.id,i),n.type==="group"&&n.prompt&&e.set(n.prompt.id,le([...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,le([...i,...o.tags??[]]))};for(let n of Object.values(r.scenes)){let s=le(n.tags??[]);e.set(n.id,s);for(let i of n.blocks){let o=le([...s,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var Ct=r=>r.kind==="line"||r.kind==="text",ce=r=>typeof r=="number"&&Number.isFinite(r)?r:void 0;function Rt(r){let e=new Map,t=(i,o,a)=>{let l=i.kind==="gameEvent"?void 0:ce(i.padAfter),c=l??o;a&&c<0&&(c=0),e.set(i.id,l!==void 0?{own:l,resolved:c}:{resolved:c})},n=(i,o)=>{let a=ce(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 l=i.beats??[],c=-1;l.forEach((d,f)=>{Ct(d)&&(c=f)}),l.forEach((d,f)=>{Ct(d)&&t(d,a,f===c)})},s=ce(r.padAfterDefault)??_;for(let i of Object.values(r.scenes)){let o=ce(i.padAfterDefault)??s;for(let a of i.blocks){let l=ce(a.padAfterDefault)??o;for(let c of a.children)n(c,l)}}return e}var Dt=new WeakMap,It=new WeakMap;function _n(r){let e=It.get(r);return e||(e=Ee(r),It.set(r,e)),e}var Pt=new WeakMap;function Hn(r){let e=Pt.get(r);return e||(e=Rt(r),Pt.set(r,e)),e}var Ot=new WeakMap;function Un(r){let e=Ot.get(r);if(e)return e;e=new Map;for(let t of Object.values(r.scenes))for(let n of t.blocks)j(n.children,s=>{if(s.type==="group"&&s.selector==="choice")for(let i of s.children)e.set(i.id,s.id)});return Ot.set(r,e),e}var Nt=new WeakMap;function Wn(r){let e=Nt.get(r);if(e)return e;e=new Map;for(let t of Object.values(r.scenes))for(let n of t.blocks)j(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 Nt.set(r,e),e}function O(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 H(r,e){return r.tagIndex.get(e)?.slice()}var pe="Patter",de=r=>r.replace(/%/g,"%25").replace(/\//g,"%2F"),Jn=r=>r.replace(/%2F/g,"/").replace(/%25/g,"%"),Lt=Symbol("ownsRegistry"),At=Symbol("setupReported"),P={stage:r=>`patter/scene/${de(r)}`,flow:r=>`patter/flow/${de(r)}/`,flowGlobals:r=>`patter/flow/${de(r)}/patter`,flowScene:(r,e)=>`patter/flow/${de(r)}/scene/${de(e)}`},fe=class{constructor(e){this.journal=e}journal},Re=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 h of Object.keys(t))Kn.has(h)||n.push({node:h,message:h==="world"?'the engine option "world" has gone: bind the scope as hostScopes: { world }':`"${h}" isn't an engine option, so it's ignored`});let s=e.strings;this.allStrings=s,this.requestedLocale=t.locale,this.currentLocale=He(e,t.locale),this.currentLocale.problem&&n.push({node:t.locale,message:this.currentLocale.problem});let i=jt(s,this.currentLocale),o=s[e.locales.default]??{},a=e.localisation,l=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 c=new Map;for(let h of e.cast??[])h.displayName&&c.set(h.name,h.displayName);let d=new Map;for(let h of e.qualifiers??[])h?.gameId&&d.set(h.gameId,h.name);let f=new Map;for(let h of e.cast??[])for(let[x,S]of Object.entries(h.qualifierLabels??{}))typeof S=="string"&&f.set(`${h.name}\0${x}`,S);let u=e.speakerPattern??xt;this.defaultSeed=(t.seed??2654435769)>>>0;let p=new Map,y=new Map,g=new Map;for(let[h,x]of Object.entries(e.scenes)){this.sceneGameIdToId.set(E(x),h);let S=new Map;for(let D of x.blocks)y.set(D.id,{sceneId:h}),g.set(D.id,D),S.set(E(D),D.id),j(D.children,$=>p.set($.id,$));this.blockGameIdToId.set(h,S)}let w=e.properties??[],I=w.filter(h=>h.shared??!0).map($t),R=w.filter(h=>!(h.shared??!0)).map($t),L=new Set(I.map(h=>h.name.toLowerCase())),k=t.registry??new be,A=!t.registry||t[Lt]===!0,T=new M(I,{pathPrefix:"@patter."}),F=[],m=[];try{k.mountOwned("patter",T,{owner:pe}),m.push("patter");let h=new Set,x=e.scopeRegistry?.scopes??[];for(let[S,D]of Object.entries(t.hostScopes??{})){let $=x.find(he=>he.token===S);if(!$&&!(e.externalScopes??[]).includes(S)){let he=x.find(kn=>kn.token.toLowerCase()===S.toLowerCase());n.push({node:S,message:he?`hostScopes binds "${S}", which this bundle doesn't declare: it declares "${he.token}", and a scope's token is case-sensitive`:`hostScopes binds "${S}", which this bundle doesn't declare`})}let xn=($?.declarations??[]).map(Ht);k.defineForeign(S,D,xn,{writable:$?.writable??!0,owner:pe}),m.push(S),h.add(S)}for(let S of A?e.scopeRegistry?.scopes??[]:[]){if(h.has(S.token)||k.has(S.token))continue;let D=(S.declarations??[]).map($=>Xn($,S.writable));k.defineOwned(S.token,D,{owner:pe}),m.push(S.token),F.push(S.token)}}catch(h){for(let x of m)k.remove(x,{keep:!0});throw h}let C=new Map;for(let[h,x]of Object.entries(e.scenes)){let S=new Set((x.sceneProps??[]).filter(D=>D.shared??!1).map(D=>D.name.toLowerCase()));C.set(h,S)}if(this.host={logEnabled:t.log??!1,tracing:t.log??!1,emitEngine:(h,x,S)=>this.emitEngine(h,x,S),bundle:e,emitIds:l,strings:i,defaultStrings:o,castDisplay:c,qualifierDisplay:d,speakerLabels:f,speakerPattern:u,nodeIndex:p,blockIndex:y,blockById:g,sceneGameIdToId:this.sceneGameIdToId,blockGameIdToId:this.blockGameIdToId,tagIndex:_n(e),padIndex:Hn(e),registry:k,ownsRegistry:A,patterBag:T,hostScopes:F,patterSharedDecls:I,patterLocalDecls:R,patterSharedNames:L,sceneSharedNames:C,sharedVisits:new Map,qualityLadders:new Map,sharedSelectors:new Map,stageBags:new Map,journal:null,customRng:t.rng,onDryChoice:t.onDryChoice,steer:Mt(t.steer,n),onError:t.onError??(h=>console.warn(h.kind==="setup"?`Patterplay: ${h.message}`:h.kind==="save"?`Patterplay: flow '${h.flow}': ${h.message}`:`Patterplay: ${h.kind} on ${h.node} in flow '${h.flow}' failed, played through: ${h.message}`)),reportRefits:()=>{let h=k.takeMisfits(x=>x==="patter"||x.startsWith("patter/")||F.includes(x));if(h.length!==0)if(t.onRefit)t.onRefit(h);else for(let x of h)console.warn(`Patterplay: the save's ${x.scope}.${x.name} was ${JSON.stringify(x.value)}, which no longer fits its declaration; it is back at its default`)},replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??_e).open,captionClose:(e.closedCaptions??_e).close,captionCharacter:e.closedCaptions?.character||Et,refSplitCache:new Map,refSplitRevision:k.revision},this.host.reportRefits(),t[At]!==!0)for(let h of n)this.reportSetup(h.node,h.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(He(this.host.bundle,e)),this.currentLocale.problem&&this.reportSetup(e,this.currentLocale.problem)}useLocale(e){this.currentLocale=e,this.host.strings=jt(this.allStrings,e)}replaceStrings(e){this.allStrings=e.strings;let t=this.currentLocale.problem;this.useLocale(He(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=c=>(c.setClosedCaptions(this.host.captionsOn),c),s=this.requestedLocale,i=(c=!1)=>new r(e,{...this.creationOptions,...s!==void 0?{locale:s}:{},steer:this.host.steer,registry:this.host.registry,[Lt]:this.host.ownsRegistry,[At]:c}),o=new Set(["patter",...this.host.hostScopes]),a=this.host.ownsRegistry?void 0:Object.fromEntries(Object.entries(this.host.registry.save()).filter(([c])=>o.has(c)||c.startsWith("patter/")));this.release(!0),a&&this.host.registry.load(a,{keepParked:!0,refit:!0});let l=i();try{return l.loadGame(t),n(l)}catch{l.release(!0);let c=this.host.ownsRegistry?t.registry:a;c&&this.host.registry.load(c,{keepParked:!0,refit:!0});let d=i(!0);for(let[f,u]of Object.entries(t.flows)){let p=u.cursor.currentSceneId;try{d.openFlow(f,p!==null?{scene:p}:{})}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=Mt(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 U(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=Ue(this.host,e);if(n===void 0)throw new Error(`unknown scene: ${e}`);if(t===void 0)return{sceneId:n};let s=We(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 Ue(this.host,e)??e}resolveBlockRef(e,t){if(t!=null)return e==null?t:We(this.host,e,t)}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?E(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?E(t):void 0}tagsForBeat(e){return H(this.host,e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?H(this.host,t):void 0)??[]}tagsForBlock(e,t){let n=this.resolveSceneRef(e),s=this.resolveBlockRef(n,t);return(s!=null?H(this.host,s):void 0)??[]}gameDataForScene(e){let t=this.resolveSceneRef(e),n=t!=null?this.host.bundle.scenes[t]:void 0;return O(n?.gameData)??{}}gameDataForBlock(e,t){let n=this.resolveBlockRef(this.resolveSceneRef(e),t),s=n!=null?this.host.blockById.get(n):void 0;return O(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)Bt(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 Bt(i.children,o),[...o]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...E(e)?{gameId:E(e)}:{},name:e.name,...Tt(e.gameData),...V(e.extensions),...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...E(t)?{gameId:E(t)}:{},name:t.name,...Tt(t.gameData),...V(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)j(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=H(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[xe(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[ke(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??_,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=O(e.gameData)),e.extensions&&Object.keys(e.extensions).length&&(n.extensions=e.extensions),t&&t.length&&(n.tags=t),n}tagsField(e){let t=H(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 fe(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:ae,...t.snapshot(),...er(e,this.host.registry.save())}}restoreFlow(e,t){this.refuseInCheckpoint("restoreFlow");let n=t.version;if(n!==3&&n!==ae)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=P.flow(e);this.host.registry.discardParked(i),this.host.registry.load(Zn(e,t),{keepParked:!0,refit:!0});let o=new U(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(P.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(P.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);_t(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 W(this.ladderOf(e),t)}compareStages(e,t,n){return J(this.ladderOf(e),t,n)}nextStage(e,t){return z(this.ladderOf(e),t)}ladderOf(e){let{scope:t,name:n}=this.splitShared(e),s=Yn(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:K(e),writable:e.writable??!0}))}splitShared(e){let t=Ut(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:ae,...this.host.ownsRegistry?{registry:this.host.registry.save()}:{},sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:Gt(this.host.sharedSelectors),flows:e}}loadGame(e){this.refuseInCheckpoint("loadGame");let t=e.version;if(t!==3&&t!==ae)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(P.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 qt(e.sharedSelectors))this.host.sharedSelectors.set(o,a);for(let[o,a]of Object.entries(e.flows)){let l=new U(o,this.host,this.defaultSeed);l.restore(a),this.flowsById.set(o,l)}this.host.reportRefits()}},U=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=ne(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 ue(this.host,"patter",()=>[...this.host.patterSharedDecls,...this.host.patterLocalDecls]).get(n);if(e==="scene"){let s=this.currentSceneId;return s==null?void 0:ue(this.host,`scene/${s}`,()=>this.host.bundle.scenes[s]?.sceneProps).get(n)}return this.registryQualities?.(e,t)??ue(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(P.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=Ue(this.host,e);if(n===void 0)return!1;let s;return t!==void 0&&(s=We(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:l,beatIndex:c,pendingChoice:d,pendingPrompt:f,pendingPromptOwnerId:u}=this,p=this.stack.map(y=>({...y}));e.undo.push(()=>{Object.assign(this,{rngState:t,started:n,flowEnded:s,dryChoice:i,ranDry:o,currentSceneId:a,activeSnippet:l,beatIndex:c,pendingChoice:d,pendingPrompt:f,pendingPromptOwnerId:u,stack:p})})}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=Wn(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:O(t.gameData),...V(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 W(this.ladderOf(e),t)}compareStages(e,t,n){return J(this.ladderOf(e),t,n)}nextStage(e,t){return z(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`);_t(this.host,s,i,t,this.currentSceneId)}let o=this.host.journal;if(s==="patter"){if(o){let a=this.host.patterSharedNames.has(i),l=a?this.host.patterBag.get(i):this.local.get(i),c=this.local;l!==void 0&&o.undo.push(a?()=>this.host.registry.set("patter",i,l):()=>c.set(i,l))}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),l=a?.get(i);a&&l!==void 0&&o.undo.push(()=>a.set(i,l))}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=Un(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:O(n.gameData)}:{}}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,...this.pendingPrompt?.shown?{pendingPrompt:zn(this.pendingPrompt.shown)}:{},selectors:Gt(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=ne(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,l=this.childrenOf(a.containerId),c=!l&&o!==void 0?this.host.nodeIndex.get(o):void 0;if(c?.type==="group"&&c.selector==="choice"){n={node:t.activeSnippetId??t.pendingChoice?.groupId??a.containerId,instead:`option ${a.containerId} has gone, so choice ${c.id} is offered again`,reoffer:c};break}let d=i!==void 0?l?.findIndex(f=>f.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=qt(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"),l=o.secretUntilEligible===!0;!a&&l||(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(l=>({id:l.id,eligible:this.holds(l)})),n=e.children.filter((l,c)=>t[c].eligible),s=e.options?.order??"sequential",i=e.options?.exhaust??"once",o=l=>(this.host.tracing&&this.emit({type:"select",group:e.id,selector:e.selector??"default",...e.selector==="sequence"?{order:s,exhaust:i}:{},children:t,picked:l?.id??null}),l),a=null;if(n.length>0){let l=this.selectorState(e);switch(e.selector){case"branch":a=n[0];break;case"sequence":a=s==="shuffle"?this.pickShuffle(n,i,l):s==="specificity"?this.pickSpecificity(n,i,l):this.pickSequential(n,i,l);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(l=>({...l})),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(l=>l.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(u=>u.id),a=new Set(e.map(u=>u.id));if(n.bag===void 0&&(n.bag=o()),!n.bag.some(u=>a.has(u))){if(t==="once")return null;if(i){let u=e[s-1];return n.last=u.id,u}if(n.bag=o(),n.bag.length===0)return null}let l=n.bag.filter(u=>a.has(u)),c=n.last!==void 0&&l.length>1?l.indexOf(n.last):-1,d=Math.floor(this.rng()*(c>=0?l.length-1:l.length));c>=0&&d>=c&&d++;let f=l[d];return n.bag.splice(n.bag.indexOf(f),1),n.last=f,e.find(u=>u.id===f)}pickSpecificity(e,t,n){let s=e;if(t!=="repeat"){n.bag===void 0&&(n.bag=e.map(d=>d.id));let c=new Set(n.bag);if(s=e.filter(d=>c.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(c=>{let d=this.specScore(c);return d>i&&(i=d),{c,s:d}}).filter(c=>c.s===i).map(c=>c.c),l;if(a.length===1)l=a[0];else{let c=n.last!==void 0?a.findIndex(f=>f.id===n.last):-1,d=Math.floor(this.rng()*(c>=0?a.length-1:a.length));c>=0&&d>=c&&d++,l=a[d]}return t!=="repeat"&&(n.bag=n.bag.filter(c=>c!==l.id)),n.last=l.id,l}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0,e):0}matchedSpec(e,t,n){return ot(e,i=>{try{return Vt(me(i,this.context(),je))}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 Vt(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 me(this.conditionAst(e),this.context(),je)}conditionAst(e){let t=Dt.get(e);return t||(t=G(e.ast),Dt.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=Be(this.rngState),t=e.next();return this.rngState=e.state(),t};beatResult(e){let t=H(this.host,e.id),n=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:O(e.gameData),...V(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:O(e.gameData),...V(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)),l=i&&a.length===0;return{type:"line",id:e.id,text:a,character:l?void 0:e.character,characterName:l?void 0:this.resolveCharacterName(e.character),direction:l?void 0:e.direction,qualifier:l?void 0:e.qualifier,qualifierName:l?void 0:this.resolveQualifierName(e.qualifier),speakerLabel:l?void 0:Ce(this.host,e.character,e.qualifier),padAfter:this.padOf(e.id),...this.spokenOf(e),gameData:O(e.gameData),...V(e.extensions),...n}}}}interpolate(e){return mt(e,t=>this.getProperty(t))}stripCaptions(e){return ht(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??oe,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=H(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:O(e.gameData),...V(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:O(e.gameData),...V(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 j(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=xe(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}padOf(e){return this.host.padIndex.get(e)?.resolved??_}resolveQualifierName(e){if(e===void 0||this.host.emitIds)return;let t=ke(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.qualifierDisplay.get(e)}splitRef(e){return Ut(this.host,e)}newLocal(){return new M(this.host.patterLocalDecls,{pathPrefix:"@patter."})}mountLocal(){this.local=this.newLocal();let e=P.flowGlobals(this.id);this.host.registry.mountOwned(e,this.local,{owner:pe}),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 M(n.filter(c=>!t.has(c.name.toLowerCase())),{pathPrefix:"@scene."}),a=P.flowScene(this.id,e),l=Ft(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,l?{keep:!0}:void 0),this.registered.delete(a),this.sceneBags.delete(e))})}if(!this.host.stageBags.has(e)){let o=new M(n.filter(l=>t.has(l.name.toLowerCase())),{pathPrefix:"@scene."}),a=Ft(this.host.registry,P.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(P.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,K(n))}}};function Bt(r,e){j(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=l=>(n?void 0:r.strings[l])??r.defaultStrings[l],i=s(xe(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(vt(e,t))??o;let a=s(ke(t))??r.qualifierDisplay.get(t)??t;return kt(s(wt)??r.speakerPattern,i,a)}function Tt(r){return r&&Object.keys(r).length?{gameData:O(r)}:{}}function V(r){return r&&Object.keys(r).length?{extensions:r}:{}}function zn(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 Gt(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 qt(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 Ft(r,e,t,n){let s=n?JSON.stringify(t.save()):"";return r.mountOwned(e,t,{owner:pe}),n&&JSON.stringify(t.save())!==s}function $t(r){return{name:r.name,type:r.type,values:r.values,stages:r.stages,default:r.default}}var Kn=new Set(["rng","seed","locale","hostScopes","registry","replayPromptOnChoose","closedCaptions","onDryChoice","steer","onError","onRefit","log"]);function Mt(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 He(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=l=>l.toLowerCase().replace(/_/g,"-"),i=n.find(l=>s(l)===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(l=>s(l)===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 jt(r,e){return e.table!==void 0?r[e.table]??{}:{}}function _t(r,e,t,n,s){let i=l=>l?.find(c=>c.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 l=r.bundle.scopeRegistry?.scopes.find(c=>c.token===e);if(!l||l.declarations===void 0)return;o=i(l.declarations)}let a=`@${e}.${t}`;if(o===void 0)throw new Error(`no property at "${a}": the content declares no ${a}`);if(!re(o,n,{noneChosen:o.type==="enum"&&o.default===""}))throw new Error(`"${a}" takes ${Qn(o)}; ${JSON.stringify(n)} doesn't fit`)}function Qn(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 ue(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 Yn(r,e,t){let n=t.toLowerCase();return e==="patter"?ue(r,"patter",()=>[...r.patterSharedDecls,...r.patterLocalDecls]).get(n):r.registry.toEvalContext().qualities?.(e,t)??ue(r,`host/${e}`,()=>r.bundle.scopeRegistry?.scopes.find(s=>s.token===e)?.declarations).get(n)}function Ht(r){return{name:r.name,type:r.type,values:r.values,stages:r.stages,default:r.default,writable:r.writable}}function Xn(r,e){let t=Ht(r),n=r.writable??e;return n===void 0?t:{...t,writable:n}}function Ue(r,e){return we(r.bundle.scenes,e,r.sceneGameIdToId)}function We(r,e,t){return r.blockGameIdToId.get(e)?.get(t)??(r.blockIndex.get(t)?.sceneId===e?t:void 0)}function Ut(r,e){r.refSplitRevision!==r.registry.revision&&(r.refSplitCache.clear(),r.refSplitRevision=r.registry.revision);let t=r.refSplitCache.get(e);return t||(t=gt(e,n=>n==="scene"||r.registry.has(n)||(r.bundle.externalScopes?.includes(n)??!1)),r.refSplitCache.set(e,t)),t}function Zn(r,e){let t={};e.scopes?.patter&&(t[P.flowGlobals(r)]=e.scopes.patter);for(let[n,s]of Object.entries(e.sceneBags??{}))t[P.flowScene(r,n)]=s;return t}function er(r,e){let t={scopes:{},sceneBags:{}},n=P.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[Jn(o.slice(6))]=i)}return t}function Vt(r){return typeof r=="boolean"?r:typeof r=="number"?r!==0:typeof r=="string"?r!=="":r.length>0}var zt="0.45.0",tr=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;function Je(r){let e=typeof r=="string"?tr.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 Jt(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 Kt(r,e,t){let n=Je(r),s=Je(e),i=Je(t);return!n||!s||!i?!1:Jt(n,s)>=0&&Jt(n,i)<0}var nr=(r,e)=>r.shared??e;function ze(r,e){return{name:r.name,type:r.type,hasDefault:r.default!==void 0,...r.default!==void 0?{default:r.default}:{},shared:nr(r,e)}}function rr(r){return{name:r.name,type:r.type,hasDefault:r.default!==void 0,...r.values?{values:[...r.values]}:{},...r.purpose?{purpose:r.purpose}:{}}}function sr(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 De(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=E(o);t.push({gameId:a,name:o.name,blocks:o.blocks.map(l=>({gameId:E(l),name:l.name}))});for(let l of o.blocks)sr(l,e);o.sceneProps?.length&&n.push({gameId:a,properties:o.sceneProps.map(l=>ze(l,!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=>ze(a,!0))})),i=Object.entries(r.gameDataFields??{}).filter(([,o])=>(o?.length??0)>0).map(([o,a])=>({kind:o,fields:(a??[]).map(rr)}));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=>ze(o,!0)),scene:n},gameData:i,counts:e}}var ge=(r,e)=>Object.prototype.hasOwnProperty.call(r,e);function Qt(r,e){return r.gameDataFields?.[e]??[]}function Ke(r,e,t){return e&&ge(e,t)?e[t]:r.find(n=>n.name===t)?.default}function Yt(r,e){let t={};for(let n of r){let s=Ke(r,e,n.name);s!==void 0&&(t[n.name]=s)}for(let[n,s]of Object.entries(e??{}))ge(t,n)||(t[n]=s);return t}function Xt(r,e,t){let n=r.extensions!==void 0&&ge(r.extensions,e)?r.extensions[e]:void 0;return n!==void 0&&ge(n.fields,t)?n.fields[t]??[]:[]}function Zt(r,e,t=""){let n=o=>({...o?.extensions??{}}),s=Object.values(r.scenes??{}),i=o=>(ge(r.scenes??{},o)?r.scenes[o]:void 0)??s.find(a=>E(a)===o);switch(e){case"project":{let o={};for(let[a,l]of Object.entries(r.extensions??{}))l.project!==void 0&&(o[a]=l.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??[],l=t.slice(o+1);return n(a.find(c=>c.id===l)??a.find(c=>E(c)===l))}case"snippet":case"option":case"line":case"text":case"gameEvent":{let o,a=(l,c)=>{for(let d of l??[]){if(o!==void 0)return;if(d.type==="group"){if(c&&d.id===t&&e==="option"){o=d;return}if(c&&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 f=(d.beats??[]).find(u=>u.id===t);if(f!==void 0){f.kind===e&&(o=f);return}}};for(let l of s)for(let c of l.blocks??[])o===void 0&&a(c.children??[],!1);return n(o)}default:return{}}}function Qe(r){return{schema:Q,save:r.saveGame()}}function Ye(r,e){if(!e||e.schema!==Q||!e.save)throw new Error(`loadState: not a ${Q} envelope`);r.loadGame(e.save)}function Ie(r){return JSON.stringify(Qe(r))}function Pe(r,e){Ye(r,JSON.parse(e))}function en(r,e){return r.getProperty(e)}function tn(r,e,t){r.setProperty(e,t)}function nn(r,e){for(let[t,n]of Object.entries(e))r.setProperty(t,n)}function Ze(r){let e={};for(let t of rn(r)){let n=t.pathPrefix??t.bag.pathPrefix;for(let[s,i]of Object.entries(t.bag.save()))e[`${n}${s}`]=i}return Object.assign(e,sn(r)),e}function rn(r){return[...r.listBags(),...r.flows().flatMap(e=>e.listBags())]}function ir(r){switch(r.type){case"line":return`line ${r.character??"?"}: ${JSON.stringify(r.text)}${Xe(r.gameData)}`;case"text":return`text: ${JSON.stringify(r.text)}${Xe(r.gameData)}`;case"gameEvent":return`game event ${r.id}${Xe(r.gameData)}`;case"choice":return`choice (${r.options.length} option${r.options.length===1?"":"s"})`;case"end":return"end"}}var Xe=r=>r?` gameData=${JSON.stringify(r)}`:"";function sn(r){let e={};for(let[t,n]of Object.entries(r.getVisitCounts()))e[`visit:${t}`]=n;for(let t of r.flows())for(let[n,s]of Object.entries(t.getVisitCounts()))e[`${t.id}/visit:${n}`]=s;return e}function on(r,e={}){let t=e.label?`[${e.label}] `:"",n=$e({mounts:()=>rn(r),extra:()=>sn(r)},{sink:e.sink,label:t});return{snapshot:()=>Ze(r),capture:()=>n.capture(),dispose:()=>n.dispose(),logStep(s){(e.sink??(i=>console.log(i)))(`${t}${ir(s)}`)}}}var or="unhandled";function an(r){let e=r.url??"ws://127.0.0.1:4471",t=r.WebSocket??globalThis.WebSocket,n=new Set,s=[],i=null,o=!1,a=r.build,l=()=>{if(!(!i||i.readyState!==1)){for(let u of s)try{i.send(u)}catch{}s=[]}},c=u=>{o||!i||i.readyState>1||(s.push(JSON.stringify(u)),l())};if(!t)return{flowOpened(){},observe(){},flowClosed(){},setBuild(){},replyPlay(){},close(){o=!0},state:"closed",build:a,url:e};let d=(u,p)=>{c({t:"played",id:u,started:p.started===!0,...typeof p.reason=="string"?{reason:p.reason}:{},...typeof p.detail=="string"?{detail:p.detail}:{}})},f=()=>{let u=JSON.stringify({t:"hello",v:1,build:a,project:r.project,flows:[...n]});try{i?.send(u)}catch{}};try{i=new t(e),i.addEventListener("open",()=>{f(),l()}),i.addEventListener("message",u=>{if(typeof u.data!="string")return;let p;try{p=JSON.parse(u.data)}catch{return}if(!(p===null||typeof p!="object")){if(p.t==="bundle")r.onBundle&&typeof p.build=="string"&&typeof p.data=="string"&&r.onBundle({build:p.build,data:p.data});else if(p.t==="play"){let y=ar(p);if(!y)return;if(!r.onPlay){d(y.id,{started:!1,reason:or});return}try{r.onPlay(y)}catch{}}}}),i.addEventListener("error",()=>{}),i.addEventListener("close",()=>{i=null,s=[]})}catch{i=null}return{flowOpened(u){n.add(u),c({t:"flowOpen",flow:u})},flowClosed(u){n.delete(u),c({t:"flowClose",flow:u})},observe(u,p,y,g,w){n.has(u)||(n.add(u),c({t:"flowOpen",flow:u})),c({t:"frame",flow:u,sceneId:p,beatId:y,type:g,choiceId:w})},replyPlay:d,setBuild(u){o||u===a||(a=u,i&&i.readyState===1&&f())},close(){o=!0,s=[];try{i?.close()}catch{}i=null},get state(){return o||!i?"closed":i.readyState===1?"connected":"connecting"},get build(){return a},url:e}}function ar(r){let{id:e,sceneId:t,blockId:n}=r;return typeof e!="string"||e===""||typeof t!="string"||t===""||typeof n!="string"||n===""?null:{id:e,sceneId:t,blockId:n,takeOver:r.takeOver===!0,...typeof r.build=="string"&&r.build!==""?{build:r.build}:{}}}function ln(r,e,t){let n=JSON.parse(t);return e.content.structureHash!==void 0&&e.content.structureHash===n.content.structureHash?(r.replaceStrings(n),{engine:r,bundle:n,kind:"text"}):{engine:r.hotSwap(n),bundle:n,kind:"structure"}}function lr(r,e){r.textContent="";let t=/\u0002([^\u0003]*)\u0003/g,n=0,s;for(;(s=t.exec(e))!==null;){s.index>n&&r.append(e.slice(n,s.index));let i=document.createElement("strong");i.textContent=s[1]??"",r.append(i),n=s.index+s[0].length}n<e.length&&r.append(e.slice(n))}var nt=!1,cn=!1,un,cr=350,et=6,dn=7,X=null,Z=0,Oe=null,dr=null;function fn(){if(X)return X;let r=document.createElement("div");return r.className="tooltip",r.setAttribute("role","tooltip"),r.hidden=!0,document.body.appendChild(r),X=r,r}var pr=r=>r instanceof HTMLElement?r.getBoundingClientRect():r;function ur(r){let e=fn(),t=pr(r),n=e.getBoundingClientRect(),s=t.top-n.height-dn;s<et&&(s=t.top+t.height+dn);let i=t.left+t.width/2-n.width/2;i=Math.max(et,Math.min(i,window.innerWidth-n.width-et)),e.style.left=`${Math.round(i)}px`,e.style.top=`${Math.round(s)}px`}function fr(r){let e=r.dataset.tip;e&&gr(r,e)}function gr(r,e){if(un?.())return;let t=fn(),n=(r instanceof HTMLElement?r.closest("dialog[open]"):null)??document.body;t.parentElement!==n&&n.appendChild(t),Oe=r instanceof HTMLElement?r:null,lr(t,e),t.hidden=!1,t.classList.remove("show"),t.offsetWidth,ur(r),t.classList.add("show")}function Y(){Z&&(window.clearTimeout(Z),Z=0),Oe=null,dr=null,X&&(X.hidden=!0,X.classList.remove("show"))}function pn(r){r!==Oe&&(Z&&window.clearTimeout(Z),Z=window.setTimeout(()=>fr(r),cr))}function hr(){yr()}function mr(){cn||(cn=!0,setTimeout(()=>{nt||typeof document>"u"||document.querySelector("[data-tip]")&&console.warn("app-shell: something set `data-tip` but no tooltip host is mounted, so those rollovers will not draw. Call initTooltips() once per window.")},0))}var tt=r=>r instanceof Element?r.closest("[data-tip]"):null;function yr(r={}){r.suppressed!==void 0&&(un=r.suppressed),!nt&&(nt=!0,document.addEventListener("pointerover",e=>{let t=tt(e.target);t&&pn(t)}),document.addEventListener("pointerout",e=>{let t=tt(e.target);if(!t)return;let n=e.relatedTarget;n instanceof Node&&t.contains(n)||Y()}),document.addEventListener("focusin",e=>{let t=tt(e.target);t&&pn(t)}),document.addEventListener("focusout",()=>Y()),document.addEventListener("pointerdown",()=>Y(),!0),document.addEventListener("scroll",()=>{Oe&&Y()},!0),document.addEventListener("keydown",e=>{e.key==="Escape"&&Y()}),window.addEventListener("blur",()=>Y()))}function gn(r,e,...t){let n=document.createElement(r),s=typeof e=="string"?{className:e}:e??{};s.className&&(n.className=s.className),s.text!==void 0&&s.text!==null&&(n.textContent=s.text),s.title!==void 0&&(n.title=s.title),s.tip!==void 0&&(n.dataset.tip=s.tip,n.setAttribute("aria-label",s.tip),hr()),s.onClick&&n.addEventListener("click",s.onClick);for(let i of t)i!=null&&n.append(i);return mr(),n}function hn(r){let e=r.default;if(e!=null)return typeof e=="boolean"?e?"True":"False":Array.isArray(e)?e.length===0?"none":e.join(", "):e===""?"none":String(e);switch(r.type){case"boolean":return"False";case"number":return"0";case"enum":return r.values?.[0]??"none";case"quality":return r.stages?.[0]??"first stage";case"flags":return"none";default:return"empty"}}var mn=r=>`default (${hn(r)})`;function rt(r){let e=r.doc===void 0?gn:(a,l)=>{let c=r.doc.createElement(a);return c.className=l.className,l.text!==void 0&&(c.textContent=l.text),l.tip!==void 0&&(c.title=l.tip,c.setAttribute("aria-label",l.tip)),l.onClick&&c.addEventListener("click",l.onClick),a==="button"&&(c.type="button"),c},t=e("span",{className:"seg shell-rungs"}),n=r.decl??{type:"quality",stages:r.stages},s=r.value===void 0,i=typeof n.default=="string"&&r.stages.includes(n.default)?n.default:r.stages[0],o=r.onPick===void 0;r.onClear&&t.append(e("button",{className:`seg-opt shell-rung shell-rung-default${s?" on":""}`,text:mn(n),tip:s?"Not set here: the declared default holds":"Clear the value, back to the default",onClick:()=>{s||r.onClear()}}));for(let a of r.stages){let l=r.value===a,c=s&&a===i,d=e(o?"span":"button",{className:`seg-opt shell-rung${l?" on":""}${c?" fallback":""}`,text:a,tip:l?"The current stage":c?"The stage it falls back to":o?a:r.pickTip?.(a)??`Set to "${a}"`,...o?{}:{onClick:()=>{l||r.onPick(a)}}});t.append(d)}return!s&&!r.stages.includes(r.value)&&t.append(e("span",{className:"seg-opt shell-rung stray on",text:r.value,tip:`"${r.value}" is not one of the stages: pick the one it belongs at now`})),t}var yn="pp-inspector-style",br=`
1
+ "use strict";var Patterplay=(()=>{var Ne=Object.defineProperty;var kn=Object.getOwnPropertyDescriptor;var Cn=Object.getOwnPropertyNames;var Rn=Object.prototype.hasOwnProperty;var Dn=(r,e)=>{for(var t in e)Ne(r,t,{get:e[t],enumerable:!0})},In=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Cn(e))!Rn.call(r,s)&&s!==t&&Ne(r,s,{get:()=>e[s],enumerable:!(n=kn(e,s))||n.enumerable});return r};var Pn=r=>In(Ne({},"__esModule",{value:!0}),r);var Er={};Dn(Er,{Checkpoint:()=>fe,DEFAULT_ESTIMATE_SPEED:()=>oe,DEFAULT_PAD_AFTER:()=>_,Engine:()=>Re,Flow:()=>U,LINE_DURATION_MAX:()=>qe,LINE_DURATION_MIN:()=>Ge,PATTERPLAY_VERSION:()=>zt,Runner:()=>Le,SAVE_SCHEMA:()=>Q,SUBTITLE_READING_MIN:()=>bt,applyLiveBundle:()=>ln,buildTagIndex:()=>ke,compareStages:()=>J,createAudioResolver:()=>wn,createBundleInspector:()=>vn,createDebugLink:()=>an,createPropertyInspector:()=>bn,createStateLogger:()=>on,describeBundle:()=>De,deserializeState:()=>Pe,diffState:()=>se,effectiveGameData:()=>Yt,estimateLineDuration:()=>St,extensionDecls:()=>Xt,extensionsOf:()=>Zt,gameDataFields:()=>Qt,gameDataValue:()=>Ke,getProperty:()=>en,loadState:()=>Ye,nextStage:()=>z,resolveSceneRef:()=>we,saveState:()=>Qe,sceneAddressIndex:()=>Ve,serializeState:()=>Ie,setProperties:()=>nn,setProperty:()=>tn,snapshotState:()=>Ze,stageIndex:()=>W,versionInRange:()=>Kt});function te(r,e){return r!==void 0&&Object.prototype.hasOwnProperty.call(r,e)?r[e]:void 0}function G(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:G(r[2])};case"bin":return{kind:"binary",op:r[1],left:G(r[2]),right:G(r[3])};case"call":{let e=r.slice(2).map(G);return{kind:"call",name:r[1],args:e}}case"fd":return{kind:"flagdelta",sign:r[1],name:r[2]}}}var S=class extends Error{constructor(e){super(e),this.name="EvalError"}};function me(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=te(e.scopes,i.scope);if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):te(o,i.name);if(a===void 0){if(n.get(i.scope)==="throw")throw new S(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{if(i.name==="advance"&&!te(t.functions,i.name)){let a=i.args[0];if(i.args.length!==1||a===void 0)throw new S(`advance() takes exactly 1 argument, got ${i.args.length}`);let l=Ae(a,e);if(l===void 0)throw new S("advance() needs a quality reference (@scope.name of a quality property)");let c=T(s(a),l,"advance");return l[Math.min(c+1,l.length-1)]}let o=te(t.functions,i.name);if(!o)throw new S(`unknown function '${i.name}'`);return o.eval(i.args,{evaluate:s,ctx:e})}case"flagdelta":throw new S("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 S(`'not' requires a boolean operand, got ${typeof a}`);return!a}let o=s(i.operand);if(typeof o!="number")throw new S(`unary '-' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let p=s(i.left);if(typeof p!="boolean")throw new S(`'and' requires boolean operands, left is ${typeof p}`);if(!p)return!1;let h=s(i.right);if(typeof h!="boolean")throw new S(`'and' requires boolean operands, right is ${typeof h}`);return h}if(i.op==="or"){let p=s(i.left);if(typeof p!="boolean")throw new S(`'or' requires boolean operands, left is ${typeof p}`);if(p)return!0;let h=s(i.right);if(typeof h!="boolean")throw new S(`'or' requires boolean operands, right is ${typeof h}`);return h}let o=s(i.left),a=s(i.right),l=Ae(i.left,e),c=Ae(i.right,e),d=l??c;if(d!==void 0){if(l&&c&&!On(l,c)&&(i.op===">"||i.op===">="||i.op==="<"||i.op==="<="))throw new S(`'${i.op}' compares two different qualities, whose stage orders are unrelated`);switch(i.op){case">":return T(o,d,">")>T(a,d,">");case">=":return T(o,d,">=")>=T(a,d,">=");case"<":return T(o,d,"<")<T(a,d,"<");case"<=":return T(o,d,"<=")<=T(a,d,"<=");case"+":case"-":case"*":case"/":throw new S(`'${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 it(o,a);case"!=":return!it(o,a);case">":return q(o,a,">"),o>a;case">=":return q(o,a,">="),o>=a;case"<":return q(o,a,"<"),o<a;case"<=":return q(o,a,"<="),o<=a;case"+":if(typeof o=="number"&&typeof a=="number"||typeof o=="string"&&typeof a=="string")return o+a;throw new S(`'+' requires two numbers or two strings, got ${typeof o} and ${typeof a}`);case"-":return q(o,a,"-"),o-a;case"*":return q(o,a,"*"),o*a;case"/":if(q(o,a,"/"),a===0)throw new S("division by zero");return o/a}}}};return s(r)}function it(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 q(r,e,t){if(typeof r!="number"||typeof e!="number")throw new S(`'${t}' requires numeric operands, got ${typeof r} and ${typeof e}`)}function Ae(r,e){if(!(r.kind!=="scopedvar"||e.qualities===void 0))return e.qualities(r.scope,r.name)}function T(r,e,t){if(typeof r!="string")throw new S(`'${t}' on a quality compares stages, got ${typeof r}`);let n=e.indexOf(r);if(n<0)throw new S(`"${r}" is not a stage of this quality (stages: ${e.join(", ")})`);return n}var On=(r,e)=>r.length===e.length&&r.every((t,n)=>t===e[n]);function ne(r){if(Number.isNaN(r)||!Number.isFinite(r))return 0;let e=Math.trunc(r)%4294967296;return e<0?e+4294967296:e}function Be(r){let e=ne(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 Fe=r=>Array.isArray(r)?r:r.stages??[],Ln=r=>Array.isArray(r)?"flags":r==null?"nothing":typeof r;function W(r,e){return typeof e=="string"?Fe(r).indexOf(e):-1}function Te(r,e){if(typeof e!="string")throw new S(`a stage is a name, got ${Ln(e)}`);let t=r.indexOf(e);if(t<0)throw new S(`"${e}" is not a stage of this quality (stages: ${r.join(", ")})`);return t}function J(r,e,t){let n=Fe(r),s=Te(n,e)-Te(n,t);return s<0?-1:s>0?1:0}function z(r,e){let t=Fe(r);return t[Math.min(Te(t,e)+1,t.length-1)]}function re(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 Nn={name:"check_flags",count:r=>Math.max(1,r.args.length-1)},An=[Nn];function ot(r,e,t){let n=t?.countingCalls??An;return ye(r,t?.want??!0,e,n)}function ye(r,e,t,n){if(r.kind==="binary"&&(r.op==="and"||r.op==="or")){let s=ye(r.left,e,t,n),i=ye(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 ye(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}function se(r,e){let t=[],n=new Set([...Object.keys(r),...Object.keys(e)]);for(let s of[...n].sort()){let i=r[s],o=e[s];JSON.stringify(i)!==JSON.stringify(o)&&t.push({path:s,from:i,to:o})}return t}var at=r=>r===void 0?"<unset>":JSON.stringify(r),lt=r=>r.pathPrefix??r.bag.pathPrefix;function $e(r,e={}){let t=e.sink??(p=>console.log(p)),n=e.label??"",s=p=>{t(`${n}${p.path}: ${at(p.from)} -> ${at(p.to)}`)},i=()=>{let p={};for(let h of r.mounts()){let g=lt(h);for(let[b,u]of Object.entries(h.bag.values))p[g+b]=u}return Object.assign(p,r.extra?.()??{}),structuredClone(p)},o=i(),a=[],l=[],c=(p,h)=>h.onAudit(g=>{let b=structuredClone({path:p+g.name,from:g.prev,to:g.next});s(b),a.push(b),o[b.path]=structuredClone(g.next)}),d=()=>{let p=r.mounts();if(!(l.length===p.length&&p.every((g,b)=>l[b].bag===g.bag))){for(let g of l)g.off();l=p.map(g=>({bag:g.bag,off:c(lt(g),g.bag)}))}};return d(),{snapshot:i,capture(){let p=i(),h=se(o,p);for(let b of h)s(b);let g=[...a,...h];return a=[],o=p,d(),g},dispose(){for(let p of l)p.off();l=[],a=[]}}}var M=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??K(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])=>dt(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);re(o,a,{noneChosen:o.type==="enum"&&o.default===""})||(this.values[i]=structuredClone(K(o)),s.push({name:i,value:a}))}return s}};function dt(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??K(r),...r.values!==void 0?{values:r.values}:{},...r.stages!==void 0?{stages:r.stages}:{},writable:t??r.writable??!0}}var Bn=r=>r.toLowerCase(),Me=1,be=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 M(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??Bn,a=new Map;for(let l of n)a.set(o(l.name),l);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,...dt(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 l=n.get(o);return l?i.get(o)?.get(Tn(l)(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 ct(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=ct(s);if(i.length===0)continue;let o=new Map;for(let[a,l]of i)o.set(a,{type:l.type,enumValues:l.values,...l.stages!==void 0?{stages:l.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:Me,scopes:this.save()}}loadFragment(e){if(e.version!==Me)throw new Error(`unsupported owned-state fragment version ${e.version} (supported: ${Me})`);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 ct(r){return r.kind==="foreign"?[...r.decls.entries()]:r.bag.declarations().map(e=>[r.bag.normalise(e.name),e])}function Tn(r){return r.kind==="foreign"?r.norm:e=>r.bag.normalise(e)}function K(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 pt=[{token:"patter",engine:"Patterplay",means:"Patter's shared globals"},{token:"story",engine:"Storylet Engine",means:"the Storylet Engine's shared @story properties"}];function ie(r){return r.ctx.host??{}}var je={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(r,e){if(r.length!==2)throw new S("random(a, b) requires exactly 2 arguments");let t=ie(e).nextRandom;if(!t)throw new S("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 S("random(a, b) arguments must be numbers");if(!Number.isInteger(n)||!Number.isInteger(s))throw new S("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:ft("check_flags"),eval(r,e){let t=ut(r[0],e,"check_flags");for(let n=1;n<r.length;n++){let s=r[n];if(s.kind!=="flagdelta")throw new S("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:ft("set_flags"),eval(r,e){let t=[...ut(r[0],e,"set_flags")];for(let n=1;n<r.length;n++){let s=r[n];if(s.kind!=="flagdelta")throw new S("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:ve("visits"),eval:(r,e)=>ie(e).visits?.(Se(r,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:ve("seen"),eval:(r,e)=>(ie(e).visits?.(Se(r,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:ve("patter_visits"),eval:(r,e)=>ie(e).patterVisits?.(Se(r,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:ve("patter_seen"),eval:(r,e)=>(ie(e).patterVisits?.(Se(r,e,"patter_seen"))??0)>0}}},Zr=pt.map(r=>r.token).filter(r=>r!=="patter"&&r!=="scene");function gt(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 Se(r,e,t){let n=e.evaluate(r[0]);if(typeof n!="string")throw new S(`${t}(id) requires a string node id`);return n}function ve(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 ut(r,e,t){if(!r)throw new S(`${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 S(`${t}() first argument must be a flags property`)}function ft(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 Fn=/^@[A-Za-z0-9_.]+$/;function*$n(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:Fn.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 Mn(r){return Array.isArray(r)?r.join(", "):typeof r=="boolean"?r?"true":"false":String(r)}function jn(r){return r===" "||r===" "||r===`
2
+ `||r==="\r"||r==="\f"||r==="\v"}function Vn(r){let e="",t=!1;for(let n of r){if(jn(n)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=n}return e}function ht(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?Vn(n):r}function mt(r,e){if(r.indexOf("{")<0)return r;let t="";for(let n of $n(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?"":Mn(s)}return t}function yt(r){return r.toLowerCase().replace(/['’]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function j(r,e){for(let t of r){e(t);let n=t.children;n&&j(n,e)}}function D(r){let e=r.gameId?.trim();return e||yt(r.name)}function Ve(r){let e=new Map;for(let[t,n]of Object.entries(r))e.set(D(n),t);return e}function we(r,e,t){return(t??Ve(r)).get(e)??(Object.hasOwn(r,e)?e:void 0)}var _=.6;var oe=1;var Gn=14,Ge=.5,qe=18,bt=1.5;var qn=[[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 St(r,e,t){let n=typeof t=="number"&&Number.isFinite(t)&&t>0?t:oe,s=0;for(let i of r??""){let o=i.codePointAt(0),a=1;for(let[l,c,d]of qn){if(o<l)break;if(o<=c){a=d;break}}s+=a}return Math.min(Math.max(s/(Gn*n),Ge),qe)}function xe(r){return`cast:${r}`}function Ee(r){return`qualifier:${r}`}function vt(r,e){return`speaker:${r}:${e}`}var wt="speaker:pattern",xt="{name} ({qualifier})";function Et(r,e,t){return r.split("{name}").map(n=>n.split("{qualifier}").join(t)).join(e)}var _e={open:"[",close:"]"},kt="SFX",Q="patter/save@0",ae=4;function le(r){let e=new Set,t=[];for(let n of r)e.has(n)||(e.add(n),t.push(n));return t}function ke(r){let e=new Map,t=(n,s)=>{let i=le([...s,...n.tags??[]]);if(e.set(n.id,i),n.type==="group"&&n.prompt&&e.set(n.prompt.id,le([...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,le([...i,...o.tags??[]]))};for(let n of Object.values(r.scenes)){let s=le(n.tags??[]);e.set(n.id,s);for(let i of n.blocks){let o=le([...s,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var Ct=r=>r.kind==="line"||r.kind==="text",ce=r=>typeof r=="number"&&Number.isFinite(r)?r:void 0;function Rt(r){let e=new Map,t=(i,o,a)=>{let l=i.kind==="gameEvent"?void 0:ce(i.padAfter),c=l??o;a&&c<0&&(c=0),e.set(i.id,l!==void 0?{own:l,resolved:c}:{resolved:c})},n=(i,o)=>{let a=ce(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 l=i.beats??[],c=-1;l.forEach((d,p)=>{Ct(d)&&(c=p)}),l.forEach((d,p)=>{Ct(d)&&t(d,a,p===c)})},s=ce(r.padAfterDefault)??_;for(let i of Object.values(r.scenes)){let o=ce(i.padAfterDefault)??s;for(let a of i.blocks){let l=ce(a.padAfterDefault)??o;for(let c of a.children)n(c,l)}}return e}var Dt=new WeakMap,It=new WeakMap;function _n(r){let e=It.get(r);return e||(e=ke(r),It.set(r,e)),e}var Pt=new WeakMap;function Hn(r){let e=Pt.get(r);return e||(e=Rt(r),Pt.set(r,e)),e}var Ot=new WeakMap;function Un(r){let e=Ot.get(r);if(e)return e;e=new Map;for(let t of Object.values(r.scenes))for(let n of t.blocks)j(n.children,s=>{if(s.type==="group"&&s.selector==="choice")for(let i of s.children)e.set(i.id,s.id)});return Ot.set(r,e),e}var Lt=new WeakMap;function Wn(r){let e=Lt.get(r);if(e)return e;e=new Map;for(let t of Object.values(r.scenes))for(let n of t.blocks)j(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 Lt.set(r,e),e}function N(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 H(r,e){return r.tagIndex.get(e)?.slice()}var pe="Patter",de=r=>r.replace(/%/g,"%25").replace(/\//g,"%2F"),Jn=r=>r.replace(/%2F/g,"/").replace(/%25/g,"%"),Nt=Symbol("ownsRegistry"),At=Symbol("setupReported"),L={stage:r=>`patter/scene/${de(r)}`,flow:r=>`patter/flow/${de(r)}/`,flowGlobals:r=>`patter/flow/${de(r)}/patter`,flowScene:(r,e)=>`patter/flow/${de(r)}/scene/${de(e)}`},fe=class{constructor(e){this.journal=e}journal},Re=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 f of Object.keys(t))Kn.has(f)||n.push({node:f,message:f==="world"?'the engine option "world" has gone: bind the scope as hostScopes: { world }':`"${f}" isn't an engine option, so it's ignored`});let s=e.strings;this.allStrings=s,this.requestedLocale=t.locale,this.currentLocale=He(e,t.locale),this.currentLocale.problem&&n.push({node:t.locale,message:this.currentLocale.problem});let i=jt(s,this.currentLocale),o=s[e.locales.default]??{},a=e.localisation,l=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 c=new Map;for(let f of e.cast??[])f.displayName&&c.set(f.name,f.displayName);let d=new Map;for(let f of e.qualifiers??[])f?.gameId&&d.set(f.gameId,f.name);let p=new Map;for(let f of e.cast??[])for(let[C,w]of Object.entries(f.qualifierLabels??{}))typeof w=="string"&&p.set(`${f.name}\0${C}`,w);let h=e.speakerPattern??xt;this.defaultSeed=(t.seed??2654435769)>>>0;let g=new Map,b=new Map,u=new Map;for(let[f,C]of Object.entries(e.scenes)){this.sceneGameIdToId.set(D(C),f);let w=new Map;for(let O of C.blocks)b.set(O.id,{sceneId:f}),u.set(O.id,O),w.set(D(O),O.id),j(O.children,$=>g.set($.id,$));this.blockGameIdToId.set(f,w)}let E=e.properties??[],R=E.filter(f=>f.shared??!0).map($t),y=E.filter(f=>!(f.shared??!0)).map($t),k=new Set(R.map(f=>f.name.toLowerCase())),v=t.registry??new be,I=!t.registry||t[Nt]===!0,B=new M(R,{pathPrefix:"@patter."}),F=[],m=[];try{v.mountOwned("patter",B,{owner:pe}),m.push("patter");let f=new Set,C=e.scopeRegistry?.scopes??[];for(let[w,O]of Object.entries(t.hostScopes??{})){let $=C.find(he=>he.token===w);if(!$&&!(e.externalScopes??[]).includes(w)){let he=C.find(En=>En.token.toLowerCase()===w.toLowerCase());n.push({node:w,message:he?`hostScopes binds "${w}", which this bundle doesn't declare: it declares "${he.token}", and a scope's token is case-sensitive`:`hostScopes binds "${w}", which this bundle doesn't declare`})}let xn=($?.declarations??[]).map(Ht);v.defineForeign(w,O,xn,{writable:$?.writable??!0,owner:pe}),m.push(w),f.add(w)}for(let w of I?e.scopeRegistry?.scopes??[]:[]){if(f.has(w.token)||v.has(w.token))continue;let O=(w.declarations??[]).map($=>Xn($,w.writable));v.defineOwned(w.token,O,{owner:pe}),m.push(w.token),F.push(w.token)}}catch(f){for(let C of m)v.remove(C,{keep:!0});throw f}let P=new Map;for(let[f,C]of Object.entries(e.scenes)){let w=new Set((C.sceneProps??[]).filter(O=>O.shared??!1).map(O=>O.name.toLowerCase()));P.set(f,w)}if(this.host={logEnabled:t.log??!1,tracing:t.log??!1,emitEngine:(f,C,w)=>this.emitEngine(f,C,w),bundle:e,emitIds:l,strings:i,defaultStrings:o,castDisplay:c,qualifierDisplay:d,speakerLabels:p,speakerPattern:h,nodeIndex:g,blockIndex:b,blockById:u,sceneGameIdToId:this.sceneGameIdToId,blockGameIdToId:this.blockGameIdToId,tagIndex:_n(e),padIndex:Hn(e),registry:v,ownsRegistry:I,patterBag:B,hostScopes:F,patterSharedDecls:R,patterLocalDecls:y,patterSharedNames:k,sceneSharedNames:P,sharedVisits:new Map,qualityLadders:new Map,sharedSelectors:new Map,stageBags:new Map,journal:null,customRng:t.rng,onDryChoice:t.onDryChoice,steer:Mt(t.steer,n),onError:t.onError??(f=>console.warn(f.kind==="setup"?`Patterplay: ${f.message}`:f.kind==="save"?`Patterplay: flow '${f.flow}': ${f.message}`:`Patterplay: ${f.kind} on ${f.node} in flow '${f.flow}' failed, played through: ${f.message}`)),reportRefits:()=>{let f=v.takeMisfits(C=>C==="patter"||C.startsWith("patter/")||F.includes(C));if(f.length!==0)if(t.onRefit)t.onRefit(f);else for(let C of f)console.warn(`Patterplay: the save's ${C.scope}.${C.name} was ${JSON.stringify(C.value)}, which no longer fits its declaration; it is back at its default`)},replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??_e).open,captionClose:(e.closedCaptions??_e).close,captionCharacter:e.closedCaptions?.character||kt,refSplitCache:new Map,refSplitRevision:v.revision},this.host.reportRefits(),t[At]!==!0)for(let f of n)this.reportSetup(f.node,f.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(He(this.host.bundle,e)),this.currentLocale.problem&&this.reportSetup(e,this.currentLocale.problem)}useLocale(e){this.currentLocale=e,this.host.strings=jt(this.allStrings,e)}replaceStrings(e){this.allStrings=e.strings;let t=this.currentLocale.problem;this.useLocale(He(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=c=>(c.setClosedCaptions(this.host.captionsOn),c),s=this.requestedLocale,i=(c=!1)=>new r(e,{...this.creationOptions,...s!==void 0?{locale:s}:{},steer:this.host.steer,registry:this.host.registry,[Nt]:this.host.ownsRegistry,[At]:c}),o=new Set(["patter",...this.host.hostScopes]),a=this.host.ownsRegistry?void 0:Object.fromEntries(Object.entries(this.host.registry.save()).filter(([c])=>o.has(c)||c.startsWith("patter/")));this.release(!0),a&&this.host.registry.load(a,{keepParked:!0,refit:!0});let l=i();try{return l.loadGame(t),n(l)}catch{l.release(!0);let c=this.host.ownsRegistry?t.registry:a;c&&this.host.registry.load(c,{keepParked:!0,refit:!0});let d=i(!0);for(let[p,h]of Object.entries(t.flows)){let g=h.cursor.currentSceneId;try{d.openFlow(p,g!==null?{scene:g}:{})}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=Mt(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 U(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=Ue(this.host,e);if(n===void 0)throw new Error(`unknown scene: ${e}`);if(t===void 0)return{sceneId:n};let s=We(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 Ue(this.host,e)??e}resolveBlockRef(e,t){if(t!=null)return e==null?t:We(this.host,e,t)}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?D(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?D(t):void 0}tagsForBeat(e){return H(this.host,e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?H(this.host,t):void 0)??[]}tagsForBlock(e,t){let n=this.resolveSceneRef(e),s=this.resolveBlockRef(n,t);return(s!=null?H(this.host,s):void 0)??[]}gameDataForScene(e){let t=this.resolveSceneRef(e),n=t!=null?this.host.bundle.scenes[t]:void 0;return N(n?.gameData)??{}}gameDataForBlock(e,t){let n=this.resolveBlockRef(this.resolveSceneRef(e),t),s=n!=null?this.host.blockById.get(n):void 0;return N(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)Bt(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 Bt(i.children,o),[...o]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...D(e)?{gameId:D(e)}:{},name:e.name,...Tt(e.gameData),...V(e.extensions),...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...D(t)?{gameId:D(t)}:{},name:t.name,...Tt(t.gameData),...V(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)j(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=H(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[xe(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[Ee(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??_,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=N(e.gameData)),e.extensions&&Object.keys(e.extensions).length&&(n.extensions=e.extensions),t&&t.length&&(n.tags=t),n}tagsField(e){let t=H(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 fe(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:ae,...t.snapshot(),...er(e,this.host.registry.save())}}restoreFlow(e,t){this.refuseInCheckpoint("restoreFlow");let n=t.version;if(n!==3&&n!==ae)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=L.flow(e);this.host.registry.discardParked(i),this.host.registry.load(Zn(e,t),{keepParked:!0,refit:!0});let o=new U(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(L.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(L.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);_t(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 W(this.ladderOf(e),t)}compareStages(e,t,n){return J(this.ladderOf(e),t,n)}nextStage(e,t){return z(this.ladderOf(e),t)}ladderOf(e){let{scope:t,name:n}=this.splitShared(e),s=Yn(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:K(e),writable:e.writable??!0}))}splitShared(e){let t=Ut(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:ae,...this.host.ownsRegistry?{registry:this.host.registry.save()}:{},sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:Gt(this.host.sharedSelectors),flows:e}}loadGame(e){this.refuseInCheckpoint("loadGame");let t=e.version;if(t!==3&&t!==ae)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(L.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 qt(e.sharedSelectors))this.host.sharedSelectors.set(o,a);for(let[o,a]of Object.entries(e.flows)){let l=new U(o,this.host,this.defaultSeed);l.restore(a),this.flowsById.set(o,l)}this.host.reportRefits()}},U=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=ne(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 ue(this.host,"patter",()=>[...this.host.patterSharedDecls,...this.host.patterLocalDecls]).get(n);if(e==="scene"){let s=this.currentSceneId;return s==null?void 0:ue(this.host,`scene/${s}`,()=>this.host.bundle.scenes[s]?.sceneProps).get(n)}return this.registryQualities?.(e,t)??ue(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(L.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=Ue(this.host,e);if(n===void 0)return!1;let s;return t!==void 0&&(s=We(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:l,beatIndex:c,pendingChoice:d,pendingPrompt:p,pendingPromptOwnerId:h}=this,g=this.stack.map(b=>({...b}));e.undo.push(()=>{Object.assign(this,{rngState:t,started:n,flowEnded:s,dryChoice:i,ranDry:o,currentSceneId:a,activeSnippet:l,beatIndex:c,pendingChoice:d,pendingPrompt:p,pendingPromptOwnerId:h,stack:g})})}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=Wn(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:N(t.gameData),...V(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 W(this.ladderOf(e),t)}compareStages(e,t,n){return J(this.ladderOf(e),t,n)}nextStage(e,t){return z(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`);_t(this.host,s,i,t,this.currentSceneId)}let o=this.host.journal;if(s==="patter"){if(o){let a=this.host.patterSharedNames.has(i),l=a?this.host.patterBag.get(i):this.local.get(i),c=this.local;l!==void 0&&o.undo.push(a?()=>this.host.registry.set("patter",i,l):()=>c.set(i,l))}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),l=a?.get(i);a&&l!==void 0&&o.undo.push(()=>a.set(i,l))}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=Un(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:N(n.gameData)}:{}}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,...this.pendingPrompt?.shown?{pendingPrompt:zn(this.pendingPrompt.shown)}:{},selectors:Gt(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=ne(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,l=this.childrenOf(a.containerId),c=!l&&o!==void 0?this.host.nodeIndex.get(o):void 0;if(c?.type==="group"&&c.selector==="choice"){n={node:t.activeSnippetId??t.pendingChoice?.groupId??a.containerId,instead:`option ${a.containerId} has gone, so choice ${c.id} is offered again`,reoffer:c};break}let d=i!==void 0?l?.findIndex(p=>p.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=qt(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"),l=o.secretUntilEligible===!0;!a&&l||(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(l=>({id:l.id,eligible:this.holds(l)})),n=e.children.filter((l,c)=>t[c].eligible),s=e.options?.order??"sequential",i=e.options?.exhaust??"once",o=l=>(this.host.tracing&&this.emit({type:"select",group:e.id,selector:e.selector??"default",...e.selector==="sequence"?{order:s,exhaust:i}:{},children:t,picked:l?.id??null}),l),a=null;if(n.length>0){let l=this.selectorState(e);switch(e.selector){case"branch":a=n[0];break;case"sequence":a=s==="shuffle"?this.pickShuffle(n,i,l):s==="specificity"?this.pickSpecificity(n,i,l):this.pickSequential(n,i,l);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(l=>({...l})),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(l=>l.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(h=>h.id),a=new Set(e.map(h=>h.id));if(n.bag===void 0&&(n.bag=o()),!n.bag.some(h=>a.has(h))){if(t==="once")return null;if(i){let h=e[s-1];return n.last=h.id,h}if(n.bag=o(),n.bag.length===0)return null}let l=n.bag.filter(h=>a.has(h)),c=n.last!==void 0&&l.length>1?l.indexOf(n.last):-1,d=Math.floor(this.rng()*(c>=0?l.length-1:l.length));c>=0&&d>=c&&d++;let p=l[d];return n.bag.splice(n.bag.indexOf(p),1),n.last=p,e.find(h=>h.id===p)}pickSpecificity(e,t,n){let s=e;if(t!=="repeat"){n.bag===void 0&&(n.bag=e.map(d=>d.id));let c=new Set(n.bag);if(s=e.filter(d=>c.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(c=>{let d=this.specScore(c);return d>i&&(i=d),{c,s:d}}).filter(c=>c.s===i).map(c=>c.c),l;if(a.length===1)l=a[0];else{let c=n.last!==void 0?a.findIndex(p=>p.id===n.last):-1,d=Math.floor(this.rng()*(c>=0?a.length-1:a.length));c>=0&&d>=c&&d++,l=a[d]}return t!=="repeat"&&(n.bag=n.bag.filter(c=>c!==l.id)),n.last=l.id,l}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0,e):0}matchedSpec(e,t,n){return ot(e,i=>{try{return Vt(me(i,this.context(),je))}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 Vt(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 me(this.conditionAst(e),this.context(),je)}conditionAst(e){let t=Dt.get(e);return t||(t=G(e.ast),Dt.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=Be(this.rngState),t=e.next();return this.rngState=e.state(),t};beatResult(e){let t=H(this.host,e.id),n=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:N(e.gameData),...V(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:N(e.gameData),...V(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)),l=i&&a.length===0;return{type:"line",id:e.id,text:a,character:l?void 0:e.character,characterName:l?void 0:this.resolveCharacterName(e.character),direction:l?void 0:e.direction,qualifier:l?void 0:e.qualifier,qualifierName:l?void 0:this.resolveQualifierName(e.qualifier),speakerLabel:l?void 0:Ce(this.host,e.character,e.qualifier),padAfter:this.padOf(e.id),...this.spokenOf(e),gameData:N(e.gameData),...V(e.extensions),...n}}}}interpolate(e){return mt(e,t=>this.getProperty(t))}stripCaptions(e){return ht(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??oe,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=H(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:N(e.gameData),...V(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:N(e.gameData),...V(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 j(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=xe(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}padOf(e){return this.host.padIndex.get(e)?.resolved??_}resolveQualifierName(e){if(e===void 0||this.host.emitIds)return;let t=Ee(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.qualifierDisplay.get(e)}splitRef(e){return Ut(this.host,e)}newLocal(){return new M(this.host.patterLocalDecls,{pathPrefix:"@patter."})}mountLocal(){this.local=this.newLocal();let e=L.flowGlobals(this.id);this.host.registry.mountOwned(e,this.local,{owner:pe}),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 M(n.filter(c=>!t.has(c.name.toLowerCase())),{pathPrefix:"@scene."}),a=L.flowScene(this.id,e),l=Ft(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,l?{keep:!0}:void 0),this.registered.delete(a),this.sceneBags.delete(e))})}if(!this.host.stageBags.has(e)){let o=new M(n.filter(l=>t.has(l.name.toLowerCase())),{pathPrefix:"@scene."}),a=Ft(this.host.registry,L.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(L.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,K(n))}}};function Bt(r,e){j(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=l=>(n?void 0:r.strings[l])??r.defaultStrings[l],i=s(xe(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(vt(e,t))??o;let a=s(Ee(t))??r.qualifierDisplay.get(t)??t;return Et(s(wt)??r.speakerPattern,i,a)}function Tt(r){return r&&Object.keys(r).length?{gameData:N(r)}:{}}function V(r){return r&&Object.keys(r).length?{extensions:r}:{}}function zn(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 Gt(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 qt(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 Ft(r,e,t,n){let s=n?JSON.stringify(t.save()):"";return r.mountOwned(e,t,{owner:pe}),n&&JSON.stringify(t.save())!==s}function $t(r){return{name:r.name,type:r.type,values:r.values,stages:r.stages,default:r.default}}var Kn=new Set(["rng","seed","locale","hostScopes","registry","replayPromptOnChoose","closedCaptions","onDryChoice","steer","onError","onRefit","log"]);function Mt(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 He(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=l=>l.toLowerCase().replace(/_/g,"-"),i=n.find(l=>s(l)===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(l=>s(l)===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 jt(r,e){return e.table!==void 0?r[e.table]??{}:{}}function _t(r,e,t,n,s){let i=l=>l?.find(c=>c.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 l=r.bundle.scopeRegistry?.scopes.find(c=>c.token===e);if(!l||l.declarations===void 0)return;o=i(l.declarations)}let a=`@${e}.${t}`;if(o===void 0)throw new Error(`no property at "${a}": the content declares no ${a}`);if(!re(o,n,{noneChosen:o.type==="enum"&&o.default===""}))throw new Error(`"${a}" takes ${Qn(o)}; ${JSON.stringify(n)} doesn't fit`)}function Qn(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 ue(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 Yn(r,e,t){let n=t.toLowerCase();return e==="patter"?ue(r,"patter",()=>[...r.patterSharedDecls,...r.patterLocalDecls]).get(n):r.registry.toEvalContext().qualities?.(e,t)??ue(r,`host/${e}`,()=>r.bundle.scopeRegistry?.scopes.find(s=>s.token===e)?.declarations).get(n)}function Ht(r){return{name:r.name,type:r.type,values:r.values,stages:r.stages,default:r.default,writable:r.writable}}function Xn(r,e){let t=Ht(r),n=r.writable??e;return n===void 0?t:{...t,writable:n}}function Ue(r,e){return we(r.bundle.scenes,e,r.sceneGameIdToId)}function We(r,e,t){return r.blockGameIdToId.get(e)?.get(t)??(r.blockIndex.get(t)?.sceneId===e?t:void 0)}function Ut(r,e){r.refSplitRevision!==r.registry.revision&&(r.refSplitCache.clear(),r.refSplitRevision=r.registry.revision);let t=r.refSplitCache.get(e);return t||(t=gt(e,n=>n==="scene"||r.registry.has(n)||(r.bundle.externalScopes?.includes(n)??!1)),r.refSplitCache.set(e,t)),t}function Zn(r,e){let t={};e.scopes?.patter&&(t[L.flowGlobals(r)]=e.scopes.patter);for(let[n,s]of Object.entries(e.sceneBags??{}))t[L.flowScene(r,n)]=s;return t}function er(r,e){let t={scopes:{},sceneBags:{}},n=L.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[Jn(o.slice(6))]=i)}return t}function Vt(r){return typeof r=="boolean"?r:typeof r=="number"?r!==0:typeof r=="string"?r!=="":r.length>0}var zt="0.46.1",tr=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;function Je(r){let e=typeof r=="string"?tr.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 Jt(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 Kt(r,e,t){let n=Je(r),s=Je(e),i=Je(t);return!n||!s||!i?!1:Jt(n,s)>=0&&Jt(n,i)<0}var nr=(r,e)=>r.shared??e;function ze(r,e){return{name:r.name,type:r.type,hasDefault:r.default!==void 0,...r.default!==void 0?{default:r.default}:{},shared:nr(r,e)}}function rr(r){return{name:r.name,type:r.type,hasDefault:r.default!==void 0,...r.values?{values:[...r.values]}:{},...r.purpose?{purpose:r.purpose}:{}}}function sr(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 De(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=D(o);t.push({gameId:a,name:o.name,blocks:o.blocks.map(l=>({gameId:D(l),name:l.name}))});for(let l of o.blocks)sr(l,e);o.sceneProps?.length&&n.push({gameId:a,properties:o.sceneProps.map(l=>ze(l,!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=>ze(a,!0))})),i=Object.entries(r.gameDataFields??{}).filter(([,o])=>(o?.length??0)>0).map(([o,a])=>({kind:o,fields:(a??[]).map(rr)}));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=>ze(o,!0)),scene:n},gameData:i,counts:e}}var ge=(r,e)=>Object.prototype.hasOwnProperty.call(r,e);function Qt(r,e){return r.gameDataFields?.[e]??[]}function Ke(r,e,t){return e&&ge(e,t)?e[t]:r.find(n=>n.name===t)?.default}function Yt(r,e){let t={};for(let n of r){let s=Ke(r,e,n.name);s!==void 0&&(t[n.name]=s)}for(let[n,s]of Object.entries(e??{}))ge(t,n)||(t[n]=s);return t}function Xt(r,e,t){let n=r.extensions!==void 0&&ge(r.extensions,e)?r.extensions[e]:void 0;return n!==void 0&&ge(n.fields,t)?n.fields[t]??[]:[]}function Zt(r,e,t=""){let n=o=>({...o?.extensions??{}}),s=Object.values(r.scenes??{}),i=o=>(ge(r.scenes??{},o)?r.scenes[o]:void 0)??s.find(a=>D(a)===o);switch(e){case"project":{let o={};for(let[a,l]of Object.entries(r.extensions??{}))l.project!==void 0&&(o[a]=l.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??[],l=t.slice(o+1);return n(a.find(c=>c.id===l)??a.find(c=>D(c)===l))}case"snippet":case"option":case"line":case"text":case"gameEvent":{let o,a=(l,c)=>{for(let d of l??[]){if(o!==void 0)return;if(d.type==="group"){if(c&&d.id===t&&e==="option"){o=d;return}if(c&&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 p=(d.beats??[]).find(h=>h.id===t);if(p!==void 0){p.kind===e&&(o=p);return}}};for(let l of s)for(let c of l.blocks??[])o===void 0&&a(c.children??[],!1);return n(o)}default:return{}}}function Qe(r){return{schema:Q,save:r.saveGame()}}function Ye(r,e){if(!e||e.schema!==Q||!e.save)throw new Error(`loadState: not a ${Q} envelope`);r.loadGame(e.save)}function Ie(r){return JSON.stringify(Qe(r))}function Pe(r,e){Ye(r,JSON.parse(e))}function en(r,e){return r.getProperty(e)}function tn(r,e,t){r.setProperty(e,t)}function nn(r,e){for(let[t,n]of Object.entries(e))r.setProperty(t,n)}function Ze(r){let e={};for(let t of rn(r)){let n=t.pathPrefix??t.bag.pathPrefix;for(let[s,i]of Object.entries(t.bag.save()))e[`${n}${s}`]=i}return Object.assign(e,sn(r)),e}function rn(r){return[...r.listBags(),...r.flows().flatMap(e=>e.listBags())]}function ir(r){switch(r.type){case"line":return`line ${r.character??"?"}: ${JSON.stringify(r.text)}${Xe(r.gameData)}`;case"text":return`text: ${JSON.stringify(r.text)}${Xe(r.gameData)}`;case"gameEvent":return`game event ${r.id}${Xe(r.gameData)}`;case"choice":return`choice (${r.options.length} option${r.options.length===1?"":"s"})`;case"end":return"end"}}var Xe=r=>r?` gameData=${JSON.stringify(r)}`:"";function sn(r){let e={};for(let[t,n]of Object.entries(r.getVisitCounts()))e[`visit:${t}`]=n;for(let t of r.flows())for(let[n,s]of Object.entries(t.getVisitCounts()))e[`${t.id}/visit:${n}`]=s;return e}function on(r,e={}){let t=e.label?`[${e.label}] `:"",n=$e({mounts:()=>rn(r),extra:()=>sn(r)},{sink:e.sink,label:t});return{snapshot:()=>Ze(r),capture:()=>n.capture(),dispose:()=>n.dispose(),logStep(s){(e.sink??(i=>console.log(i)))(`${t}${ir(s)}`)}}}var or="unhandled";function an(r){let e=r.url??"ws://127.0.0.1:4471",t=r.WebSocket??globalThis.WebSocket,n=new Set,s=[],i=null,o=!1,a=r.build,l=!1,c=!1,d=!1,p=1e3,h=null,g=()=>{if(!(!i||i.readyState!==1)){for(let y of s)try{i.send(y)}catch{}s=[]}},b=y=>{o||!i||i.readyState>1||l&&i.readyState!==1||(s.push(JSON.stringify(y)),g())};if(!t)return{flowOpened(){},observe(){},flowClosed(){},setBuild(){},replyPlay(){},close(){o=!0},state:"closed",build:a,url:e};let u=(y,k)=>{b({t:"played",id:y,started:k.started===!0,...typeof k.reason=="string"?{reason:k.reason}:{},...typeof k.detail=="string"?{detail:k.detail}:{}})},E=()=>{let y=JSON.stringify({t:"hello",v:1,build:a,project:r.project,flows:[...n]});try{i?.send(y),p=1e3}catch{}},R=()=>{if(h=null,o)return;let y;try{y=new t(e)}catch{i=null;return}i=y,y.addEventListener("open",()=>{i===y&&(c=!0,d&&(d=!1,console.info(`[patterplay] Live Link is back (${e}).`)),E(),g())}),y.addEventListener("message",k=>{if(typeof k.data!="string")return;let v;try{v=JSON.parse(k.data)}catch{return}if(!(v===null||typeof v!="object")){if(v.t==="bundle")r.onBundle&&typeof v.build=="string"&&typeof v.data=="string"&&r.onBundle({build:v.build,data:v.data});else if(v.t==="play"){let I=ar(v);if(!I)return;if(!r.onPlay){u(I.id,{started:!1,reason:or});return}try{r.onPlay(I)}catch{}}}}),y.addEventListener("error",()=>{}),y.addEventListener("close",k=>{if(i===y&&(i=null,s=[],l=!0,!o)){if(k?.code===4e3){o=!0,console.info(`[patterplay] Live Link: another game took the editor's link (${e}).`);return}c&&!d&&(d=!0,console.info(`[patterplay] Live Link lost (${e}); retrying.`)),h=setTimeout(R,p),p=Math.min(p*2,1e4)}})};return R(),{flowOpened(y){n.add(y),b({t:"flowOpen",flow:y})},flowClosed(y){n.delete(y),b({t:"flowClose",flow:y})},observe(y,k,v,I,B){n.has(y)||(n.add(y),b({t:"flowOpen",flow:y})),b({t:"frame",flow:y,sceneId:k,beatId:v,type:I,choiceId:B})},replyPlay:u,setBuild(y){o||y===a||(a=y,i&&i.readyState===1&&E())},close(){o=!0,s=[],h&&(clearTimeout(h),h=null);try{i?.close()}catch{}i=null},get state(){return o?"closed":i&&i.readyState===1?"connected":i||h?"connecting":"closed"},get build(){return a},url:e}}function ar(r){let{id:e,sceneId:t,blockId:n}=r;return typeof e!="string"||e===""||typeof t!="string"||t===""||typeof n!="string"||n===""?null:{id:e,sceneId:t,blockId:n,takeOver:r.takeOver===!0,...typeof r.build=="string"&&r.build!==""?{build:r.build}:{}}}function ln(r,e,t){let n=JSON.parse(t);return e.content.structureHash!==void 0&&e.content.structureHash===n.content.structureHash?(r.replaceStrings(n),{engine:r,bundle:n,kind:"text"}):{engine:r.hotSwap(n),bundle:n,kind:"structure"}}function lr(r,e){r.textContent="";let t=/\u0002([^\u0003]*)\u0003/g,n=0,s;for(;(s=t.exec(e))!==null;){s.index>n&&r.append(e.slice(n,s.index));let i=document.createElement("strong");i.textContent=s[1]??"",r.append(i),n=s.index+s[0].length}n<e.length&&r.append(e.slice(n))}var nt=!1,cn=!1,un,cr=350,et=6,dn=7,X=null,Z=0,Oe=null,dr=null;function fn(){if(X)return X;let r=document.createElement("div");return r.className="tooltip",r.setAttribute("role","tooltip"),r.hidden=!0,document.body.appendChild(r),X=r,r}var pr=r=>r instanceof HTMLElement?r.getBoundingClientRect():r;function ur(r){let e=fn(),t=pr(r),n=e.getBoundingClientRect(),s=t.top-n.height-dn;s<et&&(s=t.top+t.height+dn);let i=t.left+t.width/2-n.width/2;i=Math.max(et,Math.min(i,window.innerWidth-n.width-et)),e.style.left=`${Math.round(i)}px`,e.style.top=`${Math.round(s)}px`}function fr(r){let e=r.dataset.tip;e&&gr(r,e)}function gr(r,e){if(un?.())return;let t=fn(),n=(r instanceof HTMLElement?r.closest("dialog[open]"):null)??document.body;t.parentElement!==n&&n.appendChild(t),Oe=r instanceof HTMLElement?r:null,lr(t,e),t.hidden=!1,t.classList.remove("show"),t.offsetWidth,ur(r),t.classList.add("show")}function Y(){Z&&(window.clearTimeout(Z),Z=0),Oe=null,dr=null,X&&(X.hidden=!0,X.classList.remove("show"))}function pn(r){r!==Oe&&(Z&&window.clearTimeout(Z),Z=window.setTimeout(()=>fr(r),cr))}function hr(){yr()}function mr(){cn||(cn=!0,setTimeout(()=>{nt||typeof document>"u"||document.querySelector("[data-tip]")&&console.warn("app-shell: something set `data-tip` but no tooltip host is mounted, so those rollovers will not draw. Call initTooltips() once per window.")},0))}var tt=r=>r instanceof Element?r.closest("[data-tip]"):null;function yr(r={}){r.suppressed!==void 0&&(un=r.suppressed),!nt&&(nt=!0,document.addEventListener("pointerover",e=>{let t=tt(e.target);t&&pn(t)}),document.addEventListener("pointerout",e=>{let t=tt(e.target);if(!t)return;let n=e.relatedTarget;n instanceof Node&&t.contains(n)||Y()}),document.addEventListener("focusin",e=>{let t=tt(e.target);t&&pn(t)}),document.addEventListener("focusout",()=>Y()),document.addEventListener("pointerdown",()=>Y(),!0),document.addEventListener("scroll",()=>{Oe&&Y()},!0),document.addEventListener("keydown",e=>{e.key==="Escape"&&Y()}),window.addEventListener("blur",()=>Y()))}function gn(r,e,...t){let n=document.createElement(r),s=typeof e=="string"?{className:e}:e??{};s.className&&(n.className=s.className),s.text!==void 0&&s.text!==null&&(n.textContent=s.text),s.title!==void 0&&(n.title=s.title),s.tip!==void 0&&(n.dataset.tip=s.tip,n.setAttribute("aria-label",s.tip),hr()),s.onClick&&n.addEventListener("click",s.onClick);for(let i of t)i!=null&&n.append(i);return mr(),n}function hn(r){let e=r.default;if(e!=null)return typeof e=="boolean"?e?"True":"False":Array.isArray(e)?e.length===0?"none":e.join(", "):e===""?"none":String(e);switch(r.type){case"boolean":return"False";case"number":return"0";case"enum":return r.values?.[0]??"none";case"quality":return r.stages?.[0]??"first stage";case"flags":return"none";default:return"empty"}}var mn=r=>`default (${hn(r)})`;function rt(r){let e=r.doc===void 0?gn:(a,l)=>{let c=r.doc.createElement(a);return c.className=l.className,l.text!==void 0&&(c.textContent=l.text),l.tip!==void 0&&(c.title=l.tip,c.setAttribute("aria-label",l.tip)),l.onClick&&c.addEventListener("click",l.onClick),a==="button"&&(c.type="button"),c},t=e("span",{className:"seg shell-rungs"}),n=r.decl??{type:"quality",stages:r.stages},s=r.value===void 0,i=typeof n.default=="string"&&r.stages.includes(n.default)?n.default:r.stages[0],o=r.onPick===void 0;r.onClear&&t.append(e("button",{className:`seg-opt shell-rung shell-rung-default${s?" on":""}`,text:mn(n),tip:s?"Not set here: the declared default holds":"Clear the value, back to the default",onClick:()=>{s||r.onClear()}}));for(let a of r.stages){let l=r.value===a,c=s&&a===i,d=e(o?"span":"button",{className:`seg-opt shell-rung${l?" on":""}${c?" fallback":""}`,text:a,tip:l?"The current stage":c?"The stage it falls back to":o?a:r.pickTip?.(a)??`Set to "${a}"`,...o?{}:{onClick:()=>{l||r.onPick(a)}}});t.append(d)}return!s&&!r.stages.includes(r.value)&&t.append(e("span",{className:"seg-opt shell-rung stray on",text:r.value,tip:`"${r.value}" is not one of the stages: pick the one it belongs at now`})),t}var yn="pp-inspector-style",br=`
3
3
  .pp-insp{font:13px/1.4 ui-sans-serif,system-ui,sans-serif;color:#15201e;background:#f4efe6;border:1px solid #cfc7b8;border-radius:10px;padding:.6rem .7rem;max-width:22rem;box-shadow:0 6px 20px rgba(21,32,30,.12)}
4
4
  .pp-insp h4{margin:0 0 .4rem;font:600 .72rem/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.08em;text-transform:uppercase;color:#5c6b62}
5
5
  .pp-insp-empty{color:#8a9691;font-style:italic}
@@ -16,7 +16,7 @@
16
16
  .pp-insp-ctl .seg-opt+.seg-opt{border-left:1px solid #cfc7b8}
17
17
  .pp-insp-ctl .seg-opt.on{color:#214f4b;background:#dbe8e4;font-weight:600;cursor:default}
18
18
  .pp-insp-ctl .shell-rung.stray{color:#9a3b2e;text-decoration:line-through}
19
- `;function Sr(r){if(r.getElementById(yn))return;let e=r.createElement("style");e.id=yn,e.textContent=br,(r.head??r.documentElement).appendChild(e)}function vr(r,e){return Array.isArray(r)&&Array.isArray(e)?r.length===e.length&&r.every((t,n)=>t===e[n]):r===e}function bn(r,e={}){let t=e.container?.ownerDocument??document;Sr(t);let n=t.createElement("div");n.className="pp-insp";let s=t.createElement("h4");s.textContent=e.title??"Runtime state";let i=t.createElement("div"),o=t.createElement("div");o.className="pp-insp-io";let a=t.createElement("button");a.type="button",a.textContent="Save state\u2026",a.addEventListener("click",()=>{let g=new Blob([Ie(r)],{type:"application/json"}),w=t.createElement("a");w.href=URL.createObjectURL(g),w.download="save.patterstate",w.click(),URL.revokeObjectURL(w.href)});let l=t.createElement("button");l.type="button",l.textContent="Load state\u2026",l.addEventListener("click",()=>{let g=t.createElement("input");g.type="file",g.accept=".patterstate,application/json",g.addEventListener("change",()=>{let w=g.files?.[0];w&&w.text().then(I=>{try{Pe(r,I),u()}catch(R){console.error("Load state failed:",R instanceof Error?R.message:R)}})}),g.click()}),o.append(a,l),n.append(s,o,i);let c=[],d=g=>{let w=t.createElement("div");w.className="pp-insp-row";let I=t.createElement("span");I.className="pp-insp-ref",I.textContent=g.path,I.title=g.path;let R=t.createElement("div");R.className="pp-insp-ctl";let L=t.createElement("button");L.className="pp-insp-reset",L.type="button",L.textContent="\u21BA",L.title="Reset to default",w.append(I,R,L),i.appendChild(w);let k,A=m=>{r.setProperty(g.path,m),F()},T=m=>t.activeElement===m;function F(){L.disabled=vr(r.getProperty(g.path),g.default)}if(L.addEventListener("click",()=>{r.setProperty(g.path,g.default),k(),F()}),g.type==="boolean"){let m=t.createElement("input");m.type="checkbox",m.addEventListener("change",()=>A(m.checked)),R.appendChild(m),k=()=>{T(m)||(m.checked=r.getProperty(g.path)===!0)}}else if(g.type==="number"){let m=t.createElement("input");m.type="number",m.addEventListener("change",()=>A(Number(m.value))),R.appendChild(m),k=()=>{T(m)||(m.value=String(r.getProperty(g.path)??""))}}else if(g.type==="quality"){let m=()=>{let C=r.getProperty(g.path);R.replaceChildren(rt({stages:g.stages??[],value:typeof C=="string"?C:void 0,decl:g,onPick:h=>{A(h),m()},doc:t}))};k=m}else if(g.type==="enum"){let m=t.createElement("select");for(let C of g.values??[]){let h=t.createElement("option");h.value=C,h.textContent=C,m.appendChild(h)}m.addEventListener("change",()=>A(m.value)),R.appendChild(m),k=()=>{T(m)||(m.value=String(r.getProperty(g.path)??""))}}else if(g.type==="flags"){let m=t.createElement("input");m.type="text",m.placeholder="comma, separated, flags",m.addEventListener("change",()=>A(m.value.split(",").map(C=>C.trim()).filter(C=>C.length>0))),R.appendChild(m),k=()=>{if(!T(m)){let C=r.getProperty(g.path);m.value=Array.isArray(C)?C.join(", "):""}}}else{let m=t.createElement("input");m.type="text",m.addEventListener("change",()=>A(m.value)),R.appendChild(m),k=()=>{T(m)||(m.value=String(r.getProperty(g.path)??""))}}k(),F(),c.push(()=>{k(),F()})},f=r.listProperties();if(f.length===0){let g=t.createElement("div");g.className="pp-insp-empty",g.textContent="No @patter properties.",i.appendChild(g)}else for(let g of f)d(g);let u=()=>{for(let g of c)g()};e.container?.appendChild(n);let p=e.pollMs??250,y;return p>0&&(y=setInterval(u,p)),{el:n,refresh:u,destroy(){y!==void 0&&clearInterval(y),n.remove()}}}var Sn="pp-bundle-style",wr=`
19
+ `;function Sr(r){if(r.getElementById(yn))return;let e=r.createElement("style");e.id=yn,e.textContent=br,(r.head??r.documentElement).appendChild(e)}function vr(r,e){return Array.isArray(r)&&Array.isArray(e)?r.length===e.length&&r.every((t,n)=>t===e[n]):r===e}function bn(r,e={}){let t=e.container?.ownerDocument??document;Sr(t);let n=t.createElement("div");n.className="pp-insp";let s=t.createElement("h4");s.textContent=e.title??"Runtime state";let i=t.createElement("div"),o=t.createElement("div");o.className="pp-insp-io";let a=t.createElement("button");a.type="button",a.textContent="Save state\u2026",a.addEventListener("click",()=>{let u=new Blob([Ie(r)],{type:"application/json"}),E=t.createElement("a");E.href=URL.createObjectURL(u),E.download="save.patterstate",E.click(),URL.revokeObjectURL(E.href)});let l=t.createElement("button");l.type="button",l.textContent="Load state\u2026",l.addEventListener("click",()=>{let u=t.createElement("input");u.type="file",u.accept=".patterstate,application/json",u.addEventListener("change",()=>{let E=u.files?.[0];E&&E.text().then(R=>{try{Pe(r,R),h()}catch(y){console.error("Load state failed:",y instanceof Error?y.message:y)}})}),u.click()}),o.append(a,l),n.append(s,o,i);let c=[],d=u=>{let E=t.createElement("div");E.className="pp-insp-row";let R=t.createElement("span");R.className="pp-insp-ref",R.textContent=u.path,R.title=u.path;let y=t.createElement("div");y.className="pp-insp-ctl";let k=t.createElement("button");k.className="pp-insp-reset",k.type="button",k.textContent="\u21BA",k.title="Reset to default",E.append(R,y,k),i.appendChild(E);let v,I=m=>{r.setProperty(u.path,m),F()},B=m=>t.activeElement===m;function F(){k.disabled=vr(r.getProperty(u.path),u.default)}if(k.addEventListener("click",()=>{r.setProperty(u.path,u.default),v(),F()}),u.type==="boolean"){let m=t.createElement("input");m.type="checkbox",m.addEventListener("change",()=>I(m.checked)),y.appendChild(m),v=()=>{B(m)||(m.checked=r.getProperty(u.path)===!0)}}else if(u.type==="number"){let m=t.createElement("input");m.type="number",m.addEventListener("change",()=>I(Number(m.value))),y.appendChild(m),v=()=>{B(m)||(m.value=String(r.getProperty(u.path)??""))}}else if(u.type==="quality"){let m=()=>{let P=r.getProperty(u.path);y.replaceChildren(rt({stages:u.stages??[],value:typeof P=="string"?P:void 0,decl:u,onPick:f=>{I(f),m()},doc:t}))};v=m}else if(u.type==="enum"){let m=t.createElement("select");for(let P of u.values??[]){let f=t.createElement("option");f.value=P,f.textContent=P,m.appendChild(f)}m.addEventListener("change",()=>I(m.value)),y.appendChild(m),v=()=>{B(m)||(m.value=String(r.getProperty(u.path)??""))}}else if(u.type==="flags"){let m=t.createElement("input");m.type="text",m.placeholder="comma, separated, flags",m.addEventListener("change",()=>I(m.value.split(",").map(P=>P.trim()).filter(P=>P.length>0))),y.appendChild(m),v=()=>{if(!B(m)){let P=r.getProperty(u.path);m.value=Array.isArray(P)?P.join(", "):""}}}else{let m=t.createElement("input");m.type="text",m.addEventListener("change",()=>I(m.value)),y.appendChild(m),v=()=>{B(m)||(m.value=String(r.getProperty(u.path)??""))}}v(),F(),c.push(()=>{v(),F()})},p=r.listProperties();if(p.length===0){let u=t.createElement("div");u.className="pp-insp-empty",u.textContent="No @patter properties.",i.appendChild(u)}else for(let u of p)d(u);let h=()=>{for(let u of c)u()};e.container?.appendChild(n);let g=e.pollMs??250,b;return g>0&&(b=setInterval(h,g)),{el:n,refresh:h,destroy(){b!==void 0&&clearInterval(b),n.remove()}}}var Sn="pp-bundle-style",wr=`
20
20
  .pp-bundle{font:13px/1.4 ui-sans-serif,system-ui,sans-serif;color:#15201e;background:#f4efe6;border:1px solid #cfc7b8;border-radius:10px;padding:.6rem .7rem;max-width:26rem;box-shadow:0 6px 20px rgba(21,32,30,.12)}
21
21
  .pp-bundle h4{margin:0 0 .4rem;font:600 .72rem/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.08em;text-transform:uppercase;color:#5c6b62}
22
22
  .pp-bundle details{border-top:1px solid #e3dccf;padding:.3rem 0}
@@ -33,5 +33,5 @@
33
33
  .pp-bundle-empty{color:#8a9691;font-style:italic;margin-left:1rem}
34
34
  .pp-bundle-warn{color:#8a3a2f;font-weight:600}
35
35
  .pp-bundle-tag{font-size:.7rem;color:#5c6b62;border:1px solid #cfc7b8;border-radius:5px;padding:0 .25rem;margin-left:.3rem}
36
- `;function xr(r){if(r.getElementById(Sn))return;let e=r.createElement("style");e.id=Sn,e.textContent=wr,(r.head??r.documentElement).appendChild(e)}var v=(r,e,t,n)=>{let s=r.createElement(e);return t&&(s.className=t),n!==void 0&&(s.textContent=n),s};function N(r,e,t,n="pp-bundle-val"){let s=v(r,"div","pp-bundle-row");return s.append(v(r,"span","pp-bundle-key",e),v(r,"span",n,t)),s}function st(r,e){let t=v(r,"div","pp-bundle-row");t.append(v(r,"span","pp-bundle-key pp-bundle-addr",e.name));let n=v(r,"span","pp-bundle-val",e.type);return e.hasDefault||n.append(v(r,"span","pp-bundle-tag","no default")),t.append(n),t}function ee(r,e,t,n,s){let i=r.createElement("details");i.dataset.section=e,i.open=s;let o=r.createElement("summary");return o.textContent=t,n!==null&&o.append(v(r,"span","pp-bundle-count",` ${n}`)),i.append(o),i}function vn(r,e={}){let t=e.container?.ownerDocument??document;xr(t);let n=De(r),s=new Set(e.open??["identity","addresses"]),i=v(t,"div","pp-bundle");i.append(v(t,"h4",void 0,e.title??"Bundle"));let o=ee(t,"identity",n.identity.project||"(unnamed project)",null,s.has("identity"));n.identity.version&&o.append(N(t,"version",n.identity.version)),o.append(N(t,"schema",n.identity.schema)),o.append(N(t,"locales",`${n.identity.defaultLocale}${n.identity.locales.length>1?` (+${n.identity.locales.length-1})`:""}`)),o.append(N(t,"strings",n.identity.localisation)),n.identity.voiced&&o.append(N(t,"voiced","yes")),n.identity.hash&&o.append(N(t,"hash",n.identity.hash)),n.identity.structureHash&&o.append(N(t,"structure",n.identity.structureHash)),n.identity.sourceDebug&&o.append(N(t,"build","SOURCE DEBUG - not shippable","pp-bundle-val pp-bundle-warn")),i.append(o);let a=ee(t,"addresses","Addresses",n.addresses.length,s.has("addresses"));n.addresses.length||a.append(v(t,"div","pp-bundle-empty","no scenes"));for(let p of n.addresses){let y=v(t,"div","pp-bundle-row");y.append(v(t,"span","pp-bundle-key pp-bundle-addr",p.gameId),v(t,"span","pp-bundle-val",p.name)),a.append(y);for(let g of p.blocks){let w=v(t,"div","pp-bundle-row pp-bundle-sub");w.append(v(t,"span","pp-bundle-key pp-bundle-addr",g.gameId),v(t,"span","pp-bundle-val",g.name)),a.append(w)}}i.append(a);let l=n.hostScopes.reduce((p,y)=>p+y.properties.length,0),c=ee(t,"hostScopes","Host properties",l,s.has("hostScopes"));n.hostScopes.length||c.append(v(t,"div","pp-bundle-empty","the game supplies nothing"));for(let p of n.hostScopes){let y=v(t,"div","pp-bundle-row");y.append(v(t,"span","pp-bundle-key pp-bundle-addr",`@${p.token}`));let g=v(t,"span","pp-bundle-val",p.opaque?"any name, unchecked":`${p.properties.length} declared`);p.writable||g.append(v(t,"span","pp-bundle-tag","read-only")),y.append(g),c.append(y);for(let w of p.properties){let I=st(t,w);I.classList.add("pp-bundle-sub"),c.append(I)}}i.append(c);let d=n.properties.patter.length+n.properties.scene.reduce((p,y)=>p+y.properties.length,0),f=ee(t,"properties","Story properties",d,s.has("properties"));d||f.append(v(t,"div","pp-bundle-empty","none declared"));for(let p of n.properties.patter)f.append(st(t,p));for(let p of n.properties.scene){f.append(N(t,"@scene",p.gameId,"pp-bundle-val pp-bundle-addr"));for(let y of p.properties){let g=st(t,y);g.classList.add("pp-bundle-sub"),f.append(g)}}if(i.append(f),n.gameData.length){let p=ee(t,"gameData","Game data",n.gameData.reduce((y,g)=>y+g.fields.length,0),s.has("gameData"));for(let y of n.gameData){p.append(N(t,"on",y.kind));for(let g of y.fields){let w=v(t,"div","pp-bundle-row pp-bundle-sub");w.append(v(t,"span","pp-bundle-key pp-bundle-addr",g.name),v(t,"span","pp-bundle-val",g.type)),p.append(w)}}i.append(p)}let u=ee(t,"counts","Counts",null,s.has("counts"));for(let[p,y]of Object.entries(n.counts))u.append(N(t,p,String(y)));return i.append(u),e.container?.append(i),{el:i,description:n,destroy(){i.remove()}}}var Ne=class{constructor(e,t="main"){this.engine=e;this.flowId=t}engine;flowId;handlers={line:new Set,text:new Set,gameEvent:new Set,choice:new Set,ended:new Set};queued=0;delivering=!1;get flow(){return this.engine.getFlow(this.flowId)}on(e,t){let n=this.handlers[e];return n.add(t),()=>{n.delete(t)}}begin(e,t){let n=this.flow;if(!n||n.isClosed)this.engine.openFlow(this.flowId,{scene:e,block:t});else if(e===void 0){if(t!==void 0)throw new Error("Runner.begin: a block needs its scene");n.reset()}else if(!n.goto(e,t))throw new Error(`Runner.begin: address not found: ${e}${t===void 0?"":` / ${t}`}`);this.queued=0,this.next()}next(){if(!this.flow)throw new Error(`Runner.next: flow '${this.flowId}' isn't open; call begin() first`);if(this.queued++,!this.delivering){this.delivering=!0;try{for(;this.queued>0;)this.queued--,this.deliver(this.flow.advance())}finally{this.delivering=!1,this.queued=0}}}choose(e){let t=this.flow;if(!t)throw new Error(`Runner.choose: flow '${this.flowId}' isn't open; call begin() first`);t.choose(e),this.next()}stop(){this.queued=0}rebind(e){this.engine=e}deliver(e){switch(e.type){case"line":return this.emit("line",e);case"text":return this.emit("text",e);case"gameEvent":return this.emit("gameEvent",e);case"choice":return this.emit("choice",{groupId:e.groupId,options:e.options});case"end":return this.emit("ended",e.reason)}}emit(e,t){for(let n of[...this.handlers[e]])n(t)}};function wn(r,e){let n=JSON.parse(r).clips??{},s=e===""||/[/\\]$/.test(e)?"":"/";return{resolve(i){let o=n[i];return!o||!o.file?null:`${e}${s}${o.file}`}}}return Pn(kr);})();
36
+ `;function xr(r){if(r.getElementById(Sn))return;let e=r.createElement("style");e.id=Sn,e.textContent=wr,(r.head??r.documentElement).appendChild(e)}var x=(r,e,t,n)=>{let s=r.createElement(e);return t&&(s.className=t),n!==void 0&&(s.textContent=n),s};function A(r,e,t,n="pp-bundle-val"){let s=x(r,"div","pp-bundle-row");return s.append(x(r,"span","pp-bundle-key",e),x(r,"span",n,t)),s}function st(r,e){let t=x(r,"div","pp-bundle-row");t.append(x(r,"span","pp-bundle-key pp-bundle-addr",e.name));let n=x(r,"span","pp-bundle-val",e.type);return e.hasDefault||n.append(x(r,"span","pp-bundle-tag","no default")),t.append(n),t}function ee(r,e,t,n,s){let i=r.createElement("details");i.dataset.section=e,i.open=s;let o=r.createElement("summary");return o.textContent=t,n!==null&&o.append(x(r,"span","pp-bundle-count",` ${n}`)),i.append(o),i}function vn(r,e={}){let t=e.container?.ownerDocument??document;xr(t);let n=De(r),s=new Set(e.open??["identity","addresses"]),i=x(t,"div","pp-bundle");i.append(x(t,"h4",void 0,e.title??"Bundle"));let o=ee(t,"identity",n.identity.project||"(unnamed project)",null,s.has("identity"));n.identity.version&&o.append(A(t,"version",n.identity.version)),o.append(A(t,"schema",n.identity.schema)),o.append(A(t,"locales",`${n.identity.defaultLocale}${n.identity.locales.length>1?` (+${n.identity.locales.length-1})`:""}`)),o.append(A(t,"strings",n.identity.localisation)),n.identity.voiced&&o.append(A(t,"voiced","yes")),n.identity.hash&&o.append(A(t,"hash",n.identity.hash)),n.identity.structureHash&&o.append(A(t,"structure",n.identity.structureHash)),n.identity.sourceDebug&&o.append(A(t,"build","SOURCE DEBUG - not shippable","pp-bundle-val pp-bundle-warn")),i.append(o);let a=ee(t,"addresses","Addresses",n.addresses.length,s.has("addresses"));n.addresses.length||a.append(x(t,"div","pp-bundle-empty","no scenes"));for(let g of n.addresses){let b=x(t,"div","pp-bundle-row");b.append(x(t,"span","pp-bundle-key pp-bundle-addr",g.gameId),x(t,"span","pp-bundle-val",g.name)),a.append(b);for(let u of g.blocks){let E=x(t,"div","pp-bundle-row pp-bundle-sub");E.append(x(t,"span","pp-bundle-key pp-bundle-addr",u.gameId),x(t,"span","pp-bundle-val",u.name)),a.append(E)}}i.append(a);let l=n.hostScopes.reduce((g,b)=>g+b.properties.length,0),c=ee(t,"hostScopes","Host properties",l,s.has("hostScopes"));n.hostScopes.length||c.append(x(t,"div","pp-bundle-empty","the game supplies nothing"));for(let g of n.hostScopes){let b=x(t,"div","pp-bundle-row");b.append(x(t,"span","pp-bundle-key pp-bundle-addr",`@${g.token}`));let u=x(t,"span","pp-bundle-val",g.opaque?"any name, unchecked":`${g.properties.length} declared`);g.writable||u.append(x(t,"span","pp-bundle-tag","read-only")),b.append(u),c.append(b);for(let E of g.properties){let R=st(t,E);R.classList.add("pp-bundle-sub"),c.append(R)}}i.append(c);let d=n.properties.patter.length+n.properties.scene.reduce((g,b)=>g+b.properties.length,0),p=ee(t,"properties","Story properties",d,s.has("properties"));d||p.append(x(t,"div","pp-bundle-empty","none declared"));for(let g of n.properties.patter)p.append(st(t,g));for(let g of n.properties.scene){p.append(A(t,"@scene",g.gameId,"pp-bundle-val pp-bundle-addr"));for(let b of g.properties){let u=st(t,b);u.classList.add("pp-bundle-sub"),p.append(u)}}if(i.append(p),n.gameData.length){let g=ee(t,"gameData","Game data",n.gameData.reduce((b,u)=>b+u.fields.length,0),s.has("gameData"));for(let b of n.gameData){g.append(A(t,"on",b.kind));for(let u of b.fields){let E=x(t,"div","pp-bundle-row pp-bundle-sub");E.append(x(t,"span","pp-bundle-key pp-bundle-addr",u.name),x(t,"span","pp-bundle-val",u.type)),g.append(E)}}i.append(g)}let h=ee(t,"counts","Counts",null,s.has("counts"));for(let[g,b]of Object.entries(n.counts))h.append(A(t,g,String(b)));return i.append(h),e.container?.append(i),{el:i,description:n,destroy(){i.remove()}}}var Le=class{constructor(e,t="main"){this.engine=e;this.flowId=t}engine;flowId;handlers={line:new Set,text:new Set,gameEvent:new Set,choice:new Set,ended:new Set};queued=0;delivering=!1;get flow(){return this.engine.getFlow(this.flowId)}on(e,t){let n=this.handlers[e];return n.add(t),()=>{n.delete(t)}}begin(e,t){let n=this.flow;if(!n||n.isClosed)this.engine.openFlow(this.flowId,{scene:e,block:t});else if(e===void 0){if(t!==void 0)throw new Error("Runner.begin: a block needs its scene");n.reset()}else if(!n.goto(e,t))throw new Error(`Runner.begin: address not found: ${e}${t===void 0?"":` / ${t}`}`);this.queued=0,this.next()}next(){if(!this.flow)throw new Error(`Runner.next: flow '${this.flowId}' isn't open; call begin() first`);if(this.queued++,!this.delivering){this.delivering=!0;try{for(;this.queued>0;)this.queued--,this.deliver(this.flow.advance())}finally{this.delivering=!1,this.queued=0}}}choose(e){let t=this.flow;if(!t)throw new Error(`Runner.choose: flow '${this.flowId}' isn't open; call begin() first`);t.choose(e),this.next()}stop(){this.queued=0}rebind(e){this.engine=e}deliver(e){switch(e.type){case"line":return this.emit("line",e);case"text":return this.emit("text",e);case"gameEvent":return this.emit("gameEvent",e);case"choice":return this.emit("choice",{groupId:e.groupId,options:e.options});case"end":return this.emit("ended",e.reason)}}emit(e,t){for(let n of[...this.handlers[e]])n(t)}};function wn(r,e){let n=JSON.parse(r).clips??{},s=e===""||/[/\\]$/.test(e)?"":"/";return{resolve(i){let o=n[i];return!o||!o.file?null:`${e}${s}${o.file}`}}}return Pn(Er);})();
37
37
  //# sourceMappingURL=patterplay.min.js.map