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