@patterkit/play-helpers 0.14.0 → 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
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.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=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=`
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}