@patterkit/cli 0.1.3 → 0.1.4
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 +94 -47
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -49002,10 +49002,10 @@ var require_traverse = __commonJS({
|
|
|
49002
49002
|
return value;
|
|
49003
49003
|
};
|
|
49004
49004
|
Traverse.prototype.map = function(cb) {
|
|
49005
|
-
return
|
|
49005
|
+
return walk2(this.value, cb, true);
|
|
49006
49006
|
};
|
|
49007
49007
|
Traverse.prototype.forEach = function(cb) {
|
|
49008
|
-
this.value =
|
|
49008
|
+
this.value = walk2(this.value, cb, false);
|
|
49009
49009
|
return this.value;
|
|
49010
49010
|
};
|
|
49011
49011
|
Traverse.prototype.reduce = function(cb, init) {
|
|
@@ -49116,7 +49116,7 @@ var require_traverse = __commonJS({
|
|
|
49116
49116
|
}
|
|
49117
49117
|
})(this.value);
|
|
49118
49118
|
};
|
|
49119
|
-
function
|
|
49119
|
+
function walk2(root2, cb, immutable) {
|
|
49120
49120
|
var path = [];
|
|
49121
49121
|
var parents = [];
|
|
49122
49122
|
var alive = true;
|
|
@@ -190894,6 +190894,7 @@ var DEFAULT_RECORDING_STATUSES = [
|
|
|
190894
190894
|
{ name: "final", colour: 9 }
|
|
190895
190895
|
// purple
|
|
190896
190896
|
];
|
|
190897
|
+
var RERECORD_STATUS = "rerecord";
|
|
190897
190898
|
function deriveRecordingFolders(audioRoot, statuses) {
|
|
190898
190899
|
const root2 = audioRoot?.trim();
|
|
190899
190900
|
return statuses.map((s, i) => {
|
|
@@ -193886,8 +193887,17 @@ function exportBundle(input) {
|
|
|
193886
193887
|
},
|
|
193887
193888
|
voiced: project.voiced ?? false,
|
|
193888
193889
|
locales: { default: project.locales.default, included: Object.keys(strings) },
|
|
193889
|
-
|
|
193890
|
-
//
|
|
193890
|
+
// The cast is copied field by field, on purpose. Most of a CastMember is authoring context that must
|
|
193891
|
+
// never reach players: `notes` are production chatter, `gender` is translator context (it rides the
|
|
193892
|
+
// localisation formats), and `actor` is a real person's name (it belongs in the VO script). Listing
|
|
193893
|
+
// what ships, rather than subtracting what doesn't, means a field added to CastMember tomorrow stays
|
|
193894
|
+
// out of the bundle until someone deliberately adds it here.
|
|
193895
|
+
cast: project.cast?.map((c2) => {
|
|
193896
|
+
const m = { name: c2.name };
|
|
193897
|
+
if (c2.displayName !== void 0) m.displayName = c2.displayName;
|
|
193898
|
+
if (c2.gameData !== void 0) m.gameData = c2.gameData;
|
|
193899
|
+
return m;
|
|
193900
|
+
}),
|
|
193891
193901
|
properties: project.properties,
|
|
193892
193902
|
scopeRegistry: project.scopeRegistry,
|
|
193893
193903
|
gameDataFields: project.gameDataFields,
|
|
@@ -194021,7 +194031,7 @@ function bundleOutputPath(loaded) {
|
|
|
194021
194031
|
}
|
|
194022
194032
|
|
|
194023
194033
|
// ../ops/src/playable-runtime.ts
|
|
194024
|
-
var PLAYABLE_RUNTIME_JS = '"use strict";var Patterplay=(()=>{var A=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var ce=Object.getOwnPropertyNames;var le=Object.prototype.hasOwnProperty;var pe=(s,e)=>{for(var t in e)A(s,t,{get:e[t],enumerable:!0})},de=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of ce(e))!le.call(s,n)&&n!==t&&A(s,n,{get:()=>e[n],enumerable:!(r=ae(e,n))||r.enumerable});return s};var ge=s=>de(A({},"__esModule",{value:!0}),s);var xe={};pe(xe,{Engine:()=>B,Flow:()=>v,buildTagIndex:()=>O,effectiveGameData:()=>se,gameDataFields:()=>ne,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 w(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 x=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??W(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??W(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 W(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 k(s){return s.ctx.host??{}}var I={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=k(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:K("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:K("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)=>k(e).visits?.(C(s,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:D("seen"),eval:(s,e)=>(k(e).visits?.(C(s,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:D("patter_visits"),eval:(s,e)=>k(e).patterVisits?.(C(s,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:D("patter_seen"),eval:(s,e)=>(k(e).patterVisits?.(C(s,e,"patter_seen"))??0)>0}}};function V(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 C(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 K(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 ue=/^@[A-Za-z0-9_.]+$/;function*fe(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:ue.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 he(s){return Array.isArray(s)?s.join(", "):typeof s=="boolean"?s?"true":"false":String(s)}function me(s){return s===" "||s===" "||s===`\n`||s==="\\r"||s==="\\f"||s==="\\v"}function Se(s){let e="",t=!1;for(let r of s){if(me(r)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=r}return e}function z(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?Se(r):s}function X(s,e){if(s.indexOf("{")<0)return s;let t="";for(let r of fe(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?"":he(n)}return t}function E(s,e){for(let t of s){e(t);let r=t.children;r&&E(r,e)}}function ye(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||ye(s.name)}function F(s){return`cast:${s}`}var T={open:"[",close:"]"},Z="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 Q=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 g=new Map,u=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)u.set(f.id,{sceneId:d}),L.set(f.id,f),b.set(h(f),f.id),E(f.children,q=>g.set(q.id,q));this.blockGameIdToId.set(d,b)}let $=e.properties??[],N=$.filter(d=>d.shared??!0).map(Y),ie=$.filter(d=>!(d.shared??!0)).map(Y),oe=new Set(N.map(d=>d.name.toLowerCase())),P=new x().defineOwned("patter",N),H=new Set;if(t.world){let d=e.scopeRegistry?.scopes.find(b=>b.token==="world"),m=(d?.declarations??[]).map(ee);P.defineForeign("world",t.world,m,d?.writable??!0),H.add("world")}for(let d of e.scopeRegistry?.scopes??[]){if(H.has(d.token))continue;let m=(d.declarations??[]).map(ee);P.defineForeign(d.token,we(d.declarations??[]),m,d.writable??!0)}let _=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()));_.set(d,b)}this.host={bundle:e,emitIds:l,strings:i,defaultStrings:o,castDisplay:c,nodeIndex:g,blockIndex:u,blockById:L,tagIndex:O(e),shared:P,patterSharedDecls:N,patterLocalDecls:ie,patterSharedNames:oe,sceneSharedNames:_,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??T).open,captionClose:(e.closedCaptions??T).close,captionCharacter:e.closedCaptions?.character||Z,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)E(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[F(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:be(e)}))}splitShared(e){let t=this.host.refSplitCache.get(e);if(t||(t=V(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:te(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 re(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:te(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=re(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(u=>u.id);if(r.bag===void 0&&(r.bag=o()),r.bag.length===0){if(t==="once")return null;if(i){let u=e[n-1];return r.last=u.id,u}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 g=a[c];return a.splice(c,1),r.last=g,e.find(u=>u.id===g)}pickSpecificity(e,t,r){let n=e;if(t!=="repeat"){r.bag===void 0&&(r.bag=e.map(g=>g.id));let c=new Set(r.bag);if(n=e.filter(g=>c.has(g.id)),n.length===0)return t==="stick"&&r.last!==void 0?e.find(g=>g.id===r.last)??null:null}let i=-1,a=n.map(c=>{let g=this.specScore(c);return g>i&&(i=g),{c,s:g}}).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(u=>u.id===r.last):-1,g=Math.floor(this.rng()*(c>=0?a.length-1:a.length));c>=0&&g>=c&&g++,l=a[g]}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){if(e.kind==="binary"&&(e.op==="and"||e.op==="or")){let r=e.op==="and"===t,n=this.matchedSpec(e.left,t),i=this.matchedSpec(e.right,t);return r?n>0&&i>0?n+i:0:Math.max(n,i)}if(e.kind==="unary"&&e.op==="not")return this.matchedSpec(e.operand,!t);if(e.kind==="call"&&e.name==="check_flags"){let r=Math.max(1,e.args.length-1),n=M(w(e,this.evalCtx,I));return t?n?r:0:n?0:1}return M(w(e,this.evalCtx,I))===t?1:0}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?M(this.evalExpr(e.condition)):!0}evalExpr(e){return w(this.conditionAst(e),this.evalCtx,I)}conditionAst(e){let t=Q.get(e);return t||(t=S(e.ast),Q.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 X(e,t=>this.getProperty(t))}stripCaptions(e){return z(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 E(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=F(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=V(e,r=>r==="scene"||this.host.shared.has(r)),this.host.refSplitCache.set(e,t)),t}freshLocal(){return new x().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]=G(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]=G(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]=G(r))}}};function te(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 re(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 Y(s){return{name:s.name,type:s.type,values:s.values,default:s.default}}function be(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 ee(s){return{name:s.name,type:s.type,values:s.values,default:s.default,writable:s.writable}}function ve(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 we(s){let e=new Map;for(let t of s)e.set(t.name,ve(t));return{get:t=>e.get(t),set:(t,r)=>{e.set(t,r)}}}function G(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 M(s){return typeof s=="boolean"?s:typeof s=="number"?s!==0:typeof s=="string"?s!=="":s.length>0}function ne(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 se(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 ge(xe);})();\n//# sourceMappingURL=patterplay.min.js.map';
|
|
194034
|
+
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';
|
|
194025
194035
|
|
|
194026
194036
|
// ../ops/src/export-html.ts
|
|
194027
194037
|
var esc = (s) => s.replace(/[&<>]/g, (c2) => ({ "&": "&", "<": "<", ">": ">" })[c2]);
|
|
@@ -194224,6 +194234,39 @@ function scanAudioStatus(loaded) {
|
|
|
194224
194234
|
return out;
|
|
194225
194235
|
}
|
|
194226
194236
|
|
|
194237
|
+
// ../../node_modules/@wildwinter/expr-specificity/dist/index.js
|
|
194238
|
+
var CHECK_FLAGS_COUNTING_CALL = {
|
|
194239
|
+
name: "check_flags",
|
|
194240
|
+
count: (node) => Math.max(1, node.args.length - 1)
|
|
194241
|
+
};
|
|
194242
|
+
var DEFAULT_COUNTING_CALLS = [CHECK_FLAGS_COUNTING_CALL];
|
|
194243
|
+
function matchedSpecificity(node, evalTruthy, opts) {
|
|
194244
|
+
const countingCalls = opts?.countingCalls ?? DEFAULT_COUNTING_CALLS;
|
|
194245
|
+
return walk(node, opts?.want ?? true, evalTruthy, countingCalls);
|
|
194246
|
+
}
|
|
194247
|
+
function walk(node, want, evalTruthy, countingCalls) {
|
|
194248
|
+
if (node.kind === "binary" && (node.op === "and" || node.op === "or")) {
|
|
194249
|
+
const l2 = walk(node.left, want, evalTruthy, countingCalls);
|
|
194250
|
+
const r = walk(node.right, want, evalTruthy, countingCalls);
|
|
194251
|
+
const behaveAsAnd = node.op === "and" === want;
|
|
194252
|
+
if (behaveAsAnd) return l2 > 0 && r > 0 ? l2 + r : 0;
|
|
194253
|
+
return Math.max(l2, r);
|
|
194254
|
+
}
|
|
194255
|
+
if (node.kind === "unary" && node.op === "not") {
|
|
194256
|
+
return walk(node.operand, !want, evalTruthy, countingCalls);
|
|
194257
|
+
}
|
|
194258
|
+
if (node.kind === "call") {
|
|
194259
|
+
const rule = countingCalls.find((c2) => c2.name === node.name);
|
|
194260
|
+
if (rule) {
|
|
194261
|
+
const operands = rule.count(node);
|
|
194262
|
+
const holds = evalTruthy(node);
|
|
194263
|
+
if (want) return holds ? operands : 0;
|
|
194264
|
+
return holds ? 0 : 1;
|
|
194265
|
+
}
|
|
194266
|
+
}
|
|
194267
|
+
return evalTruthy(node) === want ? 1 : 0;
|
|
194268
|
+
}
|
|
194269
|
+
|
|
194227
194270
|
// ../../../expr/packages/scoperegistry/src/index.ts
|
|
194228
194271
|
var ScopeRegistry = class {
|
|
194229
194272
|
scopes = /* @__PURE__ */ new Map();
|
|
@@ -195361,21 +195404,8 @@ var Flow = class {
|
|
|
195361
195404
|
* node (comparisons, scoped vars, literals, other calls) is an atom, evaluated whole.
|
|
195362
195405
|
*/
|
|
195363
195406
|
matchedSpec(node, want) {
|
|
195364
|
-
|
|
195365
|
-
|
|
195366
|
-
const l2 = this.matchedSpec(node.left, want);
|
|
195367
|
-
const r = this.matchedSpec(node.right, want);
|
|
195368
|
-
return behaveAsAnd ? l2 > 0 && r > 0 ? l2 + r : 0 : Math.max(l2, r);
|
|
195369
|
-
}
|
|
195370
|
-
if (node.kind === "unary" && node.op === "not") {
|
|
195371
|
-
return this.matchedSpec(node.operand, !want);
|
|
195372
|
-
}
|
|
195373
|
-
if (node.kind === "call" && node.name === "check_flags") {
|
|
195374
|
-
const operands = Math.max(1, node.args.length - 1);
|
|
195375
|
-
const hit = truthy(evaluate(node, this.evalCtx, patterDialect));
|
|
195376
|
-
return want ? hit ? operands : 0 : hit ? 0 : 1;
|
|
195377
|
-
}
|
|
195378
|
-
return truthy(evaluate(node, this.evalCtx, patterDialect)) === want ? 1 : 0;
|
|
195407
|
+
const evalTruthy = (n) => truthy(evaluate(n, this.evalCtx, patterDialect));
|
|
195408
|
+
return matchedSpecificity(node, evalTruthy, { want });
|
|
195379
195409
|
}
|
|
195380
195410
|
/** A selector's cursor state - shared across flows (`group.shared`) or this flow's own. */
|
|
195381
195411
|
selectorState(group) {
|
|
@@ -195655,6 +195685,9 @@ function truthy(v) {
|
|
|
195655
195685
|
}
|
|
195656
195686
|
|
|
195657
195687
|
// ../ops/src/loaded-helpers.ts
|
|
195688
|
+
function effectiveRecording(id, base, rerecord, lowest) {
|
|
195689
|
+
return rerecord.has(id) ? RERECORD_STATUS : base.get(id) ?? lowest;
|
|
195690
|
+
}
|
|
195658
195691
|
function tableFor(loaded, locale) {
|
|
195659
195692
|
const table = {};
|
|
195660
195693
|
for (const l2 of loaded.locales) if (l2.locale === locale) Object.assign(table, l2.strings);
|
|
@@ -195681,12 +195714,14 @@ function mergeAuthoring(loaded) {
|
|
|
195681
195714
|
const writing = /* @__PURE__ */ new Map();
|
|
195682
195715
|
const recording = /* @__PURE__ */ new Map();
|
|
195683
195716
|
const cut = /* @__PURE__ */ new Set();
|
|
195717
|
+
const rerecord = /* @__PURE__ */ new Set();
|
|
195684
195718
|
const documentation = /* @__PURE__ */ new Map();
|
|
195685
195719
|
const edits = /* @__PURE__ */ new Map();
|
|
195686
195720
|
for (const a of loaded.authoring) {
|
|
195687
195721
|
for (const [id, v] of Object.entries(a.writing ?? {})) writing.set(id, v);
|
|
195688
195722
|
for (const [id, v] of Object.entries(a.recording ?? {})) recording.set(id, v);
|
|
195689
195723
|
for (const [id, v] of Object.entries(a.cut ?? {})) if (v) cut.add(id);
|
|
195724
|
+
for (const [id, v] of Object.entries(a.rerecord ?? {})) if (v) rerecord.add(id);
|
|
195690
195725
|
for (const [id, lines] of Object.entries(a.documentation ?? {})) {
|
|
195691
195726
|
const cur = documentation.get(id);
|
|
195692
195727
|
if (cur) cur.push(...lines);
|
|
@@ -195694,7 +195729,7 @@ function mergeAuthoring(loaded) {
|
|
|
195694
195729
|
}
|
|
195695
195730
|
for (const [id, v] of Object.entries(a.edits ?? {})) edits.set(id, v);
|
|
195696
195731
|
}
|
|
195697
|
-
return { writing, recording, cut, documentation, edits };
|
|
195732
|
+
return { writing, recording, cut, rerecord, documentation, edits };
|
|
195698
195733
|
}
|
|
195699
195734
|
|
|
195700
195735
|
// ../ops/src/play.ts
|
|
@@ -195822,11 +195857,11 @@ function analyzeHostScopes(bundle, hostTokens) {
|
|
|
195822
195857
|
refsIn(e.value);
|
|
195823
195858
|
}
|
|
195824
195859
|
};
|
|
195825
|
-
const
|
|
195860
|
+
const walk2 = (nodes, gate) => {
|
|
195826
195861
|
for (const node of nodes) {
|
|
195827
195862
|
const here = /* @__PURE__ */ new Set([...gate, ...refsIn(node.condition)]);
|
|
195828
195863
|
if (node.type === "group") {
|
|
195829
|
-
|
|
195864
|
+
walk2(node.children, here);
|
|
195830
195865
|
} else {
|
|
195831
195866
|
scanEffects(node.onEnter);
|
|
195832
195867
|
scanEffects(node.onExit);
|
|
@@ -195836,7 +195871,7 @@ function analyzeHostScopes(bundle, hostTokens) {
|
|
|
195836
195871
|
};
|
|
195837
195872
|
for (const scene of Object.values(bundle.scenes)) {
|
|
195838
195873
|
scanEffects(scene.onEntry);
|
|
195839
|
-
for (const block of scene.blocks)
|
|
195874
|
+
for (const block of scene.blocks) walk2(block.children, /* @__PURE__ */ new Set());
|
|
195840
195875
|
}
|
|
195841
195876
|
return { written, gatesByBeat, proposals };
|
|
195842
195877
|
}
|
|
@@ -196085,8 +196120,9 @@ function runReport(loaded, recordingOverride) {
|
|
|
196085
196120
|
const thresholdIdx = estimatingOn ? writingIndex.get(est?.thresholdStatus ?? "") ?? 0 : -1;
|
|
196086
196121
|
const defaultLines = est?.defaultLines ?? 0;
|
|
196087
196122
|
const tagMap = new Map((est?.tagEstimates ?? []).map((t) => [t.tag, t.lines]));
|
|
196088
|
-
const { writing: writingOf, recording: manualRecordingOf, cut: cutSet, edits: editsOf } = mergeAuthoring(loaded);
|
|
196089
|
-
const
|
|
196123
|
+
const { writing: writingOf, recording: manualRecordingOf, cut: cutSet, rerecord: rerecordSet, edits: editsOf } = mergeAuthoring(loaded);
|
|
196124
|
+
const recordingBase = recordingOverride ?? manualRecordingOf;
|
|
196125
|
+
const recordingOf = (id) => effectiveRecording(id, recordingBase, rerecordSet, recordingLadder[0]);
|
|
196090
196126
|
const byLocale = stringsByLocale(loaded);
|
|
196091
196127
|
const sourceStrings2 = byLocale.get(project.locales.default) ?? {};
|
|
196092
196128
|
const wordsOf = (id) => {
|
|
@@ -196199,7 +196235,7 @@ function runReport(loaded, recordingOverride) {
|
|
|
196199
196235
|
const wi = writingIndex.get(ws) ?? 0;
|
|
196200
196236
|
if (recordThreshold !== -1 && wi >= recordThreshold) voiced.readyToRecord++;
|
|
196201
196237
|
if (shipThreshold !== -1 && wi >= shipThreshold) voiced.readyToShip++;
|
|
196202
|
-
const rec = recordingOf
|
|
196238
|
+
const rec = recordingOf(u.id);
|
|
196203
196239
|
voiced.byRecording[rec] = (voiced.byRecording[rec] ?? 0) + 1;
|
|
196204
196240
|
const speaker = u.character ?? "(narrator)";
|
|
196205
196241
|
const ch = getChar(speaker);
|
|
@@ -196234,13 +196270,14 @@ function runReport(loaded, recordingOverride) {
|
|
|
196234
196270
|
const scenesByStatus = Object.fromEntries(writingLadder.map((s) => [s, 0]));
|
|
196235
196271
|
for (const s of reports) if (s.status) scenesByStatus[s.status] = (scenesByStatus[s.status] ?? 0) + 1;
|
|
196236
196272
|
const coverage = { totalScenes: reports.length, estimated: reports.filter((s) => s.estimated).length };
|
|
196273
|
+
const reportedRecordingLadder = (totals.voiced.byRecording[RERECORD_STATUS] ?? 0) > 0 ? [...recordingLadder, RERECORD_STATUS] : recordingLadder;
|
|
196237
196274
|
return {
|
|
196238
196275
|
project: { id: project.project.id, name: project.project.name },
|
|
196239
196276
|
voiced: project.voiced ?? false,
|
|
196240
196277
|
// Recording tracking is opt-in (default off) even for a voiced project (#206).
|
|
196241
196278
|
recordingTracked: (project.voiced ?? false) && (project.trackAudioStatus ?? false),
|
|
196242
196279
|
writingLadder,
|
|
196243
|
-
recordingLadder,
|
|
196280
|
+
recordingLadder: reportedRecordingLadder,
|
|
196244
196281
|
scenes: reports,
|
|
196245
196282
|
characters: [...characters2.values()].sort((a, b) => b.lines + b.estimatedLines - (a.lines + a.estimatedLines)),
|
|
196246
196283
|
locales,
|
|
@@ -196481,12 +196518,18 @@ function extractLoc(loaded, opts = {}) {
|
|
|
196481
196518
|
const localised = e?.localisedAt?.[targetLocale];
|
|
196482
196519
|
return !!(e?.modifiedAt && localised && e.modifiedAt > localised);
|
|
196483
196520
|
};
|
|
196521
|
+
const genderOf = /* @__PURE__ */ new Map();
|
|
196522
|
+
for (const c2 of loaded.project.cast ?? []) if (c2.gender) genderOf.set(c2.name, c2.gender);
|
|
196523
|
+
const withGender = (context) => {
|
|
196524
|
+
const g = context?.character ? genderOf.get(context.character) : void 0;
|
|
196525
|
+
return g ? { ...context, gender: g } : context;
|
|
196526
|
+
};
|
|
196484
196527
|
const entries = [];
|
|
196485
196528
|
const push2 = (id, scene, context) => {
|
|
196486
196529
|
const src = source2[id];
|
|
196487
196530
|
if (src === void 0) return;
|
|
196488
196531
|
const translation = isTemplate ? "" : target[id] ?? "";
|
|
196489
|
-
entries.push({ id, scene, source: src, translation, comments: commentsOf(id), context, stale: staleFor(id, translation) });
|
|
196532
|
+
entries.push({ id, scene, source: src, translation, comments: commentsOf(id), context: withGender(context), stale: staleFor(id, translation) });
|
|
196490
196533
|
};
|
|
196491
196534
|
for (const scene of loaded.scenes) {
|
|
196492
196535
|
for (const block of scene.blocks) {
|
|
@@ -196507,7 +196550,7 @@ function extractLoc(loaded, opts = {}) {
|
|
|
196507
196550
|
const id = castStringKey(c2.name);
|
|
196508
196551
|
const src = source2[id] ?? c2.displayName;
|
|
196509
196552
|
const translation = isTemplate ? "" : target[id] ?? "";
|
|
196510
|
-
entries.push({ id, scene: PROJECT_LOCALE_SCENE, source: src, translation, comments: commentsOf(id), context: { character: c2.name }, stale: staleFor(id, translation) });
|
|
196553
|
+
entries.push({ id, scene: PROJECT_LOCALE_SCENE, source: src, translation, comments: commentsOf(id), context: withGender({ character: c2.name }), stale: staleFor(id, translation) });
|
|
196511
196554
|
}
|
|
196512
196555
|
return { project: loaded.project.project.id, defaultLocale, locale: targetLocale, entries };
|
|
196513
196556
|
}
|
|
@@ -196630,6 +196673,7 @@ function catalogToPo(catalog) {
|
|
|
196630
196673
|
if (e.context?.character || e.context?.kind) {
|
|
196631
196674
|
out.push(`#. [${[e.context.kind, e.context.character].filter(Boolean).join(" ")}]`);
|
|
196632
196675
|
}
|
|
196676
|
+
if (e.context?.gender) out.push(`#. Gender: ${e.context.gender}`);
|
|
196633
196677
|
out.push(`#: ${e.scene}`);
|
|
196634
196678
|
if (e.stale) out.push("#, fuzzy");
|
|
196635
196679
|
out.push(poField("msgctxt", e.id), poField("msgid", e.source), poField("msgstr", e.translation), "");
|
|
@@ -196723,7 +196767,7 @@ function poToCatalog(text) {
|
|
|
196723
196767
|
}
|
|
196724
196768
|
|
|
196725
196769
|
// ../ops/src/loc-xlsx.ts
|
|
196726
|
-
var HEADERS = ["ID", "Source", "Translation", "Comments", "Status"];
|
|
196770
|
+
var HEADERS = ["ID", "Source", "Translation", "Comments", "Status", "Gender"];
|
|
196727
196771
|
var sheetName = (scene) => scene.replace(/[:\\/?*[\]]/g, "-").slice(0, 31);
|
|
196728
196772
|
async function catalogToXlsx(catalog) {
|
|
196729
196773
|
const { default: ExcelJS } = await Promise.resolve().then(() => __toESM(require_excel(), 1));
|
|
@@ -196738,7 +196782,8 @@ async function catalogToXlsx(catalog) {
|
|
|
196738
196782
|
{ header: "Source", key: "source", width: 40 },
|
|
196739
196783
|
{ header: "Translation", key: "translation", width: 40 },
|
|
196740
196784
|
{ header: "Comments", key: "comments", width: 30 },
|
|
196741
|
-
{ header: "Status", key: "status", width: 10 }
|
|
196785
|
+
{ header: "Status", key: "status", width: 10 },
|
|
196786
|
+
{ header: "Gender", key: "gender", width: 12 }
|
|
196742
196787
|
];
|
|
196743
196788
|
ws.getRow(1).font = { bold: true };
|
|
196744
196789
|
for (const e of entries) {
|
|
@@ -196747,7 +196792,8 @@ async function catalogToXlsx(catalog) {
|
|
|
196747
196792
|
source: e.source,
|
|
196748
196793
|
translation: e.translation,
|
|
196749
196794
|
comments: e.comments.join("\n"),
|
|
196750
|
-
status: e.stale ? "stale" : e.translation ? "translated" : ""
|
|
196795
|
+
status: e.stale ? "stale" : e.translation ? "translated" : "",
|
|
196796
|
+
gender: e.context?.gender ?? ""
|
|
196751
196797
|
});
|
|
196752
196798
|
}
|
|
196753
196799
|
}
|
|
@@ -196802,8 +196848,9 @@ function runVoiceScript(loaded, opts = {}) {
|
|
|
196802
196848
|
const stub = writingLadder[0];
|
|
196803
196849
|
const recordThreshold = ladderDecls.findIndex((s) => s.readyToRecord);
|
|
196804
196850
|
const writingIndex = new Map(writingLadder.map((name, i) => [name, i]));
|
|
196805
|
-
const { writing: writingOf, recording: manualRecordingOf, cut: cutSet, documentation: docsOf } = mergeAuthoring(loaded);
|
|
196806
|
-
const
|
|
196851
|
+
const { writing: writingOf, recording: manualRecordingOf, cut: cutSet, rerecord: rerecordSet, documentation: docsOf } = mergeAuthoring(loaded);
|
|
196852
|
+
const recordingBase = opts.recordingOverride ?? manualRecordingOf;
|
|
196853
|
+
const recordingOf = (id) => effectiveRecording(id, recordingBase, rerecordSet, recordingLadder[0]);
|
|
196807
196854
|
const source2 = sourceStrings(loaded);
|
|
196808
196855
|
const actorOf = /* @__PURE__ */ new Map();
|
|
196809
196856
|
for (const c2 of project.cast ?? []) if (c2.actor) actorOf.set(c2.name, c2.actor);
|
|
@@ -196834,7 +196881,7 @@ function runVoiceScript(loaded, opts = {}) {
|
|
|
196834
196881
|
text: plainVoice(source2[beat.id] ?? ""),
|
|
196835
196882
|
comments: leading ? [...ancestorVo, ...own] : own,
|
|
196836
196883
|
// first line of the run gets the enclosing context
|
|
196837
|
-
recordingStatus: recordingOf
|
|
196884
|
+
recordingStatus: recordingOf(beat.id)
|
|
196838
196885
|
});
|
|
196839
196886
|
leading = false;
|
|
196840
196887
|
}
|
|
@@ -197025,7 +197072,7 @@ function runScriptDoc(loaded) {
|
|
|
197025
197072
|
}
|
|
197026
197073
|
if (node.jump) els.push({ kind: "jump", indent, snippet: sid, text: jumpText(node.jump) });
|
|
197027
197074
|
};
|
|
197028
|
-
const
|
|
197075
|
+
const walk2 = (node, indent, sid) => {
|
|
197029
197076
|
if (cut.has(node.id)) return;
|
|
197030
197077
|
if (node.type === "snippet") {
|
|
197031
197078
|
if (node.condition) els.push({ kind: "condition", indent, snippet: sid, text: `if ${humanize(node.condition)}` });
|
|
@@ -197041,7 +197088,7 @@ function runScriptDoc(loaded) {
|
|
|
197041
197088
|
if (child.type === "group" && child.prompt) {
|
|
197042
197089
|
if (child.condition) els.push({ kind: "condition", indent, snippet: cid, text: `if ${humanize(child.condition)}` });
|
|
197043
197090
|
els.push({ kind: "option", indent, snippet: cid, runs: textRuns(textOf(child.prompt.id) || "(option)"), tag: optionTag(child) });
|
|
197044
|
-
for (const c2 of child.children ?? [])
|
|
197091
|
+
for (const c2 of child.children ?? []) walk2(c2, indent + 1, cid);
|
|
197045
197092
|
} else if (child.type === "snippet") {
|
|
197046
197093
|
const beats = child.beats ?? [];
|
|
197047
197094
|
const first2 = beats.find((b) => b.kind === "line" || b.kind === "text");
|
|
@@ -197060,7 +197107,7 @@ function runScriptDoc(loaded) {
|
|
|
197060
197107
|
}
|
|
197061
197108
|
if (child.jump) els.push({ kind: "jump", indent: indent + 1, snippet: cid, text: jumpText(child.jump) });
|
|
197062
197109
|
} else {
|
|
197063
|
-
|
|
197110
|
+
walk2(child, indent + 1, cid);
|
|
197064
197111
|
}
|
|
197065
197112
|
}
|
|
197066
197113
|
return;
|
|
@@ -197071,16 +197118,16 @@ function runScriptDoc(loaded) {
|
|
|
197071
197118
|
kids.forEach((child, i) => {
|
|
197072
197119
|
const isCatchAll = i === kids.length - 1 && kids.length > 1 && !("condition" in child && child.condition);
|
|
197073
197120
|
if (isCatchAll) els.push({ kind: "else", indent });
|
|
197074
|
-
|
|
197121
|
+
walk2(child, indent, nextSid());
|
|
197075
197122
|
});
|
|
197076
197123
|
return;
|
|
197077
197124
|
}
|
|
197078
197125
|
if (node.selector === "sequence") {
|
|
197079
197126
|
els.push({ kind: "group", indent, label: sequenceLabel(node) });
|
|
197080
|
-
for (const child of node.children ?? [])
|
|
197127
|
+
for (const child of node.children ?? []) walk2(child, indent, nextSid());
|
|
197081
197128
|
return;
|
|
197082
197129
|
}
|
|
197083
|
-
for (const child of node.children ?? [])
|
|
197130
|
+
for (const child of node.children ?? []) walk2(child, indent, sid);
|
|
197084
197131
|
};
|
|
197085
197132
|
for (const scene of loaded.scenes) {
|
|
197086
197133
|
if (cut.has(scene.id)) continue;
|
|
@@ -197088,7 +197135,7 @@ function runScriptDoc(loaded) {
|
|
|
197088
197135
|
for (const block of scene.blocks) {
|
|
197089
197136
|
if (cut.has(block.id)) continue;
|
|
197090
197137
|
els.push({ kind: "block", text: block.name });
|
|
197091
|
-
for (const child of block.children ?? [])
|
|
197138
|
+
for (const child of block.children ?? []) walk2(child, 0, void 0);
|
|
197092
197139
|
}
|
|
197093
197140
|
}
|
|
197094
197141
|
return { project: project.project.name, elements: els };
|
|
@@ -237665,14 +237712,14 @@ function orderChildren(merged, B, O, T, path, conflicts, warnings) {
|
|
|
237665
237712
|
}
|
|
237666
237713
|
function checkDuplicateIds(root2, conflicts) {
|
|
237667
237714
|
const seen = /* @__PURE__ */ new Set(), dup = /* @__PURE__ */ new Set();
|
|
237668
|
-
const
|
|
237715
|
+
const walk2 = (n) => {
|
|
237669
237716
|
if (n.id) {
|
|
237670
237717
|
if (seen.has(n.id)) dup.add(n.id);
|
|
237671
237718
|
else seen.add(n.id);
|
|
237672
237719
|
}
|
|
237673
|
-
n.children.forEach(
|
|
237720
|
+
n.children.forEach(walk2);
|
|
237674
237721
|
};
|
|
237675
|
-
|
|
237722
|
+
walk2(root2);
|
|
237676
237723
|
for (const id of dup) conflicts.push({ id, path: "scene", base: void 0, ours: void 0, theirs: void 0, kind: "structural" });
|
|
237677
237724
|
}
|
|
237678
237725
|
var idMap = (nodes) => new Map(nodes.filter((n) => n.id).map((n) => [n.id, n]));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patterkit/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
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.
|
|
32
|
+
"@patterkit/core": "0.1.3",
|
|
33
|
+
"@patterkit/ops": "0.2.0",
|
|
34
34
|
"@wildwinter/simple-vc-lib": "^0.2.0"
|
|
35
35
|
}
|
|
36
36
|
}
|