@patterkit/cli 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +132 -4
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -194028,7 +194028,7 @@ function bundleOutputPath(loaded) {
|
|
|
194028
194028
|
}
|
|
194029
194029
|
|
|
194030
194030
|
// ../ops/src/playable-runtime.ts
|
|
194031
|
-
var PLAYABLE_RUNTIME_JS = '"use strict";var Patterplay=(()=>{var P=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var de=Object.prototype.hasOwnProperty;var ue=(s,e)=>{for(var t in e)P(s,t,{get:e[t],enumerable:!0})},ge=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of pe(e))!de.call(s,n)&&n!==t&&P(s,n,{get:()=>e[n],enumerable:!(r=le(e,n))||r.enumerable});return s};var fe=s=>ge(P({},"__esModule",{value:!0}),s);var De={};ue(De,{Engine:()=>B,Flow:()=>v,buildTagIndex:()=>O,effectiveGameData:()=>oe,gameDataFields:()=>ie,gameDataValue:()=>j});function S(s){switch(s[0]){case"b":return{kind:"bool",value:s[1]};case"n":return{kind:"number",value:s[1]};case"s":return{kind:"string",value:s[1]};case"sv":return{kind:"scopedvar",scope:s[1],name:s[2]};case"u":return{kind:"unary",op:s[1],operand:S(s[2])};case"bin":return{kind:"binary",op:s[1],left:S(s[2]),right:S(s[3])};case"call":{let e=s.slice(2).map(S);return{kind:"call",name:s[1],args:e}}case"fd":return{kind:"flagdelta",sign:s[1],name:s[2]}}}var p=class extends Error{constructor(e){super(e),this.name="EvalError"}};function E(s,e,t){let r=new Map(t.scopes.map(i=>[i.token,i.missing??"false"])),n=i=>{switch(i.kind){case"bool":return i.value;case"number":return i.value;case"string":return i.value;case"scopedvar":{let o=e.scopes[i.scope];if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):o[i.name];if(a===void 0){if(r.get(i.scope)==="throw")throw new p(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{let o=t.functions[i.name];if(!o)throw new p(`unknown function \'${i.name}\'`);return o.eval(i.args,{evaluate:n,ctx:e})}case"flagdelta":throw new p("flagdelta node is only valid as an argument to a flag-delta function");case"unary":{if(i.op==="not"){let a=n(i.operand);if(typeof a!="boolean")throw new p(`\'not\' requires a boolean operand, got ${typeof a}`);return!a}let o=n(i.operand);if(typeof o!="number")throw new p(`unary \'-\' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let l=n(i.left);if(typeof l!="boolean")throw new p(`\'and\' requires boolean operands, left is ${typeof l}`);if(!l)return!1;let c=n(i.right);if(typeof c!="boolean")throw new p(`\'and\' requires boolean operands, right is ${typeof c}`);return c}if(i.op==="or"){let l=n(i.left);if(typeof l!="boolean")throw new p(`\'or\' requires boolean operands, left is ${typeof l}`);if(l)return!0;let c=n(i.right);if(typeof c!="boolean")throw new p(`\'or\' requires boolean operands, right is ${typeof c}`);return c}let o=n(i.left),a=n(i.right);switch(i.op){case"==":return U(o,a);case"!=":return!U(o,a);case">":return y(o,a,">"),o>a;case">=":return y(o,a,">="),o>=a;case"<":return y(o,a,"<"),o<a;case"<=":return y(o,a,"<="),o<=a;case"+":if(typeof o=="number"&&typeof a=="number"||typeof o=="string"&&typeof a=="string")return o+a;throw new p(`\'+\' requires two numbers or two strings, got ${typeof o} and ${typeof a}`);case"-":return y(o,a,"-"),o-a;case"*":return y(o,a,"*"),o*a;case"/":if(y(o,a,"/"),a===0)throw new p("division by zero");return o/a}}}};return n(s)}function U(s,e){if(Array.isArray(s)||Array.isArray(e)){if(!Array.isArray(s)||!Array.isArray(e)||s.length!==e.length)return!1;for(let t=0;t<s.length;t++)if(s[t]!==e[t])return!1;return!0}return s===e}function y(s,e,t){if(typeof s!="number"||typeof e!="number")throw new p(`\'${t}\' requires numeric operands, got ${typeof s} and ${typeof e}`)}var he={name:"check_flags",count:s=>Math.max(1,s.args.length-1)},me=[he];function W(s,e,t){let r=t?.countingCalls??me;return C(s,t?.want??!0,e,r)}function C(s,e,t,r){if(s.kind==="binary"&&(s.op==="and"||s.op==="or")){let n=C(s.left,e,t,r),i=C(s.right,e,t,r);return s.op==="and"===e?n>0&&i>0?n+i:0:Math.max(n,i)}if(s.kind==="unary"&&s.op==="not")return C(s.operand,!e,t,r);if(s.kind==="call"){let n=r.find(i=>i.name===s.name);if(n){let i=n.count(s),o=t(s);return e?o?i:0:o?0:1}}return t(s)===e?1:0}var w=class{scopes=new Map;defineOwned(e,t){this.assertFree(e);let r={},n=new Map;for(let i of t){let o=i.name.toLowerCase();n.set(o,i),r[o]=i.default??K(i)}return this.scopes.set(e,{kind:"owned",bag:r,decls:n}),this}reseedOwned(e,t){let r=this.scopes.get(e);if(!r||r.kind!=="owned")throw new Error(`\'@${e}\' is not an owned scope`);for(let n of Object.keys(r.bag))delete r.bag[n];r.decls.clear();for(let n of t){let i=n.name.toLowerCase();r.decls.set(i,n),r.bag[i]=n.default??K(n)}return this}defineForeign(e,t,r=[],n=!0){this.assertFree(e);let i=new Map;for(let o of r)i.set(o.name.toLowerCase(),o);return this.scopes.set(e,{kind:"foreign",resolver:t,decls:i,scopeWritable:n}),this}has(e){return this.scopes.has(e)}get(e,t){let r=this.scopes.get(e);if(!r)return;let n=t.toLowerCase();return r.kind==="owned"?r.bag[n]:r.resolver.get(n)}set(e,t,r){let n=this.scopes.get(e);if(!n)throw new Error(`unknown scope \'@${e}\'`);let i=t.toLowerCase();if(!this.writable(n,i))throw new Error(`\'@${e}.${t}\' is read-only`);n.kind==="owned"?n.bag[i]=r:n.resolver.set(i,r)}writable(e,t){return e.kind==="owned"?e.decls.get(t)?.writable??!0:e.resolver.set?e.decls.get(t)?.writable??e.scopeWritable:!1}toEvalContext(e){let t={};for(let[r,n]of this.scopes)t[r]=n.kind==="owned"?n.bag:n.resolver;return{scopes:t,host:e}}toSchema(){let e=new Map;for(let[t,r]of this.scopes){if(r.decls.size===0)continue;let n=new Map;for(let[i,o]of r.decls)n.set(i,{type:o.type,enumValues:o.values});e.set(t,n)}return{properties:e}}save(){let e={};for(let[t,r]of this.scopes)r.kind==="owned"&&(e[t]={...r.bag});return e}load(e){for(let[t,r]of Object.entries(e)){let n=this.scopes.get(t);n?.kind==="owned"&&Object.assign(n.bag,r)}}assertFree(e){if(this.scopes.has(e))throw new Error(`scope \'@${e}\' is already registered`)}};function K(s){if(s.default!==void 0)return s.default;switch(s.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"enum":return s.values?.[0]??"";case"flags":return[]}}function x(s){return s.ctx.host??{}}var T={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(s,e){if(s.length!==2)throw new p("random(a, b) requires exactly 2 arguments");let t=x(e).nextRandom;if(!t)throw new p("random() called without a PRNG in context");let r=e.evaluate(s[0]),n=e.evaluate(s[1]);if(typeof r!="number"||typeof n!="number")throw new p("random(a, b) arguments must be numbers");if(!Number.isInteger(r)||!Number.isInteger(n))throw new p("random(a, b) arguments must be integers");let i=Math.min(r,n),o=Math.max(r,n);return Math.floor(t()*(o-i+1))+i}},check_flags:{minArgs:1,returnType:"boolean",flagDeltaArgs:!0,validate:z("check_flags"),eval(s,e){let t=J(s[0],e,"check_flags");for(let r=1;r<s.length;r++){let n=s[r];if(n.kind!=="flagdelta")throw new p("check_flags() flag args must be +flagName or -flagName");if(n.sign==="+"?!t.includes(n.name):t.includes(n.name))return!1}return!0}},set_flags:{minArgs:1,returnType:"flags",flagDeltaArgs:!0,validate:z("set_flags"),eval(s,e){let t=[...J(s[0],e,"set_flags")];for(let r=1;r<s.length;r++){let n=s[r];if(n.kind!=="flagdelta")throw new p("set_flags() flag args must be +flagName or -flagName");if(n.sign==="+")t.includes(n.name)||t.push(n.name);else{let i=t.indexOf(n.name);i>=0&&t.splice(i,1)}}return t}},visits:{minArgs:1,maxArgs:1,returnType:"number",validate:I("visits"),eval:(s,e)=>x(e).visits?.(D(s,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:I("seen"),eval:(s,e)=>(x(e).visits?.(D(s,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:I("patter_visits"),eval:(s,e)=>x(e).patterVisits?.(D(s,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:I("patter_seen"),eval:(s,e)=>(x(e).patterVisits?.(D(s,e,"patter_seen"))??0)>0}}};function F(s,e){let t=s.replace(/^@/,"").split(".");return t.length===2&&e(t[0])?{scope:t[0],name:t[1].toLowerCase()}:{scope:"patter",name:t.join(".").toLowerCase()}}function D(s,e,t){let r=e.evaluate(s[0]);if(typeof r!="string")throw new p(`${t}(id) requires a string node id`);return r}function I(s){return(e,t)=>{let r=e[0];r&&r.kind!=="string"&&t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${s}(id): the argument must be a string id literal (a scene / block / node id)`})}}function J(s,e,t){if(!s)throw new p(`${t}() requires at least one argument (the flags variable)`);let r=e.evaluate(s);if(Array.isArray(r))return r;if(r===!1||r===null||r===void 0)return[];throw new p(`${t}() first argument must be a flags property`)}function z(s){return(e,t)=>{if(e.length===0)return;let r=e[0];if(r.kind!=="scopedvar"){t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${s}(): first argument must be a flags property reference (@name or @scope.name)`});return}let n=t.schema.properties.get(r.scope)?.get(r.name);if(n&&n.type!=="flags"){let i=r.scope===t.defaultScope?r.name:`${r.scope}.${r.name}`;t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${s}(): \'@${i}\' is not a flags property (got ${n.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:`${s}(): argument ${i+1} must be +flagName or -flagName`}):n?.type==="flags"&&n.enumValues&&!n.enumValues.includes(o.name)&&t.report({path:[...t.path,"args",i],kind:"unknown-flag-name",severity:"error",message:`${s}(): unknown flag \'${o.name}\'`,reference:o.name})}}}var Se=/^@[A-Za-z0-9_.]+$/;function*ye(s){let e="",t=0;for(;t<s.length;){let r=s[t];if(r==="{"&&s[t+1]==="{"){e+="{",t+=2;continue}if(r==="}"&&s[t+1]==="}"){e+="}",t+=2;continue}if(r==="{"){let n=s.indexOf("}",t+1);if(n!==-1){let i=s.slice(t,n+1),o=s.slice(t+1,n).trim();if(o.startsWith("@")){e&&(yield{kind:"text",value:e},e=""),yield{kind:"slot",raw:i,inner:o,ref:Se.test(o)?o:void 0},t=n+1;continue}e+=i,t=n+1;continue}}e+=r,t+=1}e&&(yield{kind:"text",value:e})}function be(s){return Array.isArray(s)?s.join(", "):typeof s=="boolean"?s?"true":"false":String(s)}function ve(s){return s===" "||s===" "||s===`\n`||s==="\\r"||s==="\\f"||s==="\\v"}function we(s){let e="",t=!1;for(let r of s){if(ve(r)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=r}return e}function X(s,e,t){if(e.length===0||s.indexOf(e)<0)return s;let r="",n=0,i=!1;for(;n<s.length;){if(s.startsWith(e,n)){let o=s.indexOf(t,n+e.length);if(o>=0){n=o+t.length,i=!0;continue}r+=s.slice(n);break}r+=s[n],n+=1}return i?we(r):s}function Z(s,e){if(s.indexOf("{")<0)return s;let t="";for(let r of ye(s)){if(r.kind==="text"){t+=r.value;continue}if(!r.ref){t+=r.raw;continue}let n=e(r.ref);t+=n===void 0?"":be(n)}return t}function k(s,e){for(let t of s){e(t);let r=t.children;r&&k(r,e)}}function xe(s){return s.toLowerCase().replace(/[\'\u2019]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function h(s){let e=s.gameId?.trim();return e||xe(s.name)}function V(s){return`cast:${s}`}var G={open:"[",close:"]"},Q="SFX";function R(s){let e=new Set,t=[];for(let r of s)e.has(r)||(e.add(r),t.push(r));return t}function O(s){let e=new Map,t=(r,n)=>{let i=R([...n,...r.tags??[]]);if(e.set(r.id,i),r.type==="group")for(let o of r.children)t(o,i);else for(let o of r.beats??[])e.set(o.id,R([...i,...o.tags??[]]))};for(let r of Object.values(s.scenes)){let n=R(r.tags??[]);e.set(r.id,n);for(let i of r.blocks){let o=R([...n,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var Y=new WeakMap,B=class s{host;defaultSeed;flowsById=new Map;allStrings;currentLocale;sourceDebug;sceneGameIdToId=new Map;blockGameIdToId=new Map;creationOptions;constructor(e,t={}){this.creationOptions=t;let r=t.locale??e.locales.default,n=e.strings;this.allStrings=n,this.currentLocale=r;let i=n[r]??{},o=n[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 d of e.cast??[])d.displayName&&c.set(d.name,d.displayName);this.defaultSeed=(t.seed??2654435769)>>>0;let u=new Map,g=new Map,L=new Map;for(let[d,m]of Object.entries(e.scenes)){this.sceneGameIdToId.set(h(m),d);let b=new Map;for(let f of m.blocks)g.set(f.id,{sceneId:d}),L.set(f.id,f),b.set(h(f),f.id),k(f.children,q=>u.set(q.id,q));this.blockGameIdToId.set(d,b)}let $=e.properties??[],N=$.filter(d=>d.shared??!0).map(ee),ae=$.filter(d=>!(d.shared??!0)).map(ee),ce=new Set(N.map(d=>d.name.toLowerCase())),A=new w().defineOwned("patter",N),_=new Set;if(t.world){let d=e.scopeRegistry?.scopes.find(b=>b.token==="world"),m=(d?.declarations??[]).map(te);A.defineForeign("world",t.world,m,d?.writable??!0),_.add("world")}for(let d of e.scopeRegistry?.scopes??[]){if(_.has(d.token))continue;let m=(d.declarations??[]).map(te);A.defineForeign(d.token,Ce(d.declarations??[]),m,d.writable??!0)}let H=new Map;for(let[d,m]of Object.entries(e.scenes)){let b=new Set((m.sceneProps??[]).filter(f=>f.shared??!1).map(f=>f.name.toLowerCase()));H.set(d,b)}this.host={bundle:e,emitIds:l,strings:i,defaultStrings:o,castDisplay:c,nodeIndex:u,blockIndex:g,blockById:L,tagIndex:O(e),shared:A,patterSharedDecls:N,patterLocalDecls:ae,patterSharedNames:ce,sceneSharedNames:H,sharedVisits:new Map,sharedSelectors:new Map,stageBags:new Map,customRng:t.rng,onDryChoice:t.onDryChoice,replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??G).open,captionClose:(e.closedCaptions??G).close,captionCharacter:e.closedCaptions?.character||Q,refSplitCache:new Map}}get locale(){return this.currentLocale}get isSourceDebug(){return this.sourceDebug}setLocale(e){this.currentLocale=e,this.host.strings=this.allStrings[e]??{}}replaceStrings(e){this.allStrings=e.strings,this.host.strings=this.allStrings[this.currentLocale]??{},this.host.defaultStrings=this.allStrings[this.host.bundle.locales.default]??{}}hotSwap(e){let t=this.saveGame(),r=i=>(i.setLocale(this.currentLocale),i.setClosedCaptions(this.host.captionsOn),i),n=new s(e,this.creationOptions);try{return n.loadGame(t),r(n)}catch{let i=new s(e,this.creationOptions);for(let[o,a]of Object.entries(t.flows)){let l=a.cursor.currentSceneId;try{i.openFlow(o,l!==null?{scene:l}:{})}catch{}}return r(i)}}get closedCaptions(){return this.host.captionsOn}setClosedCaptions(e){this.host.captionsOn=e}openFlow(e,t={}){let r=this.resolveSceneRef(t.scene),n=this.resolveBlockRef(r,t.block),i=new v(e,this.host,t.seed??this.defaultSeed);return this.flowsById.set(e,i),i.start(r,n),i}resolveSceneRef(e){if(e!=null)return this.host.bundle.scenes[e]?e:this.sceneGameIdToId.get(e)??e}resolveBlockRef(e,t){if(t!=null){if(this.host.blockById.has(t))return t;if(e!=null){let r=this.blockGameIdToId.get(e)?.get(t);if(r)return r}return t}}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?h(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?h(t):void 0}tagsForBeat(e){return this.host.tagIndex.get(e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?this.host.tagIndex.get(t):void 0)??[]}tagsForBlock(e,t){let r=this.resolveSceneRef(e),n=this.resolveBlockRef(r,t);return(n!=null?this.host.tagIndex.get(n):void 0)??[]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...h(e)?{gameId:h(e)}:{},name:e.name,...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...h(t)?{gameId:h(t)}:{},name:t.name,...this.tagsField(t.id),children:t.children.map(r=>this.outlineNode(r))}))}))}getBeatSequence(){let e=[];for(let t of Object.values(this.host.bundle.scenes))for(let r of t.blocks)k(r.children,n=>{if(n.type==="snippet")for(let i of n.beats??[])e.push({sceneId:t.id,blockId:r.id,snippetId:n.id,beat:this.beatInfo(i)})});return e}outlineNode(e){return e.type==="group"?{type:"group",id:e.id,...this.tagsField(e.id),...e.selector?{selector:e.selector}:{},...e.prompt?{prompt:this.beatInfo(e.prompt)}:{},children:e.children.map(t=>this.outlineNode(t))}:{type:"snippet",id:e.id,...this.tagsField(e.id),beats:(e.beats??[]).map(t=>this.beatInfo(t)),...e.jump?{jumpTo:e.jump.to,...e.jump.mode?{jumpMode:e.jump.mode}:{}}:{}}}beatInfo(e){let t=this.host.tagIndex.get(e.id),r={id:e.id,kind:e.kind};if(e.kind==="line"){if(e.character!==void 0){r.character=e.character;let n=this.host.defaultStrings[V(e.character)]??this.host.castDisplay.get(e.character);n!==void 0&&(r.characterName=n)}e.direction!==void 0&&(r.direction=e.direction)}if(e.kind==="line"||e.kind==="text"){let n=this.host.defaultStrings[e.id];n!==void 0&&(r.text=n)}return e.gameData&&Object.keys(e.gameData).length&&(r.gameData=e.gameData),t&&t.length&&(r.tags=t),r}tagsField(e){let t=this.host.tagIndex.get(e);return t&&t.length?{tags:t}:{}}getFlow(e){return this.flowsById.get(e)}flows(){return[...this.flowsById.values()]}closeFlow(e){this.flowsById.delete(e)}reset(){this.flowsById.clear(),this.host.shared.reseedOwned("patter",this.host.patterSharedDecls),this.host.sharedVisits.clear(),this.host.sharedSelectors.clear(),this.host.stageBags.clear()}getProperty(e){let{scope:t,name:r}=this.splitShared(e);return this.host.shared.get(t,r)}setProperty(e,t){let{scope:r,name:n}=this.splitShared(e);this.host.shared.set(r,n,t)}listProperties(){return this.host.patterSharedDecls.map(e=>({ref:`@${e.name}`,type:e.type,values:e.values,value:this.getProperty(`@${e.name}`),default:ke(e)}))}splitShared(e){let t=this.host.refSplitCache.get(e);if(t||(t=F(e,r=>r==="scene"||this.host.shared.has(r)),this.host.refSplitCache.set(e,t)),t.scope==="scene")throw new Error(`\'${e}\': @scene properties are scene-scoped - read/write them on a Flow, not the Engine`);return t}save(){return this.host.shared.save()}load(e){this.host.shared.load(e)}saveGame(){let e={};for(let[t,r]of this.flowsById)e[t]=r.snapshot();return{version:2,shared:this.host.shared.save(),sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:ne(this.host.sharedSelectors),stageBags:Object.fromEntries([...this.host.stageBags].map(([t,r])=>[t,{...r}])),flows:e}}loadGame(e){if(e.version!==2)throw new Error(`unsupported save version: ${e.version}`);this.host.shared.load(e.shared),this.host.sharedVisits.clear();for(let[t,r]of Object.entries(e.sharedVisits??{}))this.host.sharedVisits.set(t,r);this.host.sharedSelectors.clear();for(let[t,r]of se(e.sharedSelectors))this.host.sharedSelectors.set(t,r);this.host.stageBags.clear();for(let[t,r]of Object.entries(e.stageBags??{}))this.host.stageBags.set(t,{...r});this.flowsById.clear();for(let[t,r]of Object.entries(e.flows)){let n=new v(t,this.host,this.defaultSeed);n.restore(r),this.flowsById.set(t,n)}}},v=class{id;host;local;rngState;started=!1;flowEnded=!1;currentSceneId=null;stack=[];activeSnippet=null;beatIndex=0;pendingChoice=null;pendingPromptBeat=null;pendingPromptOwnerId=null;selectors=new Map;visitCounts=new Map;sceneBags=new Map;patterResolver={get:e=>this.host.patterSharedNames.has(e)?this.host.shared.get("patter",e):this.local.get("patter",e),set:(e,t)=>{this.host.patterSharedNames.has(e)?this.host.shared.set("patter",e,t):this.local.set("patter",e,t)}};sceneResolver={get:e=>{let t=this.currentSceneId;return t===null?void 0:(this.host.sceneSharedNames.get(t)?.has(e)?this.host.stageBags.get(t):this.sceneBags.get(t))?.[e]},set:(e,t)=>{let r=this.currentSceneId;if(r===null)return;let n=this.host.sceneSharedNames.get(r)?.has(e)?this.host.stageBags.get(r):this.sceneBags.get(r);n&&(n[e]=t)}};evalCtx;constructor(e,t,r){this.id=e,this.host=t,this.rngState=r>>>0,this.local=this.freshLocal();let n={...t.shared.toEvalContext().scopes};n.patter=this.patterResolver,n.scene=this.sceneResolver,this.evalCtx={scopes:n,host:{nextRandom:this.rng,visits:i=>this.visitCounts.get(i)??0,patterVisits:i=>this.host.sharedVisits.get(i)??0}}}start(e,t){if(this.sceneBags.clear(),this.local=this.freshLocal(),this.selectors.clear(),this.visitCounts.clear(),this.stack=[],this.currentSceneId=null,this.flowEnded=!1,this.activeSnippet=null,this.beatIndex=0,this.pendingChoice=null,this.started=!0,t){let r=this.host.blockIndex.get(t);if(!r)throw new Error(`unknown block: ${t}`);this.enterSceneSetup(r.sceneId),this.stack=[{sceneId:r.sceneId,containerId:t,index:0}],this.enter(t)}else{let r=e??Object.keys(this.host.bundle.scenes)[0],n=r?this.host.bundle.scenes[r]:void 0;if(!n)throw new Error(r?`unknown scene: ${r}`:"no scenes in bundle");this.enterSceneSetup(r);let i=n.blocks[0];i&&(this.stack=[{sceneId:r,containerId:i.id,index:0}],this.enter(i.id))}this.settle()}reset(e,t){this.start(e,t)}get currentScene(){return this.currentSceneId}advance(){if(!this.started)throw new Error("flow has not been started");if(this.pendingPromptBeat){let e=this.pendingPromptBeat;return this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.beatResult(e)}return this.settle(),this.flowEnded?{type:"end"}:this.pendingChoice?{type:"choice",groupId:this.pendingChoice.groupId,options:this.pendingChoice.options}:this.activeSnippet?this.beatResult(this.activeSnippet.beats[this.beatIndex++]):(this.flowEnded=!0,{type:"end"})}advanceToStop(){let e=[];for(;;){let t=this.advance();if(t.type==="choice"||t.type==="end")return{played:e,stop:t};e.push(t)}}settle(){let e=0;for(;;){if(++e>1e4)throw new Error("flow did not settle after 10000 transitions - likely a jump cycle with no deliverable content");if(this.flowEnded||this.pendingChoice)return;if(this.activeSnippet){if(this.beatIndex<(this.activeSnippet.beats?.length??0))return;this.runEffects(this.activeSnippet.onExit);let n=this.activeSnippet.jump;this.activeSnippet=null,this.beatIndex=0,this.resolveJump(n);continue}let t=this.stack[this.stack.length-1];if(!t){this.flowEnded=!0;return}t.sceneId!==this.currentSceneId&&(this.currentSceneId=t.sceneId);let r=this.childrenOf(t.containerId);if(!r){this.stack.pop();continue}for(;t.index<r.length&&!this.eligible(r[t.index]);)t.index++;if(t.index>=r.length){this.stack.pop();continue}this.enterChild(r[t.index++])}}getChoices(){return this.pendingChoice?.options??[]}choose(e){let t=this.pendingChoice;if(!t)throw new Error("no choice is pending");let r=t.options.find(i=>i.id===e);if(!r)throw new Error(`unknown choice option: ${e}`);if(!r.eligible)throw new Error(`choice option is not eligible: ${e}`);let n=t.byId.get(e);this.pendingChoice=null,this.pendingPromptBeat=this.host.replayPromptOnChoose?this.promptBeatOf(n)??null:null,this.pendingPromptOwnerId=this.pendingPromptBeat?n.id:null,this.enterChild(n)}isEnded(){return this.flowEnded}getProperty(e){let{scope:t,name:r}=this.splitRef(e);return t==="patter"?this.patterResolver.get(r):t==="scene"?this.sceneResolver.get(r):this.host.shared.get(t,r)}setProperty(e,t){let{scope:r,name:n}=this.splitRef(e);if(r==="patter")this.patterResolver.set(n,t);else if(r==="scene"){if(this.currentSceneId===null)throw new Error(`\'${e}\': the flow has not entered a scene yet`);this.sceneResolver.set(n,t)}else this.host.shared.set(r,n,t)}snapshot(){return{scopes:this.local.save(),sceneBags:Object.fromEntries([...this.sceneBags].map(([e,t])=>[e,{...t}])),rngState:this.rngState,visits:Object.fromEntries(this.visitCounts),cursor:{flowEnded:this.flowEnded,currentSceneId:this.currentSceneId,stack:this.stack.map(e=>{let t=this.childrenOf(e.containerId)?.[e.index];return t?{...e,nextId:t.id}:{...e}}),activeSnippetId:this.activeSnippet?.id??null,beatIndex:this.beatIndex,pendingChoice:this.pendingChoice?{groupId:this.pendingChoice.groupId,options:this.pendingChoice.options.map(e=>({...e}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,selectors:ne(this.selectors)}}}restore(e){this.rngState=e.rngState>>>0,this.visitCounts=new Map(Object.entries(e.visits??{}));let t=e.cursor;if(this.started=!0,this.flowEnded=t.flowEnded,this.beatIndex=t.beatIndex,this.currentSceneId=t.currentSceneId,this.stack=t.stack.map(r=>{let{nextId:n,...i}=r;if(n!==void 0){let o=this.childrenOf(i.containerId)?.findIndex(a=>a.id===n)??-1;if(o>=0)return{...i,index:o}}return{...i}}),this.sceneBags=new Map(Object.entries(e.sceneBags??{}).map(([r,n])=>[r,{...n}])),this.local=this.freshLocal(),this.local.load(e.scopes),this.activeSnippet=null,t.activeSnippetId!==null){let r=this.host.nodeIndex.get(t.activeSnippetId);r&&r.type==="snippet"&&(this.activeSnippet=r)}if(this.selectors=se(t.selectors),this.pendingChoice=null,t.pendingChoice!==null){let r=new Map,n=[];for(let i of t.pendingChoice.options){let o=this.host.nodeIndex.get(i.id);o&&(r.set(i.id,o),n.push({...i}))}n.length>0&&(this.pendingChoice={groupId:t.pendingChoice.groupId,options:n,byId:r})}if(this.pendingPromptBeat=null,this.pendingPromptOwnerId=t.pendingPromptOwnerId??null,this.pendingPromptOwnerId){let r=this.host.nodeIndex.get(this.pendingPromptOwnerId);this.pendingPromptBeat=r?this.promptBeatOf(r)??null:null,this.pendingPromptBeat||(this.pendingPromptOwnerId=null)}}enterSceneSetup(e){let t=this.host.bundle.scenes[e];if(!t)throw new Error(`unknown scene: ${e}`);this.currentSceneId=e,this.enter(e),this.seedScene(t),this.runEffects(t.onEntry)}enterChild(e){if(this.enter(e.id),e.type==="snippet"){this.beginSnippet(e);return}let t=e.selector??"run";if(t==="run"){this.stack.push({sceneId:this.currentSceneId,containerId:e.id,index:0});return}if(t==="choice"){this.setupChoice(e);return}let r=this.selectChild(e);r&&this.enterChild(r)}childrenOf(e){let t=this.host.blockById.get(e);if(t)return t.children;let r=this.host.nodeIndex.get(e);if(r&&r.type==="group")return r.children}beginSnippet(e){this.runEffects(e.onEnter),this.activeSnippet=e,this.beatIndex=0}setupChoice(e){let t=[],r=new Map,n=[];for(let o of e.children){if(o.fallback===!0){n.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,prompt:this.promptFor(o),eligible:a,gameData:o.gameData}),r.set(o.id,o))}if(t.length>0){this.pendingChoice={groupId:e.id,options:t,byId:r};return}let i=n.find(o=>this.eligible(o));if(i){this.enterChild(i);return}this.host.onDryChoice?.(e.id)}resolveJump(e){e&&this.enterTarget(e.to,e.mode==="call"?"call":"jump")}enterTarget(e,t){if(e==="END"){this.flowEnded=!0,this.stack=[];return}let r,n,i=this.host.bundle.scenes[e];if(i){this.enterSceneSetup(e);let a=i.blocks[0];if(!a){t==="jump"&&(this.stack=[]);return}r=e,n=a.id}else{let a=this.host.blockIndex.get(e);if(!a)throw new Error(`jump target not found: ${e}`);a.sceneId!==this.currentSceneId&&this.enterSceneSetup(a.sceneId),r=a.sceneId,n=e}this.enter(n);let o={sceneId:r,containerId:n,index:0};t==="call"?this.stack.push(o):this.stack=[o]}selectChild(e){let t=e.children.filter(n=>this.eligible(n));if(t.length===0)return null;let r=this.selectorState(e);switch(e.selector){case"branch":return t[0];case"sequence":{let n=e.options?.order??"sequential",i=e.options?.exhaust??"once";return n==="shuffle"?this.pickShuffle(t,i,r):n==="specificity"?this.pickSpecificity(t,i,r):this.pickSequential(t,i,r)}default:return null}}pickSequential(e,t,r){let n=e.length,i=r.seq??0;return r.seq=i+1,t==="repeat"?e[i%n]:i<n?e[i]:t==="stick"?e[n-1]:null}pickShuffle(e,t,r){let n=e.length,i=t==="stick",o=()=>(i?e.slice(0,n-1):e).map(g=>g.id);if(r.bag===void 0&&(r.bag=o()),r.bag.length===0){if(t==="once")return null;if(i){let g=e[n-1];return r.last=g.id,g}r.bag=o()}let a=r.bag,l=r.last!==void 0&&a.length>1?a.indexOf(r.last):-1,c=Math.floor(this.rng()*(l>=0?a.length-1:a.length));l>=0&&c>=l&&c++;let u=a[c];return a.splice(c,1),r.last=u,e.find(g=>g.id===u)}pickSpecificity(e,t,r){let n=e;if(t!=="repeat"){r.bag===void 0&&(r.bag=e.map(u=>u.id));let c=new Set(r.bag);if(n=e.filter(u=>c.has(u.id)),n.length===0)return t==="stick"&&r.last!==void 0?e.find(u=>u.id===r.last)??null:null}let i=-1,a=n.map(c=>{let u=this.specScore(c);return u>i&&(i=u),{c,s:u}}).filter(c=>c.s===i).map(c=>c.c),l;if(a.length===1)l=a[0];else{let c=r.last!==void 0?a.findIndex(g=>g.id===r.last):-1,u=Math.floor(this.rng()*(c>=0?a.length-1:a.length));c>=0&&u>=c&&u++,l=a[u]}return t!=="repeat"&&(r.bag=r.bag.filter(c=>c!==l.id)),r.last=l.id,l}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0):0}matchedSpec(e,t){return W(e,n=>re(E(n,this.evalCtx,T)),{want:t})}selectorState(e){let t=e.shared?this.host.sharedSelectors:this.selectors,r=t.get(e.id);return r||(r={},t.set(e.id,r)),r}runEffects(e){for(let t of e??[])this.setProperty(t.target,this.evalExpr(t.value))}eligible(e){return e.condition?re(this.evalExpr(e.condition)):!0}evalExpr(e){return E(this.conditionAst(e),this.evalCtx,T)}conditionAst(e){let t=Y.get(e);return t||(t=S(e.ast),Y.set(e,t)),t}enter(e){this.visitCounts.set(e,(this.visitCounts.get(e)??0)+1),this.host.sharedVisits.set(e,(this.host.sharedVisits.get(e)??0)+1)}rng=()=>{if(this.host.customRng)return this.host.customRng();let e=this.rngState+1831565813|0;this.rngState=e;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};beatResult(e){let t=this.host.tagIndex.get(e.id),r=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:e.gameData,...r};case"text":return{type:"text",id:e.id,text:this.interpolate(this.resolveString(e.id)),gameData:e.gameData,...r};case"line":{let n=this.resolveString(e.id),i=!this.host.captionsOn,a=i&&e.character===this.host.captionCharacter?"":this.captionLine(this.host.bundle.voiced?n:this.interpolate(n)),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,gameData:e.gameData,...r}}}}interpolate(e){return Z(e,t=>this.getProperty(t))}stripCaptions(e){return X(e,this.host.captionOpen,this.host.captionClose)}captionLine(e){return this.host.captionsOn?e:this.stripCaptions(e)}promptFor(e){let t=this.promptBeatOf(e);if(!t)return;let r=this.interpolate(this.resolveString(t.id));return t.kind==="line"?{kind:"line",text:this.captionLine(r),character:t.character,characterName:this.resolveCharacterName(t.character),direction:t.direction}:{kind:"text",text:r}}promptBeatOf(e){return e.type==="group"&&e.prompt?e.prompt:((e.type==="snippet"?e:this.firstTextSnippetIn(e.children))?.beats??[]).find(r=>r.kind==="line"||r.kind==="text")}firstTextSnippetIn(e){let t;return k(e,r=>{!t&&r.type==="snippet"&&(r.beats??[]).some(n=>n.kind==="line"||n.kind==="text")&&(t=r)}),t}resolveString(e){if(this.host.emitIds)return e;let t=this.host.strings[e];if(t!==void 0)return t;let r=this.host.defaultStrings[e];return r!==void 0?`<Untranslated: ${e}> ${r}`:e}resolveCharacterName(e){if(e===void 0||this.host.emitIds)return;let t=V(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}splitRef(e){let t=this.host.refSplitCache.get(e);return t||(t=F(e,r=>r==="scene"||this.host.shared.has(r)),this.host.refSplitCache.set(e,t)),t}freshLocal(){return new w().defineOwned("patter",this.host.patterLocalDecls)}seedScene(e){let t=this.host.sceneSharedNames.get(e.id)??new Set;if(!this.sceneBags.has(e.id)){let r={};for(let n of e.sceneProps??[]){let i=n.name.toLowerCase();t.has(i)||(r[i]=M(n))}this.sceneBags.set(e.id,r)}if(!this.host.stageBags.has(e.id)){let r={};for(let n of e.sceneProps??[]){let i=n.name.toLowerCase();t.has(i)&&(r[i]=M(n))}this.host.stageBags.set(e.id,r)}for(let r of e.sceneProps??[]){if(!r.temporary)continue;let n=r.name.toLowerCase(),i=t.has(n)?this.host.stageBags.get(e.id):this.sceneBags.get(e.id);i&&(i[n]=M(r))}}};function ne(s){let e={};for(let[t,r]of s){let n={};r.seq!==void 0&&(n.seq=r.seq),r.bag&&(n.bag=[...r.bag]),r.last!==void 0&&(n.last=r.last),e[t]=n}return e}function se(s){let e=new Map;for(let[t,r]of Object.entries(s??{})){let n={};r.seq!==void 0&&(n.seq=r.seq),r.bag&&(n.bag=[...r.bag]),r.last!==void 0&&(n.last=r.last),e.set(t,n)}return e}function ee(s){return{name:s.name,type:s.type,values:s.values,default:s.default}}function ke(s){if(s.default!==void 0)return s.default;switch(s.type){case"number":return 0;case"string":return"";case"flags":return[];case"enum":return s.values?.[0]??"";default:return!1}}function te(s){return{name:s.name,type:s.type,values:s.values,default:s.default,writable:s.writable}}function Ee(s){if(s.default!==void 0)return s.default;switch(s.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"flags":return[];case"enum":return s.values?.[0]??""}}function Ce(s){let e=new Map;for(let t of s)e.set(t.name,Ee(t));return{get:t=>e.get(t),set:(t,r)=>{e.set(t,r)}}}function M(s){if(s.default!==void 0)return s.default;switch(s.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"flags":return[];case"enum":return s.values?.[0]??""}}function re(s){return typeof s=="boolean"?s:typeof s=="number"?s!==0:typeof s=="string"?s!=="":s.length>0}function ie(s,e){return s.gameDataFields?.[e]??[]}function j(s,e,t){return e&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:s.find(r=>r.name===t)?.default}function oe(s,e){let t={};for(let r of s){let n=j(s,e,r.name);n!==void 0&&(t[r.name]=n)}for(let[r,n]of Object.entries(e??{}))r in t||(t[r]=n);return t}return fe(De);})();\n//# sourceMappingURL=patterplay.min.js.map';
|
|
194031
|
+
var PLAYABLE_RUNTIME_JS = '"use strict";var Patterplay=(()=>{var P=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var de=Object.prototype.hasOwnProperty;var ue=(s,e)=>{for(var t in e)P(s,t,{get:e[t],enumerable:!0})},ge=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of pe(e))!de.call(s,n)&&n!==t&&P(s,n,{get:()=>e[n],enumerable:!(r=le(e,n))||r.enumerable});return s};var fe=s=>ge(P({},"__esModule",{value:!0}),s);var Ie={};ue(Ie,{Engine:()=>B,Flow:()=>v,buildTagIndex:()=>O,effectiveGameData:()=>oe,gameDataFields:()=>ie,gameDataValue:()=>j});function S(s){switch(s[0]){case"b":return{kind:"bool",value:s[1]};case"n":return{kind:"number",value:s[1]};case"s":return{kind:"string",value:s[1]};case"sv":return{kind:"scopedvar",scope:s[1],name:s[2]};case"u":return{kind:"unary",op:s[1],operand:S(s[2])};case"bin":return{kind:"binary",op:s[1],left:S(s[2]),right:S(s[3])};case"call":{let e=s.slice(2).map(S);return{kind:"call",name:s[1],args:e}}case"fd":return{kind:"flagdelta",sign:s[1],name:s[2]}}}var p=class extends Error{constructor(e){super(e),this.name="EvalError"}};function E(s,e,t){let r=new Map(t.scopes.map(i=>[i.token,i.missing??"false"])),n=i=>{switch(i.kind){case"bool":return i.value;case"number":return i.value;case"string":return i.value;case"scopedvar":{let o=e.scopes[i.scope];if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):o[i.name];if(a===void 0){if(r.get(i.scope)==="throw")throw new p(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{let o=t.functions[i.name];if(!o)throw new p(`unknown function \'${i.name}\'`);return o.eval(i.args,{evaluate:n,ctx:e})}case"flagdelta":throw new p("flagdelta node is only valid as an argument to a flag-delta function");case"unary":{if(i.op==="not"){let a=n(i.operand);if(typeof a!="boolean")throw new p(`\'not\' requires a boolean operand, got ${typeof a}`);return!a}let o=n(i.operand);if(typeof o!="number")throw new p(`unary \'-\' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let l=n(i.left);if(typeof l!="boolean")throw new p(`\'and\' requires boolean operands, left is ${typeof l}`);if(!l)return!1;let c=n(i.right);if(typeof c!="boolean")throw new p(`\'and\' requires boolean operands, right is ${typeof c}`);return c}if(i.op==="or"){let l=n(i.left);if(typeof l!="boolean")throw new p(`\'or\' requires boolean operands, left is ${typeof l}`);if(l)return!0;let c=n(i.right);if(typeof c!="boolean")throw new p(`\'or\' requires boolean operands, right is ${typeof c}`);return c}let o=n(i.left),a=n(i.right);switch(i.op){case"==":return U(o,a);case"!=":return!U(o,a);case">":return y(o,a,">"),o>a;case">=":return y(o,a,">="),o>=a;case"<":return y(o,a,"<"),o<a;case"<=":return y(o,a,"<="),o<=a;case"+":if(typeof o=="number"&&typeof a=="number"||typeof o=="string"&&typeof a=="string")return o+a;throw new p(`\'+\' requires two numbers or two strings, got ${typeof o} and ${typeof a}`);case"-":return y(o,a,"-"),o-a;case"*":return y(o,a,"*"),o*a;case"/":if(y(o,a,"/"),a===0)throw new p("division by zero");return o/a}}}};return n(s)}function U(s,e){if(Array.isArray(s)||Array.isArray(e)){if(!Array.isArray(s)||!Array.isArray(e)||s.length!==e.length)return!1;for(let t=0;t<s.length;t++)if(s[t]!==e[t])return!1;return!0}return s===e}function y(s,e,t){if(typeof s!="number"||typeof e!="number")throw new p(`\'${t}\' requires numeric operands, got ${typeof s} and ${typeof e}`)}var he={name:"check_flags",count:s=>Math.max(1,s.args.length-1)},me=[he];function W(s,e,t){let r=t?.countingCalls??me;return C(s,t?.want??!0,e,r)}function C(s,e,t,r){if(s.kind==="binary"&&(s.op==="and"||s.op==="or")){let n=C(s.left,e,t,r),i=C(s.right,e,t,r);return s.op==="and"===e?n>0&&i>0?n+i:0:Math.max(n,i)}if(s.kind==="unary"&&s.op==="not")return C(s.operand,!e,t,r);if(s.kind==="call"){let n=r.find(i=>i.name===s.name);if(n){let i=n.count(s),o=t(s);return e?o?i:0:o?0:1}}return t(s)===e?1:0}var w=class{scopes=new Map;defineOwned(e,t){this.assertFree(e);let r={},n=new Map;for(let i of t){let o=i.name.toLowerCase();n.set(o,i),r[o]=i.default??K(i)}return this.scopes.set(e,{kind:"owned",bag:r,decls:n}),this}reseedOwned(e,t){let r=this.scopes.get(e);if(!r||r.kind!=="owned")throw new Error(`\'@${e}\' is not an owned scope`);for(let n of Object.keys(r.bag))delete r.bag[n];r.decls.clear();for(let n of t){let i=n.name.toLowerCase();r.decls.set(i,n),r.bag[i]=n.default??K(n)}return this}defineForeign(e,t,r=[],n=!0){this.assertFree(e);let i=new Map;for(let o of r)i.set(o.name.toLowerCase(),o);return this.scopes.set(e,{kind:"foreign",resolver:t,decls:i,scopeWritable:n}),this}has(e){return this.scopes.has(e)}get(e,t){let r=this.scopes.get(e);if(!r)return;let n=t.toLowerCase();return r.kind==="owned"?r.bag[n]:r.resolver.get(n)}set(e,t,r){let n=this.scopes.get(e);if(!n)throw new Error(`unknown scope \'@${e}\'`);let i=t.toLowerCase();if(!this.writable(n,i))throw new Error(`\'@${e}.${t}\' is read-only`);n.kind==="owned"?n.bag[i]=r:n.resolver.set(i,r)}writable(e,t){return e.kind==="owned"?e.decls.get(t)?.writable??!0:e.resolver.set?e.decls.get(t)?.writable??e.scopeWritable:!1}toEvalContext(e){let t={};for(let[r,n]of this.scopes)t[r]=n.kind==="owned"?n.bag:n.resolver;return{scopes:t,host:e}}toSchema(){let e=new Map;for(let[t,r]of this.scopes){if(r.decls.size===0)continue;let n=new Map;for(let[i,o]of r.decls)n.set(i,{type:o.type,enumValues:o.values});e.set(t,n)}return{properties:e}}save(){let e={};for(let[t,r]of this.scopes)r.kind==="owned"&&(e[t]={...r.bag});return e}load(e){for(let[t,r]of Object.entries(e)){let n=this.scopes.get(t);n?.kind==="owned"&&Object.assign(n.bag,r)}}assertFree(e){if(this.scopes.has(e))throw new Error(`scope \'@${e}\' is already registered`)}};function K(s){if(s.default!==void 0)return s.default;switch(s.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"enum":return s.values?.[0]??"";case"flags":return[]}}function x(s){return s.ctx.host??{}}var T={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(s,e){if(s.length!==2)throw new p("random(a, b) requires exactly 2 arguments");let t=x(e).nextRandom;if(!t)throw new p("random() called without a PRNG in context");let r=e.evaluate(s[0]),n=e.evaluate(s[1]);if(typeof r!="number"||typeof n!="number")throw new p("random(a, b) arguments must be numbers");if(!Number.isInteger(r)||!Number.isInteger(n))throw new p("random(a, b) arguments must be integers");let i=Math.min(r,n),o=Math.max(r,n);return Math.floor(t()*(o-i+1))+i}},check_flags:{minArgs:1,returnType:"boolean",flagDeltaArgs:!0,validate:z("check_flags"),eval(s,e){let t=J(s[0],e,"check_flags");for(let r=1;r<s.length;r++){let n=s[r];if(n.kind!=="flagdelta")throw new p("check_flags() flag args must be +flagName or -flagName");if(n.sign==="+"?!t.includes(n.name):t.includes(n.name))return!1}return!0}},set_flags:{minArgs:1,returnType:"flags",flagDeltaArgs:!0,validate:z("set_flags"),eval(s,e){let t=[...J(s[0],e,"set_flags")];for(let r=1;r<s.length;r++){let n=s[r];if(n.kind!=="flagdelta")throw new p("set_flags() flag args must be +flagName or -flagName");if(n.sign==="+")t.includes(n.name)||t.push(n.name);else{let i=t.indexOf(n.name);i>=0&&t.splice(i,1)}}return t}},visits:{minArgs:1,maxArgs:1,returnType:"number",validate:D("visits"),eval:(s,e)=>x(e).visits?.(I(s,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:D("seen"),eval:(s,e)=>(x(e).visits?.(I(s,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:D("patter_visits"),eval:(s,e)=>x(e).patterVisits?.(I(s,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:D("patter_seen"),eval:(s,e)=>(x(e).patterVisits?.(I(s,e,"patter_seen"))??0)>0}}};function F(s,e){let t=s.replace(/^@/,"").split(".");return t.length===2&&e(t[0])?{scope:t[0],name:t[1].toLowerCase()}:{scope:"patter",name:t.join(".").toLowerCase()}}function I(s,e,t){let r=e.evaluate(s[0]);if(typeof r!="string")throw new p(`${t}(id) requires a string node id`);return r}function D(s){return(e,t)=>{let r=e[0];r&&r.kind!=="string"&&t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${s}(id): the argument must be a string id literal (a scene / block / node id)`})}}function J(s,e,t){if(!s)throw new p(`${t}() requires at least one argument (the flags variable)`);let r=e.evaluate(s);if(Array.isArray(r))return r;if(r===!1||r===null||r===void 0)return[];throw new p(`${t}() first argument must be a flags property`)}function z(s){return(e,t)=>{if(e.length===0)return;let r=e[0];if(r.kind!=="scopedvar"){t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${s}(): first argument must be a flags property reference (@name or @scope.name)`});return}let n=t.schema.properties.get(r.scope)?.get(r.name);if(n&&n.type!=="flags"){let i=r.scope===t.defaultScope?r.name:`${r.scope}.${r.name}`;t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${s}(): \'@${i}\' is not a flags property (got ${n.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:`${s}(): argument ${i+1} must be +flagName or -flagName`}):n?.type==="flags"&&n.enumValues&&!n.enumValues.includes(o.name)&&t.report({path:[...t.path,"args",i],kind:"unknown-flag-name",severity:"error",message:`${s}(): unknown flag \'${o.name}\'`,reference:o.name})}}}var Se=/^@[A-Za-z0-9_.]+$/;function*ye(s){let e="",t=0;for(;t<s.length;){let r=s[t];if(r==="{"&&s[t+1]==="{"){e+="{",t+=2;continue}if(r==="}"&&s[t+1]==="}"){e+="}",t+=2;continue}if(r==="{"){let n=s.indexOf("}",t+1);if(n!==-1){let i=s.slice(t,n+1),o=s.slice(t+1,n).trim();if(o.startsWith("@")){e&&(yield{kind:"text",value:e},e=""),yield{kind:"slot",raw:i,inner:o,ref:Se.test(o)?o:void 0},t=n+1;continue}e+=i,t=n+1;continue}}e+=r,t+=1}e&&(yield{kind:"text",value:e})}function be(s){return Array.isArray(s)?s.join(", "):typeof s=="boolean"?s?"true":"false":String(s)}function ve(s){return s===" "||s===" "||s===`\n`||s==="\\r"||s==="\\f"||s==="\\v"}function we(s){let e="",t=!1;for(let r of s){if(ve(r)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=r}return e}function X(s,e,t){if(e.length===0||s.indexOf(e)<0)return s;let r="",n=0,i=!1;for(;n<s.length;){if(s.startsWith(e,n)){let o=s.indexOf(t,n+e.length);if(o>=0){n=o+t.length,i=!0;continue}r+=s.slice(n);break}r+=s[n],n+=1}return i?we(r):s}function Z(s,e){if(s.indexOf("{")<0)return s;let t="";for(let r of ye(s)){if(r.kind==="text"){t+=r.value;continue}if(!r.ref){t+=r.raw;continue}let n=e(r.ref);t+=n===void 0?"":be(n)}return t}function k(s,e){for(let t of s){e(t);let r=t.children;r&&k(r,e)}}function xe(s){return s.toLowerCase().replace(/[\'\u2019]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function h(s){let e=s.gameId?.trim();return e||xe(s.name)}function G(s){return`cast:${s}`}var V={open:"[",close:"]"},Q="SFX";function R(s){let e=new Set,t=[];for(let r of s)e.has(r)||(e.add(r),t.push(r));return t}function O(s){let e=new Map,t=(r,n)=>{let i=R([...n,...r.tags??[]]);if(e.set(r.id,i),r.type==="group")for(let o of r.children)t(o,i);else for(let o of r.beats??[])e.set(o.id,R([...i,...o.tags??[]]))};for(let r of Object.values(s.scenes)){let n=R(r.tags??[]);e.set(r.id,n);for(let i of r.blocks){let o=R([...n,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var Y=new WeakMap,B=class s{host;defaultSeed;flowsById=new Map;allStrings;currentLocale;sourceDebug;sceneGameIdToId=new Map;blockGameIdToId=new Map;creationOptions;constructor(e,t={}){this.creationOptions=t;let r=t.locale??e.locales.default,n=e.strings;this.allStrings=n,this.currentLocale=r;let i=n[r]??{},o=n[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 d of e.cast??[])d.displayName&&c.set(d.name,d.displayName);this.defaultSeed=(t.seed??2654435769)>>>0;let u=new Map,g=new Map,L=new Map;for(let[d,m]of Object.entries(e.scenes)){this.sceneGameIdToId.set(h(m),d);let b=new Map;for(let f of m.blocks)g.set(f.id,{sceneId:d}),L.set(f.id,f),b.set(h(f),f.id),k(f.children,q=>u.set(q.id,q));this.blockGameIdToId.set(d,b)}let $=e.properties??[],N=$.filter(d=>d.shared??!0).map(ee),ae=$.filter(d=>!(d.shared??!0)).map(ee),ce=new Set(N.map(d=>d.name.toLowerCase())),A=new w().defineOwned("patter",N),_=new Set;if(t.world){let d=e.scopeRegistry?.scopes.find(b=>b.token==="world"),m=(d?.declarations??[]).map(te);A.defineForeign("world",t.world,m,d?.writable??!0),_.add("world")}for(let d of e.scopeRegistry?.scopes??[]){if(_.has(d.token))continue;let m=(d.declarations??[]).map(te);A.defineForeign(d.token,Ce(d.declarations??[]),m,d.writable??!0)}let H=new Map;for(let[d,m]of Object.entries(e.scenes)){let b=new Set((m.sceneProps??[]).filter(f=>f.shared??!1).map(f=>f.name.toLowerCase()));H.set(d,b)}this.host={bundle:e,emitIds:l,strings:i,defaultStrings:o,castDisplay:c,nodeIndex:u,blockIndex:g,blockById:L,sceneGameIdToId:this.sceneGameIdToId,blockGameIdToId:this.blockGameIdToId,tagIndex:O(e),shared:A,patterSharedDecls:N,patterLocalDecls:ae,patterSharedNames:ce,sceneSharedNames:H,sharedVisits:new Map,sharedSelectors:new Map,stageBags:new Map,customRng:t.rng,onDryChoice:t.onDryChoice,replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??V).open,captionClose:(e.closedCaptions??V).close,captionCharacter:e.closedCaptions?.character||Q,refSplitCache:new Map}}get locale(){return this.currentLocale}get isSourceDebug(){return this.sourceDebug}setLocale(e){this.currentLocale=e,this.host.strings=this.allStrings[e]??{}}replaceStrings(e){this.allStrings=e.strings,this.host.strings=this.allStrings[this.currentLocale]??{},this.host.defaultStrings=this.allStrings[this.host.bundle.locales.default]??{}}hotSwap(e){let t=this.saveGame(),r=i=>(i.setLocale(this.currentLocale),i.setClosedCaptions(this.host.captionsOn),i),n=new s(e,this.creationOptions);try{return n.loadGame(t),r(n)}catch{let i=new s(e,this.creationOptions);for(let[o,a]of Object.entries(t.flows)){let l=a.cursor.currentSceneId;try{i.openFlow(o,l!==null?{scene:l}:{})}catch{}}return r(i)}}get closedCaptions(){return this.host.captionsOn}setClosedCaptions(e){this.host.captionsOn=e}openFlow(e,t={}){let r=this.resolveSceneRef(t.scene),n=this.resolveBlockRef(r,t.block);this.flowsById.get(e)?.close();let i=new v(e,this.host,t.seed??this.defaultSeed);return this.flowsById.set(e,i),i.start(r,n),i}runFlow(e,t,r){let n=this.flowsById.get(e);if(!n)return this.openFlow(e,{scene:t,block:r}).advanceToStop().played;if(!n.goto(t,r))throw new Error(`runFlow: address not found: ${t}${r===void 0?"":` / ${r}`}`);return n.advanceToStop().played}resolveSceneRef(e){if(e!=null)return this.host.bundle.scenes[e]?e:this.sceneGameIdToId.get(e)??e}resolveBlockRef(e,t){if(t!=null){if(this.host.blockById.has(t))return t;if(e!=null){let r=this.blockGameIdToId.get(e)?.get(t);if(r)return r}return t}}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?h(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?h(t):void 0}tagsForBeat(e){return this.host.tagIndex.get(e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?this.host.tagIndex.get(t):void 0)??[]}tagsForBlock(e,t){let r=this.resolveSceneRef(e),n=this.resolveBlockRef(r,t);return(n!=null?this.host.tagIndex.get(n):void 0)??[]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...h(e)?{gameId:h(e)}:{},name:e.name,...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...h(t)?{gameId:h(t)}:{},name:t.name,...this.tagsField(t.id),children:t.children.map(r=>this.outlineNode(r))}))}))}getBeatSequence(){let e=[];for(let t of Object.values(this.host.bundle.scenes))for(let r of t.blocks)k(r.children,n=>{if(n.type==="snippet")for(let i of n.beats??[])e.push({sceneId:t.id,blockId:r.id,snippetId:n.id,beat:this.beatInfo(i)})});return e}outlineNode(e){return e.type==="group"?{type:"group",id:e.id,...this.tagsField(e.id),...e.selector?{selector:e.selector}:{},...e.prompt?{prompt:this.beatInfo(e.prompt)}:{},children:e.children.map(t=>this.outlineNode(t))}:{type:"snippet",id:e.id,...this.tagsField(e.id),beats:(e.beats??[]).map(t=>this.beatInfo(t)),...e.jump?{jumpTo:e.jump.to,...e.jump.mode?{jumpMode:e.jump.mode}:{}}:{}}}beatInfo(e){let t=this.host.tagIndex.get(e.id),r={id:e.id,kind:e.kind};if(e.kind==="line"){if(e.character!==void 0){r.character=e.character;let n=this.host.defaultStrings[G(e.character)]??this.host.castDisplay.get(e.character);n!==void 0&&(r.characterName=n)}e.direction!==void 0&&(r.direction=e.direction)}if(e.kind==="line"||e.kind==="text"){let n=this.host.defaultStrings[e.id];n!==void 0&&(r.text=n)}return e.gameData&&Object.keys(e.gameData).length&&(r.gameData=e.gameData),t&&t.length&&(r.tags=t),r}tagsField(e){let t=this.host.tagIndex.get(e);return t&&t.length?{tags:t}:{}}getFlow(e){return this.flowsById.get(e)}flows(){return[...this.flowsById.values()]}closeFlow(e){this.flowsById.get(e)?.close(),this.flowsById.delete(e)}reset(){for(let e of this.flowsById.values())e.close();this.flowsById.clear(),this.host.shared.reseedOwned("patter",this.host.patterSharedDecls),this.host.sharedVisits.clear(),this.host.sharedSelectors.clear(),this.host.stageBags.clear()}getProperty(e){let{scope:t,name:r}=this.splitShared(e);return this.host.shared.get(t,r)}setProperty(e,t){let{scope:r,name:n}=this.splitShared(e);this.host.shared.set(r,n,t)}listProperties(){return this.host.patterSharedDecls.map(e=>({ref:`@${e.name}`,type:e.type,values:e.values,value:this.getProperty(`@${e.name}`),default:ke(e)}))}splitShared(e){let t=this.host.refSplitCache.get(e);if(t||(t=F(e,r=>r==="scene"||this.host.shared.has(r)),this.host.refSplitCache.set(e,t)),t.scope==="scene")throw new Error(`\'${e}\': @scene properties are scene-scoped - read/write them on a Flow, not the Engine`);return t}save(){return this.host.shared.save()}load(e){this.host.shared.load(e)}saveGame(){let e={};for(let[t,r]of this.flowsById)e[t]=r.snapshot();return{version:2,shared:this.host.shared.save(),sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:ne(this.host.sharedSelectors),stageBags:Object.fromEntries([...this.host.stageBags].map(([t,r])=>[t,{...r}])),flows:e}}loadGame(e){if(e.version!==2)throw new Error(`unsupported save version: ${e.version}`);this.host.shared.load(e.shared),this.host.sharedVisits.clear();for(let[t,r]of Object.entries(e.sharedVisits??{}))this.host.sharedVisits.set(t,r);this.host.sharedSelectors.clear();for(let[t,r]of se(e.sharedSelectors))this.host.sharedSelectors.set(t,r);this.host.stageBags.clear();for(let[t,r]of Object.entries(e.stageBags??{}))this.host.stageBags.set(t,{...r});this.flowsById.clear();for(let[t,r]of Object.entries(e.flows)){let n=new v(t,this.host,this.defaultSeed);n.restore(r),this.flowsById.set(t,n)}}},v=class{id;host;local;rngState;started=!1;flowEnded=!1;closed=!1;currentSceneId=null;stack=[];activeSnippet=null;beatIndex=0;pendingChoice=null;pendingPromptBeat=null;pendingPromptOwnerId=null;selectors=new Map;visitCounts=new Map;sceneBags=new Map;patterResolver={get:e=>this.host.patterSharedNames.has(e)?this.host.shared.get("patter",e):this.local.get("patter",e),set:(e,t)=>{this.host.patterSharedNames.has(e)?this.host.shared.set("patter",e,t):this.local.set("patter",e,t)}};sceneResolver={get:e=>{let t=this.currentSceneId;return t===null?void 0:(this.host.sceneSharedNames.get(t)?.has(e)?this.host.stageBags.get(t):this.sceneBags.get(t))?.[e]},set:(e,t)=>{let r=this.currentSceneId;if(r===null)return;let n=this.host.sceneSharedNames.get(r)?.has(e)?this.host.stageBags.get(r):this.sceneBags.get(r);n&&(n[e]=t)}};evalCtx;constructor(e,t,r){this.id=e,this.host=t,this.rngState=r>>>0,this.local=this.freshLocal();let n={...t.shared.toEvalContext().scopes};n.patter=this.patterResolver,n.scene=this.sceneResolver,this.evalCtx={scopes:n,host:{nextRandom:this.rng,visits:i=>this.visitCounts.get(i)??0,patterVisits:i=>this.host.sharedVisits.get(i)??0}}}start(e,t){if(this.sceneBags.clear(),this.local=this.freshLocal(),this.selectors.clear(),this.visitCounts.clear(),this.stack=[],this.currentSceneId=null,this.flowEnded=!1,this.activeSnippet=null,this.beatIndex=0,this.pendingChoice=null,this.started=!0,t){let r=this.host.blockIndex.get(t);if(!r)throw new Error(`unknown block: ${t}`);this.enterSceneSetup(r.sceneId),this.stack=[{sceneId:r.sceneId,containerId:t,index:0}],this.enter(t)}else{let r=e??Object.keys(this.host.bundle.scenes)[0],n=r?this.host.bundle.scenes[r]:void 0;if(!n)throw new Error(r?`unknown scene: ${r}`:"no scenes in bundle");this.enterSceneSetup(r);let i=n.blocks[0];i&&(this.stack=[{sceneId:r,containerId:i.id,index:0}],this.enter(i.id))}this.settle()}reset(e,t){this.start(e,t)}goto(e,t){if(this.closed)return!1;if(e==="END")return this.started=!0,this.pendingChoice=null,this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!0,this.stack=[],!0;let r=this.host.sceneGameIdToId.get(e)??(this.host.bundle.scenes[e]?e:void 0);if(r===void 0)return!1;let n;return t!==void 0&&(n=this.host.blockGameIdToId.get(r)?.get(t)??(this.host.blockIndex.get(t)?.sceneId===r?t:void 0),n===void 0)?!1:this.started?(this.pendingChoice=null,this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!1,this.enterTarget(n??r,"jump"),this.settle(),!0):(this.start(r,n),!0)}close(){this.closed=!0,this.flowEnded=!0,this.stack=[],this.activeSnippet=null,this.beatIndex=0,this.pendingChoice=null,this.pendingPromptBeat=null,this.pendingPromptOwnerId=null}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.pendingPromptBeat){let e=this.pendingPromptBeat;return this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.beatResult(e)}return this.settle(),this.flowEnded?{type:"end"}:this.pendingChoice?{type:"choice",groupId:this.pendingChoice.groupId,options:this.pendingChoice.options}:this.activeSnippet?this.beatResult(this.activeSnippet.beats[this.beatIndex++]):(this.flowEnded=!0,{type:"end"})}advanceToStop(){let e=[];for(;;){let t=this.advance();if(t.type==="choice"||t.type==="end")return{played:e,stop:t};e.push(t)}}settle(){let e=0;for(;;){if(++e>1e4)throw new Error("flow did not settle after 10000 transitions - likely a jump cycle with no deliverable content");if(this.flowEnded||this.pendingChoice)return;if(this.activeSnippet){if(this.beatIndex<(this.activeSnippet.beats?.length??0))return;this.runEffects(this.activeSnippet.onExit);let n=this.activeSnippet.jump;this.activeSnippet=null,this.beatIndex=0,this.resolveJump(n);continue}let t=this.stack[this.stack.length-1];if(!t){this.flowEnded=!0;return}t.sceneId!==this.currentSceneId&&(this.currentSceneId=t.sceneId);let r=this.childrenOf(t.containerId);if(!r){this.stack.pop();continue}for(;t.index<r.length&&!this.eligible(r[t.index]);)t.index++;if(t.index>=r.length){this.stack.pop();continue}this.enterChild(r[t.index++])}}getChoices(){return this.pendingChoice?.options??[]}choose(e){let t=this.pendingChoice;if(!t)throw new Error("no choice is pending");let r=t.options.find(i=>i.id===e);if(!r)throw new Error(`unknown choice option: ${e}`);if(!r.eligible)throw new Error(`choice option is not eligible: ${e}`);let n=t.byId.get(e);this.pendingChoice=null,this.pendingPromptBeat=this.host.replayPromptOnChoose?this.promptBeatOf(n)??null:null,this.pendingPromptOwnerId=this.pendingPromptBeat?n.id:null,this.enterChild(n)}isEnded(){return this.flowEnded}getProperty(e){let{scope:t,name:r}=this.splitRef(e);return t==="patter"?this.patterResolver.get(r):t==="scene"?this.sceneResolver.get(r):this.host.shared.get(t,r)}setProperty(e,t){let{scope:r,name:n}=this.splitRef(e);if(r==="patter")this.patterResolver.set(n,t);else if(r==="scene"){if(this.currentSceneId===null)throw new Error(`\'${e}\': the flow has not entered a scene yet`);this.sceneResolver.set(n,t)}else this.host.shared.set(r,n,t)}snapshot(){return{scopes:this.local.save(),sceneBags:Object.fromEntries([...this.sceneBags].map(([e,t])=>[e,{...t}])),rngState:this.rngState,visits:Object.fromEntries(this.visitCounts),cursor:{flowEnded:this.flowEnded,currentSceneId:this.currentSceneId,stack:this.stack.map(e=>{let t=this.childrenOf(e.containerId)?.[e.index];return t?{...e,nextId:t.id}:{...e}}),activeSnippetId:this.activeSnippet?.id??null,beatIndex:this.beatIndex,pendingChoice:this.pendingChoice?{groupId:this.pendingChoice.groupId,options:this.pendingChoice.options.map(e=>({...e}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,selectors:ne(this.selectors)}}}restore(e){this.rngState=e.rngState>>>0,this.visitCounts=new Map(Object.entries(e.visits??{}));let t=e.cursor;if(this.started=!0,this.flowEnded=t.flowEnded,this.beatIndex=t.beatIndex,this.currentSceneId=t.currentSceneId,this.stack=t.stack.map(r=>{let{nextId:n,...i}=r;if(n!==void 0){let o=this.childrenOf(i.containerId)?.findIndex(a=>a.id===n)??-1;if(o>=0)return{...i,index:o}}return{...i}}),this.sceneBags=new Map(Object.entries(e.sceneBags??{}).map(([r,n])=>[r,{...n}])),this.local=this.freshLocal(),this.local.load(e.scopes),this.activeSnippet=null,t.activeSnippetId!==null){let r=this.host.nodeIndex.get(t.activeSnippetId);r&&r.type==="snippet"&&(this.activeSnippet=r)}if(this.selectors=se(t.selectors),this.pendingChoice=null,t.pendingChoice!==null){let r=new Map,n=[];for(let i of t.pendingChoice.options){let o=this.host.nodeIndex.get(i.id);o&&(r.set(i.id,o),n.push({...i}))}n.length>0&&(this.pendingChoice={groupId:t.pendingChoice.groupId,options:n,byId:r})}if(this.pendingPromptBeat=null,this.pendingPromptOwnerId=t.pendingPromptOwnerId??null,this.pendingPromptOwnerId){let r=this.host.nodeIndex.get(this.pendingPromptOwnerId);this.pendingPromptBeat=r?this.promptBeatOf(r)??null:null,this.pendingPromptBeat||(this.pendingPromptOwnerId=null)}}enterSceneSetup(e){let t=this.host.bundle.scenes[e];if(!t)throw new Error(`unknown scene: ${e}`);this.currentSceneId=e,this.enter(e),this.seedScene(t),this.runEffects(t.onEntry)}enterChild(e){if(this.enter(e.id),e.type==="snippet"){this.beginSnippet(e);return}let t=e.selector??"run";if(t==="run"){this.stack.push({sceneId:this.currentSceneId,containerId:e.id,index:0});return}if(t==="choice"){this.setupChoice(e);return}let r=this.selectChild(e);r&&this.enterChild(r)}childrenOf(e){let t=this.host.blockById.get(e);if(t)return t.children;let r=this.host.nodeIndex.get(e);if(r&&r.type==="group")return r.children}beginSnippet(e){this.runEffects(e.onEnter),this.activeSnippet=e,this.beatIndex=0}setupChoice(e){let t=[],r=new Map,n=[];for(let o of e.children){if(o.fallback===!0){n.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,prompt:this.promptFor(o),eligible:a,gameData:o.gameData}),r.set(o.id,o))}if(t.length>0){this.pendingChoice={groupId:e.id,options:t,byId:r};return}let i=n.find(o=>this.eligible(o));if(i){this.enterChild(i);return}this.host.onDryChoice?.(e.id)}resolveJump(e){e&&this.enterTarget(e.to,e.mode==="call"?"call":"jump")}enterTarget(e,t){if(e==="END"){this.flowEnded=!0,this.stack=[];return}let r,n,i=this.host.bundle.scenes[e];if(i){this.enterSceneSetup(e);let a=i.blocks[0];if(!a){t==="jump"&&(this.stack=[]);return}r=e,n=a.id}else{let a=this.host.blockIndex.get(e);if(!a)throw new Error(`jump target not found: ${e}`);a.sceneId!==this.currentSceneId&&this.enterSceneSetup(a.sceneId),r=a.sceneId,n=e}this.enter(n);let o={sceneId:r,containerId:n,index:0};t==="call"?this.stack.push(o):this.stack=[o]}selectChild(e){let t=e.children.filter(n=>this.eligible(n));if(t.length===0)return null;let r=this.selectorState(e);switch(e.selector){case"branch":return t[0];case"sequence":{let n=e.options?.order??"sequential",i=e.options?.exhaust??"once";return n==="shuffle"?this.pickShuffle(t,i,r):n==="specificity"?this.pickSpecificity(t,i,r):this.pickSequential(t,i,r)}default:return null}}pickSequential(e,t,r){let n=e.length,i=r.seq??0;return r.seq=i+1,t==="repeat"?e[i%n]:i<n?e[i]:t==="stick"?e[n-1]:null}pickShuffle(e,t,r){let n=e.length,i=t==="stick",o=()=>(i?e.slice(0,n-1):e).map(g=>g.id);if(r.bag===void 0&&(r.bag=o()),r.bag.length===0){if(t==="once")return null;if(i){let g=e[n-1];return r.last=g.id,g}r.bag=o()}let a=r.bag,l=r.last!==void 0&&a.length>1?a.indexOf(r.last):-1,c=Math.floor(this.rng()*(l>=0?a.length-1:a.length));l>=0&&c>=l&&c++;let u=a[c];return a.splice(c,1),r.last=u,e.find(g=>g.id===u)}pickSpecificity(e,t,r){let n=e;if(t!=="repeat"){r.bag===void 0&&(r.bag=e.map(u=>u.id));let c=new Set(r.bag);if(n=e.filter(u=>c.has(u.id)),n.length===0)return t==="stick"&&r.last!==void 0?e.find(u=>u.id===r.last)??null:null}let i=-1,a=n.map(c=>{let u=this.specScore(c);return u>i&&(i=u),{c,s:u}}).filter(c=>c.s===i).map(c=>c.c),l;if(a.length===1)l=a[0];else{let c=r.last!==void 0?a.findIndex(g=>g.id===r.last):-1,u=Math.floor(this.rng()*(c>=0?a.length-1:a.length));c>=0&&u>=c&&u++,l=a[u]}return t!=="repeat"&&(r.bag=r.bag.filter(c=>c!==l.id)),r.last=l.id,l}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0):0}matchedSpec(e,t){return W(e,n=>re(E(n,this.evalCtx,T)),{want:t})}selectorState(e){let t=e.shared?this.host.sharedSelectors:this.selectors,r=t.get(e.id);return r||(r={},t.set(e.id,r)),r}runEffects(e){for(let t of e??[])this.setProperty(t.target,this.evalExpr(t.value))}eligible(e){return e.condition?re(this.evalExpr(e.condition)):!0}evalExpr(e){return E(this.conditionAst(e),this.evalCtx,T)}conditionAst(e){let t=Y.get(e);return t||(t=S(e.ast),Y.set(e,t)),t}enter(e){this.visitCounts.set(e,(this.visitCounts.get(e)??0)+1),this.host.sharedVisits.set(e,(this.host.sharedVisits.get(e)??0)+1)}rng=()=>{if(this.host.customRng)return this.host.customRng();let e=this.rngState+1831565813|0;this.rngState=e;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};beatResult(e){let t=this.host.tagIndex.get(e.id),r=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:e.gameData,...r};case"text":return{type:"text",id:e.id,text:this.interpolate(this.resolveString(e.id)),gameData:e.gameData,...r};case"line":{let n=this.resolveString(e.id),i=!this.host.captionsOn,a=i&&e.character===this.host.captionCharacter?"":this.captionLine(this.host.bundle.voiced?n:this.interpolate(n)),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,gameData:e.gameData,...r}}}}interpolate(e){return Z(e,t=>this.getProperty(t))}stripCaptions(e){return X(e,this.host.captionOpen,this.host.captionClose)}captionLine(e){return this.host.captionsOn?e:this.stripCaptions(e)}promptFor(e){let t=this.promptBeatOf(e);if(!t)return;let r=this.interpolate(this.resolveString(t.id));return t.kind==="line"?{kind:"line",text:this.captionLine(r),character:t.character,characterName:this.resolveCharacterName(t.character),direction:t.direction}:{kind:"text",text:r}}promptBeatOf(e){return e.type==="group"&&e.prompt?e.prompt:((e.type==="snippet"?e:this.firstTextSnippetIn(e.children))?.beats??[]).find(r=>r.kind==="line"||r.kind==="text")}firstTextSnippetIn(e){let t;return k(e,r=>{!t&&r.type==="snippet"&&(r.beats??[]).some(n=>n.kind==="line"||n.kind==="text")&&(t=r)}),t}resolveString(e){if(this.host.emitIds)return e;let t=this.host.strings[e];if(t!==void 0)return t;let r=this.host.defaultStrings[e];return r!==void 0?`<Untranslated: ${e}> ${r}`:e}resolveCharacterName(e){if(e===void 0||this.host.emitIds)return;let t=G(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}splitRef(e){let t=this.host.refSplitCache.get(e);return t||(t=F(e,r=>r==="scene"||this.host.shared.has(r)),this.host.refSplitCache.set(e,t)),t}freshLocal(){return new w().defineOwned("patter",this.host.patterLocalDecls)}seedScene(e){let t=this.host.sceneSharedNames.get(e.id)??new Set;if(!this.sceneBags.has(e.id)){let r={};for(let n of e.sceneProps??[]){let i=n.name.toLowerCase();t.has(i)||(r[i]=M(n))}this.sceneBags.set(e.id,r)}if(!this.host.stageBags.has(e.id)){let r={};for(let n of e.sceneProps??[]){let i=n.name.toLowerCase();t.has(i)&&(r[i]=M(n))}this.host.stageBags.set(e.id,r)}for(let r of e.sceneProps??[]){if(!r.temporary)continue;let n=r.name.toLowerCase(),i=t.has(n)?this.host.stageBags.get(e.id):this.sceneBags.get(e.id);i&&(i[n]=M(r))}}};function ne(s){let e={};for(let[t,r]of s){let n={};r.seq!==void 0&&(n.seq=r.seq),r.bag&&(n.bag=[...r.bag]),r.last!==void 0&&(n.last=r.last),e[t]=n}return e}function se(s){let e=new Map;for(let[t,r]of Object.entries(s??{})){let n={};r.seq!==void 0&&(n.seq=r.seq),r.bag&&(n.bag=[...r.bag]),r.last!==void 0&&(n.last=r.last),e.set(t,n)}return e}function ee(s){return{name:s.name,type:s.type,values:s.values,default:s.default}}function ke(s){if(s.default!==void 0)return s.default;switch(s.type){case"number":return 0;case"string":return"";case"flags":return[];case"enum":return s.values?.[0]??"";default:return!1}}function te(s){return{name:s.name,type:s.type,values:s.values,default:s.default,writable:s.writable}}function Ee(s){if(s.default!==void 0)return s.default;switch(s.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"flags":return[];case"enum":return s.values?.[0]??""}}function Ce(s){let e=new Map;for(let t of s)e.set(t.name,Ee(t));return{get:t=>e.get(t),set:(t,r)=>{e.set(t,r)}}}function M(s){if(s.default!==void 0)return s.default;switch(s.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"flags":return[];case"enum":return s.values?.[0]??""}}function re(s){return typeof s=="boolean"?s:typeof s=="number"?s!==0:typeof s=="string"?s!=="":s.length>0}function ie(s,e){return s.gameDataFields?.[e]??[]}function j(s,e,t){return e&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:s.find(r=>r.name===t)?.default}function oe(s,e){let t={};for(let r of s){let n=j(s,e,r.name);n!==void 0&&(t[r.name]=n)}for(let[r,n]of Object.entries(e??{}))r in t||(t[r]=n);return t}return fe(Ie);})();\n//# sourceMappingURL=patterplay.min.js.map';
|
|
194032
194032
|
|
|
194033
194033
|
// ../ops/src/export-html.ts
|
|
194034
194034
|
var esc = (s) => s.replace(/[&<>]/g, (c2) => ({ "&": "&", "<": "<", ">": ">" })[c2]);
|
|
@@ -194517,6 +194517,9 @@ var Engine = class _Engine {
|
|
|
194517
194517
|
nodeIndex,
|
|
194518
194518
|
blockIndex,
|
|
194519
194519
|
blockById,
|
|
194520
|
+
sceneGameIdToId: this.sceneGameIdToId,
|
|
194521
|
+
blockGameIdToId: this.blockGameIdToId,
|
|
194522
|
+
// same instances the engine resolves with
|
|
194520
194523
|
tagIndex: buildTagIndex(bundle),
|
|
194521
194524
|
shared,
|
|
194522
194525
|
patterSharedDecls,
|
|
@@ -194625,16 +194628,56 @@ var Engine = class _Engine {
|
|
|
194625
194628
|
/**
|
|
194626
194629
|
* Open (and start) a named flow. Each flow has its own cursor, PRNG, and per-flow
|
|
194627
194630
|
* half of the scopes (not-shared `@patter`/`@scene`); all flows share the shared
|
|
194628
|
-
* half.
|
|
194631
|
+
* half.
|
|
194632
|
+
*
|
|
194633
|
+
* Re-opening an existing id REPLACES it with a fresh flow, and CLOSES the old one
|
|
194634
|
+
* ({@link Flow.close}) so a host still holding it cannot keep driving the shared world. Replacing is
|
|
194635
|
+
* therefore a reset: that name's cursor, visit counts, selector cursors (so any shuffle / once-each
|
|
194636
|
+
* position) and per-flow properties all start over.
|
|
194637
|
+
*
|
|
194638
|
+
* Contrast {@link runFlow}, which REUSES a flow of the same name instead of replacing it - that is the
|
|
194639
|
+
* call to reach for when you want a speaker's variation state to carry on.
|
|
194629
194640
|
*/
|
|
194630
194641
|
openFlow(id, opts = {}) {
|
|
194631
194642
|
const sceneId = this.resolveSceneRef(opts.scene);
|
|
194632
194643
|
const blockId = this.resolveBlockRef(sceneId, opts.block);
|
|
194644
|
+
this.flowsById.get(id)?.close();
|
|
194633
194645
|
const flow = new Flow(id, this.host, opts.seed ?? this.defaultSeed);
|
|
194634
194646
|
this.flowsById.set(id, flow);
|
|
194635
194647
|
flow.start(sceneId, blockId);
|
|
194636
194648
|
return flow;
|
|
194637
194649
|
}
|
|
194650
|
+
/**
|
|
194651
|
+
* "Play this address and give me everything it produced" - the one-call form of the bark / one-shot
|
|
194652
|
+
* pattern. The NAMED flow is reused if it already exists (moved with {@link Flow.goto}) and opened at
|
|
194653
|
+
* the address if not, then run to its next stop, returning every beat it played.
|
|
194654
|
+
*
|
|
194655
|
+
* Calling it again with the SAME NAME does NOT replace the flow - it reuses it, and that is the whole
|
|
194656
|
+
* point. A flow owns its selector cursors, visit counts and per-flow properties, so reusing one lets a
|
|
194657
|
+
* **shuffle keep its bag** and an **"once each" list keep its place**: successive calls give the next
|
|
194658
|
+
* variation instead of replaying the first forever. (A fresh flow each time would reset all of it,
|
|
194659
|
+
* unless every such group happened to be authored `shared`.) Use one name per independent speaker;
|
|
194660
|
+
* different names never share per-flow state.
|
|
194661
|
+
*
|
|
194662
|
+
* This is exactly where it differs from {@link openFlow}, which REPLACES a flow of the same name and
|
|
194663
|
+
* so resets that variation state. Never mix the two on one name unless you mean to start over.
|
|
194664
|
+
*
|
|
194665
|
+
* Returns the played beats in order - `[]` means the address had nothing left to give (an exhausted
|
|
194666
|
+
* variation list, say), which is the signal to fall back to other content. It THROWS on an address
|
|
194667
|
+
* that does not resolve: unlike `goto` (a navigation primitive, where probing is legitimate), naming a
|
|
194668
|
+
* location here asserts it exists, and keeping `[]` unambiguous is worth more than a soft failure.
|
|
194669
|
+
*
|
|
194670
|
+
* A run that stops at a CHOICE returns the beats up to it and leaves the choice pending on the flow -
|
|
194671
|
+
* fetch it with `engine.getFlow(name)?.getChoices()`.
|
|
194672
|
+
*/
|
|
194673
|
+
runFlow(flow, scene, block) {
|
|
194674
|
+
const existing = this.flowsById.get(flow);
|
|
194675
|
+
if (!existing) return this.openFlow(flow, { scene, block }).advanceToStop().played;
|
|
194676
|
+
if (!existing.goto(scene, block)) {
|
|
194677
|
+
throw new Error(`runFlow: address not found: ${scene}${block === void 0 ? "" : ` / ${block}`}`);
|
|
194678
|
+
}
|
|
194679
|
+
return existing.advanceToStop().played;
|
|
194680
|
+
}
|
|
194638
194681
|
/** Resolve a scene reference (a gameId address OR an internal id) to its internal id. */
|
|
194639
194682
|
resolveSceneRef(ref) {
|
|
194640
194683
|
if (ref == null) return void 0;
|
|
@@ -194772,8 +194815,10 @@ var Engine = class _Engine {
|
|
|
194772
194815
|
flows() {
|
|
194773
194816
|
return [...this.flowsById.values()];
|
|
194774
194817
|
}
|
|
194775
|
-
/** Close (remove) a flow.
|
|
194818
|
+
/** Close (remove) a flow. The flow object is FINISHED, not merely unregistered, so a host still
|
|
194819
|
+
* holding it cannot keep advancing it into the shared world (see {@link Flow.close}). */
|
|
194776
194820
|
closeFlow(id) {
|
|
194821
|
+
this.flowsById.get(id)?.close();
|
|
194777
194822
|
this.flowsById.delete(id);
|
|
194778
194823
|
}
|
|
194779
194824
|
/**
|
|
@@ -194783,6 +194828,7 @@ var Engine = class _Engine {
|
|
|
194783
194828
|
* After reset, open fresh flows with `openFlow`.
|
|
194784
194829
|
*/
|
|
194785
194830
|
reset() {
|
|
194831
|
+
for (const flow of this.flowsById.values()) flow.close();
|
|
194786
194832
|
this.flowsById.clear();
|
|
194787
194833
|
this.host.shared.reseedOwned("patter", this.host.patterSharedDecls);
|
|
194788
194834
|
this.host.sharedVisits.clear();
|
|
@@ -194874,6 +194920,9 @@ var Flow = class {
|
|
|
194874
194920
|
// `activeSnippet`/`beatIndex`.
|
|
194875
194921
|
started = false;
|
|
194876
194922
|
flowEnded = false;
|
|
194923
|
+
/** Closed by the engine (see `close()`). Terminal, and distinct from `flowEnded`: an ENDED flow is
|
|
194924
|
+
* merely out of content and `goto` revives it; a CLOSED one is finished for good. */
|
|
194925
|
+
closed = false;
|
|
194877
194926
|
currentSceneId = null;
|
|
194878
194927
|
stack = [];
|
|
194879
194928
|
activeSnippet = null;
|
|
@@ -194980,6 +195029,81 @@ var Flow = class {
|
|
|
194980
195029
|
reset(sceneId, blockId) {
|
|
194981
195030
|
this.start(sceneId, blockId);
|
|
194982
195031
|
}
|
|
195032
|
+
/**
|
|
195033
|
+
* Send this flow's cursor to an ADDRESS, exactly as an authored `go` jump would: the target scene's
|
|
195034
|
+
* `onEntry` effects run, entering counts as a visit, and the callstack is REPLACED - any pending
|
|
195035
|
+
* `call` returns are discarded, just as a goto inside a call does.
|
|
195036
|
+
*
|
|
195037
|
+
* `scene` and `block` are host-facing gameIds (spec §6) or internal ids; `block` is scene-scoped, so
|
|
195038
|
+
* it is looked up within `scene`. `"END"` ends the flow. To move within the current scene, pass the
|
|
195039
|
+
* current scene's address again (`flow.currentScene` -> `engine.sceneAddress`).
|
|
195040
|
+
*
|
|
195041
|
+
* This is HOST navigation, not authoring, and it takes effect IMMEDIATELY: any beats left in the
|
|
195042
|
+
* snippet being delivered are abandoned, and a pending choice is dropped. The format stops an AUTHOR
|
|
195043
|
+
* writing a divert into the middle of a snippet; a host teleport is out-of-band, like `reset()` or
|
|
195044
|
+
* `loadGame()`. A flow that never started starts here; one that already ended resumes here.
|
|
195045
|
+
*
|
|
195046
|
+
* Returns false - leaving the cursor exactly where it was - if the address does not resolve. Per-flow
|
|
195047
|
+
* state (properties, visit counts, selector cursors) is untouched either way: this MOVES, never resets.
|
|
195048
|
+
*/
|
|
195049
|
+
goto(scene, block) {
|
|
195050
|
+
if (this.closed) return false;
|
|
195051
|
+
if (scene === "END") {
|
|
195052
|
+
this.started = true;
|
|
195053
|
+
this.pendingChoice = null;
|
|
195054
|
+
this.pendingPromptBeat = null;
|
|
195055
|
+
this.pendingPromptOwnerId = null;
|
|
195056
|
+
this.activeSnippet = null;
|
|
195057
|
+
this.beatIndex = 0;
|
|
195058
|
+
this.flowEnded = true;
|
|
195059
|
+
this.stack = [];
|
|
195060
|
+
return true;
|
|
195061
|
+
}
|
|
195062
|
+
const sceneId = this.host.sceneGameIdToId.get(scene) ?? (this.host.bundle.scenes[scene] ? scene : void 0);
|
|
195063
|
+
if (sceneId === void 0) return false;
|
|
195064
|
+
let blockId;
|
|
195065
|
+
if (block !== void 0) {
|
|
195066
|
+
blockId = this.host.blockGameIdToId.get(sceneId)?.get(block) ?? (this.host.blockIndex.get(block)?.sceneId === sceneId ? block : void 0);
|
|
195067
|
+
if (blockId === void 0) return false;
|
|
195068
|
+
}
|
|
195069
|
+
if (!this.started) {
|
|
195070
|
+
this.start(sceneId, blockId);
|
|
195071
|
+
return true;
|
|
195072
|
+
}
|
|
195073
|
+
this.pendingChoice = null;
|
|
195074
|
+
this.pendingPromptBeat = null;
|
|
195075
|
+
this.pendingPromptOwnerId = null;
|
|
195076
|
+
this.activeSnippet = null;
|
|
195077
|
+
this.beatIndex = 0;
|
|
195078
|
+
this.flowEnded = false;
|
|
195079
|
+
this.enterTarget(blockId ?? sceneId, "jump");
|
|
195080
|
+
this.settle();
|
|
195081
|
+
return true;
|
|
195082
|
+
}
|
|
195083
|
+
/**
|
|
195084
|
+
* Finish this flow for good. Engine-managed: `engine.closeFlow(id)`, `engine.reset()`, and re-opening
|
|
195085
|
+
* a name with `engine.openFlow` all call it on the flow being dropped.
|
|
195086
|
+
*
|
|
195087
|
+
* A dropped flow used to stay fully live: unregistered and invisible to `engine.flows()`, but a host
|
|
195088
|
+
* still holding the object could keep advancing it, and every scene `onEntry`, shared property, world
|
|
195089
|
+
* visit count and shared selector cursor it touched still landed on the engine. Closing makes that
|
|
195090
|
+
* stale reference inert - `advance()` reports the end and `goto()` refuses - so a forgotten reference
|
|
195091
|
+
* cannot quietly mutate the world. Terminal: unlike ending, a close is never revived.
|
|
195092
|
+
*/
|
|
195093
|
+
close() {
|
|
195094
|
+
this.closed = true;
|
|
195095
|
+
this.flowEnded = true;
|
|
195096
|
+
this.stack = [];
|
|
195097
|
+
this.activeSnippet = null;
|
|
195098
|
+
this.beatIndex = 0;
|
|
195099
|
+
this.pendingChoice = null;
|
|
195100
|
+
this.pendingPromptBeat = null;
|
|
195101
|
+
this.pendingPromptOwnerId = null;
|
|
195102
|
+
}
|
|
195103
|
+
/** True once the engine has closed this flow (closed, dropped by `reset()`, or replaced by name). */
|
|
195104
|
+
get isClosed() {
|
|
195105
|
+
return this.closed;
|
|
195106
|
+
}
|
|
194983
195107
|
/** The scene the cursor is currently in - set on entry and whenever a jump crosses scenes. Read
|
|
194984
195108
|
* right after `advance()` to know which scene the just-played beat lives in (tooling that mirrors
|
|
194985
195109
|
* the playhead, e.g. an editor following a cross-scene jump). `null` before the flow has started. */
|
|
@@ -194988,6 +195112,7 @@ var Flow = class {
|
|
|
194988
195112
|
}
|
|
194989
195113
|
/** Run until the next line, game event, choice, or the end of the flow. */
|
|
194990
195114
|
advance() {
|
|
195115
|
+
if (this.closed) return { type: "end" };
|
|
194991
195116
|
if (!this.started) throw new Error("flow has not been started");
|
|
194992
195117
|
if (this.pendingPromptBeat) {
|
|
194993
195118
|
const b = this.pendingPromptBeat;
|
|
@@ -237033,7 +237158,10 @@ function runInit(opts) {
|
|
|
237033
237158
|
scene: sceneId,
|
|
237034
237159
|
locale: "en",
|
|
237035
237160
|
default: true,
|
|
237036
|
-
|
|
237161
|
+
// The starter line is STORY content the writer replaces, so it must read the same however the
|
|
237162
|
+
// project was made: no file paths, no commands. (Front-ends give their own next step - `patter init`
|
|
237163
|
+
// prints "try: patter play <dir>" on the terminal, and Patterpad just opens the scene for editing.)
|
|
237164
|
+
strings: { [beatId]: `Welcome to ${name}. This is the first line of your story - replace it with your own.` }
|
|
237037
237165
|
};
|
|
237038
237166
|
const bundle = opts.bundle ?? "commit";
|
|
237039
237167
|
const projectFile = join4(dir2, `${fileSlug}.patterproj`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patterkit/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "The `patter` CLI: validate, format, export, and play a Patter project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"build:standalone:others": "node scripts/build-standalone.mjs --targets=linux-x64,linux-arm64,windows-x64"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@patterkit/core": "0.1.
|
|
33
|
-
"@patterkit/ops": "0.2.
|
|
32
|
+
"@patterkit/core": "0.1.5",
|
|
33
|
+
"@patterkit/ops": "0.2.3",
|
|
34
34
|
"@wildwinter/simple-vc-lib": "^0.2.0"
|
|
35
35
|
}
|
|
36
36
|
}
|