@datamoc/mw_games 0.17.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +1 -1
- package/dist/mw_games.global.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
- package/tools/csp.mjs +10 -1
- package/tools/sbom.mjs +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,31 @@ All notable changes to `mwg` are documented here. Format follows
|
|
|
5
5
|
[Semantic Versioning](https://semver.org/) as of this first release - a 0.y.z version means
|
|
6
6
|
the public API may still change between minor versions.
|
|
7
7
|
|
|
8
|
+
## [0.17.1] - 2026-09-25
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- A page built on a Windows checkout refused its own inline script. The HTML parser turns
|
|
13
|
+
newlines into LF before it hashes an inline script, while `contentSecurityPolicy` hashed the
|
|
14
|
+
CRLF bytes a `core.autocrlf=true` checkout hands over, so Chrome computed a different hash
|
|
15
|
+
from the one the policy allowed. The page logged a Content-Security-Policy violation that
|
|
16
|
+
`mwg-smoke`, the visual smoke and `mwg-bench` read as a page error, the source-page fallback
|
|
17
|
+
script never ran, and the same build on Linux stayed quiet - which is why no browser job had
|
|
18
|
+
caught it. Inline scripts are now hashed after CRLF and lone CR become LF; the standalone
|
|
19
|
+
page's unpacker scripts stay hashed as written, since no parser touches those. A CRLF
|
|
20
|
+
checkout and an LF checkout now produce the same policy, pinned by a test.
|
|
21
|
+
- The committed-artifact checks no longer read the checkout's line endings. `api:check`,
|
|
22
|
+
`stats:check`, `sbom:check` and the committed-SBOM test compared generated text against the
|
|
23
|
+
committed file byte for byte, so a Windows clone failed them on a tree `git diff` called
|
|
24
|
+
clean; `bundle.distRaw` summed the bytes `tsc` copies out of a source file's comments, which
|
|
25
|
+
recorded who generated the file rather than what ships.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- The `check` job runs on `windows-latest` alongside `ubuntu-latest`, so the two failures above
|
|
30
|
+
fail the push instead of reaching a Windows contributor. The gates themselves are unchanged,
|
|
31
|
+
and `fail-fast` is off so one OS failing still shows the other.
|
|
32
|
+
|
|
8
33
|
## [0.17.0] - 2026-09-25
|
|
9
34
|
|
|
10
35
|
### Security
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ playable in the browser with no download, plus the generated API reference.
|
|
|
15
15
|
planning or porting a demanding game with mwg, with links to the [mwg reference](https://github.com/datamoc/mwg/blob/main/REFERENCE.md)
|
|
16
16
|
and the [mwg Pixel Dungeon study](https://datamoc.github.io/mwg-pixel-dungeon/).
|
|
17
17
|
|
|
18
|
-
> **Status: pre-alpha (v0.17.
|
|
18
|
+
> **Status: pre-alpha (v0.17.1).** Every module in the shared floor below, plus optional
|
|
19
19
|
> 3D, mobile (Capacitor) and desktop (WebView2) packaging, is built and tested - see
|
|
20
20
|
> [ROADMAP.md](https://github.com/datamoc/mwg/blob/main/ROADMAP.md) for open work, and
|
|
21
21
|
> [CLOSED.md](https://github.com/datamoc/mwg/blob/main/CLOSED.md) for the full, numbered shipped history.
|
package/dist/mw_games.global.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var mw_games=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(e){throw n=[e],e}},c=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),l=(e,t)=>{let r={};for(var i in e)n(r,i,{get:e[i],enumerable:!0});return t||n(r,Symbol.toStringTag,{value:`Module`}),r},u=(e,t,a,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=i(t),l=0,u=c.length,d;l<u;l++)d=c[l],!o.call(e,d)&&d!==a&&n(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(s=r(t,d))||s.enumerable});return e},d=(e,r,i)=>(i=e==null?{}:t(a(e)),u(r||!e||!e.__esModule||!o.call(e,`default`)?n(i,`default`,{value:e,enumerable:!0}):i,e)),f=`0.17.0`,p=class{constructor(e=!1){this.listeners=[],this.stackMode=e}add(e){this.listeners.includes(e)||(this.stackMode?this.listeners.unshift(e):this.listeners.push(e))}remove(e){let t=this.listeners.indexOf(e);t!==-1&&this.listeners.splice(t,1)}removeAll(){this.listeners.length=0}get size(){return this.listeners.length}dispatch(e){let t=this.listeners.slice();for(let n of t)if(this.listeners.includes(n)&&n(e)===!0)return!0;return!1}},m=class{constructor(){this.onDestroy=new p,this.destroyed=!1}update(e){}resize(e,t){}onSuspend(){}onResume(e){}destroy(){this.destroyed||(this.destroyed=!0,this.onDestroy.dispatch(),this.onDestroy.removeAll(),this.teardown())}teardown(){}get isDestroyed(){return this.destroyed}},h=class{constructor(){this.scenes=[]}get current(){return this.scenes.length===0?null:this.scenes[this.scenes.length-1]}get depth(){return this.scenes.length}replace(e){for(let e of this.scenes)e.destroy();this.scenes=[e],e.create()}push(e){this.current?.onSuspend(),this.scenes.push(e),e.create()}pop(e){if(this.scenes.length<=1)throw Error(`cannot pop the last scene off the stack - switchScene somewhere instead`);this.scenes.pop()?.destroy(),this.current?.onResume(e)}update(e){this.current?.update(e)}resize(e,t){for(let n of this.scenes)n.resize(e,t)}destroy(){for(let e of this.scenes)e.destroy();this.scenes=[]}},g=class{constructor(){this.items=new Map}register(e,t){if(this.items.has(e))throw Error(`"${e}" is already registered`);this.items.set(e,t)}get(e){let t=this.items.get(e);if(t===void 0)throw Error(`no registration named "${e}"`);return t}has(e){return this.items.has(e)}list(){return[...this.items.keys()]}},_=class{constructor(){this.order=[],this.registry=new g}add(e,t){this.registry.register(e.name,e),this.order.push(e),e.create?.(t)}has(e){return this.registry.has(e)}get(e){return this.registry.get(e)}update(e,t){for(let n of this.order)n.update?.(e,t)}resize(e,t,n){for(let r of this.order)r.resize?.(e,t,n)}onSuspend(e){for(let t of this.order)t.onSuspend?.(e)}onResume(e,t){for(let n of this.order)n.onResume?.(e,t)}destroy(e){for(let t=this.order.length-1;t>=0;t--)this.order[t].destroy?.(e);this.order=[],this.registry=new g}},v={debug:0,info:1,warn:2,error:3},y=class{constructor(e,t={}){if(!e)throw Error(`a logger needs a category`);this.category=e,this.level=t.level??`debug`,this.sink=t.sink??b}setLevel(e){this.level=e}debug(e,t){this.write(`debug`,e,t)}info(e,t){this.write(`info`,e,t)}warn(e,t){this.write(`warn`,e,t)}error(e,t){this.write(`error`,e,t)}write(e,t,n){v[e]<v[this.level]||this.sink({level:e,category:this.category,message:t,data:n,time:Date.now()})}};function b(e){let t=`[${e.category}] ${e.message}`;e.level===`debug`?console.debug(t,e.data??``):e.level===`info`?console.info(t,e.data??``):e.level===`warn`?console.warn(t,e.data??``):console.error(t,e.data??``)}var x=class{constructor(){this.hooks=[]}on(e,t,n){this.hooks.push({event:e,handler:t,source:n})}off(e){this.hooks=this.hooks.filter(t=>t.handler!==e)}offSource(e){this.hooks=this.hooks.filter(t=>t.source!==e)}emit(e,...t){for(let n of[...this.hooks])n.event===e&&n.handler(...t)}get size(){return this.hooks.length}clear(){this.hooks=[]}},S=l({Generator:()=>w,MersenneTwister:()=>ge,RandomStreams:()=>ve,chance:()=>se,element:()=>ce,float:()=>D,int:()=>O,normalRange:()=>oe,pop:()=>ne,push:()=>te,range:()=>ae,reset:()=>ie,shuffle:()=>ue,weighted:()=>le,weightedKey:()=>k,withSeed:()=>re});function C(e){let t=e>>>0;return()=>{t=t+2654435769>>>0;let e=t;return e=Math.imul(e^e>>>16,569420461),e=Math.imul(e^e>>>15,1935289751),(e^e>>>15)>>>0}}var w=class{constructor(e){this.s0=0,this.s1=0,this.s2=0,this.s3=0,this.seed=e===void 0?Math.random()*4294967296>>>0:e>>>0;let t=C(this.seed);this.s0=t(),this.s1=t(),this.s2=t(),this.s3=t(),(this.s0|this.s1|this.s2|this.s3)===0&&(this.s0=1)}nextUint32(){let e=Math.imul(ee(Math.imul(this.s1,5),7),9)>>>0>>>0,t=this.s1<<9>>>0;return this.s2^=this.s0,this.s3^=this.s1,this.s1^=this.s2,this.s0^=this.s3,this.s2^=t,this.s3=ee(this.s3,11),e}float(){return this.nextUint32()/4294967296}int(e){if(e<=0)return 0;let t=4294967296-4294967296%e,n=this.nextUint32();for(;n>=t;)n=this.nextUint32();return n%e}getState(){return[this.s0,this.s1,this.s2,this.s3]}setState(e){[this.s0,this.s1,this.s2,this.s3]=e}};function ee(e,t){return(e<<t|e>>>32-t)>>>0}var T=[new w],E=()=>T[T.length-1];function te(e){let t=new w(e);return T.push(t),t}function ne(){if(T.length===1)throw Error(`the base random generator cannot be popped`);T.pop()}function re(e,t){te(e);try{return t()}finally{ne()}}function ie(){T.length=0,T.push(new w)}function D(e,t){return e===void 0?E().float():t===void 0?E().float()*e:e+E().float()*(t-e)}function O(e,t){return t===void 0?E().int(e):e+E().int(t-e)}function ae(e,t){return e+E().int(t-e+1)}function oe(e,t){return e+Math.floor((E().float()+E().float())*(t-e+1)/2)}function se(e){return E().float()<e}function ce(e){return e.length>0?e[E().int(e.length)]:null}function le(e){let t=0;for(let n of e)t+=n;if(t<=0)return null;let n=E().float()*t;for(let t=0;t<e.length;t++)if(n-=e[t],n<0)return t;return e.length-1}function k(e){let t=[...e.keys()],n=le(t.map(t=>e.get(t)??0));return n===null?null:t[n]}function ue(e){for(let t=e.length-1;t>0;t--){let n=E().int(t+1);[e[t],e[n]]=[e[n],e[t]]}return e}var de=624,fe=397,pe=2567483615,me=2147483648,he=2147483647,ge=class{constructor(e=5489){this.state=new Uint32Array(de),this.index=de,this.seedValue=5489,this.produced=0,this.seed(e)}seed(e){this.seedValue=e>>>0,this.state[0]=this.seedValue;for(let e=1;e<de;e++){let t=this.state[e-1]^this.state[e-1]>>>30;this.state[e]=Math.imul(1812433253,t)+e>>>0}this.index=de,this.produced=0}generate(){for(let e=0;e<de;e++){let t=this.state[e]&me|this.state[(e+1)%de]&he,n=this.state[(e+fe)%de]^t>>>1;t&1&&(n^=pe),this.state[e]=n>>>0}this.index=0}nextUint32(){this.index>=de&&this.generate();let e=this.state[this.index++];return e^=e>>>11,e^=e<<7&2636928640,e^=e<<15&4022730752,e^=e>>>18,this.produced++,e>>>0}float(){return this.nextUint32()/4294967296}int(e){if(e<=0)return 0;let t=4294967296-4294967296%e,n=this.nextUint32();for(;n>=t;)n=this.nextUint32();return n%e}discard(e){for(let t=0;t<e;t++)this.nextUint32()}get discardCount(){return this.produced}getState(){return{seed:this.seedValue,state:[...this.state],index:this.index,discard:this.produced}}setState(e){this.seedValue=e.seed>>>0;for(let t=0;t<de;t++)this.state[t]=(e.state[t]??0)>>>0;this.index=e.index,this.produced=e.discard}};function _e(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619)>>>0;return t>>>0}var ve=class{constructor(e=0){this.streams=new Map,this.baseSeed=e>>>0}stream(e){let t=this.streams.get(e);if(!t){let n=(this.baseSeed^_e(e))>>>0;t={seed:n,engine:new ge(n)},this.streams.set(e,t)}return t.engine}seedOf(e){return this.streams.get(e)?.seed}reseed(e){this.baseSeed=e>>>0,this.streams.clear()}names(){return[...this.streams.keys()]}getState(){let e={};for(let[t,n]of this.streams)e[t]=n.engine.getState();return e}setState(e){for(let[t,n]of Object.entries(e)){let e=new ge(n.seed);e.setState(n),this.streams.set(t,{seed:n.seed,engine:e})}}},ye=l({DEFAULT_BINDINGS:()=>je,actionsForKey:()=>Pe,attach:()=>ht,attachSwipe:()=>mt,bind:()=>Me,bindAxis:()=>at,bindButton:()=>it,bindTouch:()=>lt,detach:()=>gt,dispatchComposition:()=>Ee,dispatchText:()=>Te,endFrame:()=>Ke,exportBindings:()=>Le,gamepadAxisCode:()=>rt,gamepadButtonCode:()=>nt,importBindings:()=>Re,isDown:()=>Ue,justPressed:()=>We,justReleased:()=>Ge,keysFor:()=>Ie,onAction:()=>Se,onComposition:()=>we,onKey:()=>M,onText:()=>Ce,onWheel:()=>De,pollGamepads:()=>ot,pressTouch:()=>ut,releaseTouch:()=>dt,resetBindings:()=>ze,rumble:()=>st,textFromKey:()=>N,touchCode:()=>ct,unbind:()=>Fe,wheelActionFor:()=>Oe}),be=new Map,A=new Set,j=new Set,xe=new Set,Se=new p(!0),M=new p(!0),Ce=new p(!0),we=new p(!0);function N(e){return e.isComposing||e.ctrlKey||e.metaKey||e.altKey?null:e.key.length===1?e.key:null}function Te(e){e.length>0&&Ce.dispatch(e)}function Ee(e){we.dispatch({phase:e.phase,text:e.text})}var De=new p(!0);function Oe(e){return e.ctrlKey||e.metaKey?`zoom`:e.shiftKey?`scrollHorizontal`:`scroll`}function ke(e){let t=Oe(e);t===`zoom`&&e.preventDefault();let n=t===`scrollHorizontal`&&e.deltaX!==0?e.deltaX:e.deltaY;De.dispatch({action:t,delta:n})}var Ae=!1,je={up:[`ArrowUp`,`KeyW`,`Numpad8`],down:[`ArrowDown`,`KeyS`,`Numpad2`],left:[`ArrowLeft`,`KeyA`,`Numpad4`],right:[`ArrowRight`,`KeyD`,`Numpad6`],upLeft:[`Numpad7`],upRight:[`Numpad9`],downLeft:[`Numpad1`],downRight:[`Numpad3`],wait:[`Numpad5`,`Period`],confirm:[`Enter`,`Space`,`NumpadEnter`],cancel:[`Escape`,`Backspace`],menu:[`KeyI`,`Tab`]};function Me(e,t){be.set(e,new Set(t))}function Ne(e,t){let n=be.get(e)??new Set;for(let e of t)n.add(e);be.set(e,n)}function Pe(e){return Be(e)}function Fe(e){be.delete(e)}function Ie(e){return[...be.get(e)??[]]}function Le(){let e={};for(let[t,n]of be)e[t]=[...n];return e}function Re(e){be.clear();for(let[t,n]of Object.entries(e))Me(t,n)}function ze(){Re(je)}ze();function Be(e){let t=[];for(let[n,r]of be)r.has(e)&&t.push(n);return t}function Ve(e){if(!A.has(e)){A.add(e);for(let t of Be(e))j.add(t),Se.dispatch(t)}}function He(e){if(A.has(e)){A.delete(e);for(let t of Be(e))xe.add(t)}}function Ue(e){let t=be.get(e);if(!t)return!1;for(let e of t)if(A.has(e))return!0;return!1}function We(e){return j.has(e)}function Ge(e){return xe.has(e)}function Ke(){j.clear(),xe.clear()}function qe(e){let t=N(e);t!==null&&Te(t)}function Je(e){if(e.repeat){M.dispatch(e),qe(e);return}Ve(e.code),M.dispatch(e),qe(e)}function Ye(e){He(e.code)}function Xe(e){Ee({phase:`start`,text:e.data??``})}function Ze(e){Ee({phase:`update`,text:e.data??``})}function Qe(e){Ee({phase:`end`,text:e.data??``})}function $e(){A.clear(),j.clear(),xe.clear()}var et=.5,tt=new Set;function nt(e,t){return`Gamepad${e}Button${t}`}function rt(e,t,n){return`Gamepad${e}Axis${t}${n>0?`+`:`-`}`}function it(e,t,n){Ne(e,n.map(e=>nt(t,e)))}function at(e,t,n,r){Ne(e,[rt(t,n,r)])}function ot(e=typeof navigator?.getGamepads==`function`?navigator.getGamepads():[]){tt.clear();for(let t of e)if(t){for(let e=0;e<t.buttons.length;e++)t.buttons[e].pressed&&tt.add(nt(t.index,e));for(let e=0;e<t.axes.length;e++){let n=t.axes[e];n>=et?tt.add(rt(t.index,e,1)):n<=-.5&&tt.add(rt(t.index,e,-1))}}for(let e of tt)Ve(e);for(let e of A)!tt.has(e)&&e.startsWith(`Gamepad`)&&He(e)}function st(e,t,n=typeof navigator?.getGamepads==`function`?navigator.getGamepads():[]){(n[e]?.vibrationActuator)?.playEffect(`dual-rumble`,{duration:t.duration,weakMagnitude:t.weakMagnitude??1,strongMagnitude:t.strongMagnitude??1})}function ct(e){return`Touch:${e}`}function lt(e,t=e){Ne(e,[ct(t)])}function ut(e){Ve(ct(e))}function dt(e){He(ct(e))}var ft={up:`up`,down:`down`,left:`left`,right:`right`,upLeft:`upLeft`,upRight:`upRight`,downLeft:`downLeft`,downRight:`downRight`},pt=[`right`,`downRight`,`down`,`downLeft`,`left`,`upLeft`,`up`,`upRight`];function mt(e,t={}){let n={...ft,...t.actions},r=t.minDistance??24;for(let e of[...pt,`tap`]){let t=n[e];t&<(t,`swipe:${e}`)}let i=!1,a=-1,o=0,s=0;function c(e){ut(`swipe:${e}`),dt(`swipe:${e}`)}function l(e){i=!0,a=e.pointerId,o=e.clientX,s=e.clientY}function u(e){if(!i||e.pointerId!==a)return;i=!1;let t=e.clientX-o,l=e.clientY-s;if(Math.hypot(t,l)<r){n.tap&&c(`tap`);return}let u=pt[(Math.round(Math.atan2(l,t)/(Math.PI/4))%8+8)%8];n[u]&&c(u)}return e.addEventListener(`pointerdown`,l),e.addEventListener(`pointerup`,u),e.addEventListener(`pointercancel`,u),()=>{e.removeEventListener(`pointerdown`,l),e.removeEventListener(`pointerup`,u),e.removeEventListener(`pointercancel`,u)}}function ht(e=window){Ae||(Ae=!0,e.addEventListener(`keydown`,Je),e.addEventListener(`keyup`,Ye),e.addEventListener(`compositionstart`,Xe),e.addEventListener(`compositionupdate`,Ze),e.addEventListener(`compositionend`,Qe),window.addEventListener(`blur`,$e),e.addEventListener(`wheel`,ke,{passive:!1}))}function gt(e=window){Ae&&(Ae=!1,e.removeEventListener(`keydown`,Je),e.removeEventListener(`keyup`,Ye),e.removeEventListener(`compositionstart`,Xe),e.removeEventListener(`compositionupdate`,Ze),e.removeEventListener(`compositionend`,Qe),e.removeEventListener(`wheel`,ke),window.removeEventListener(`blur`,$e),$e())}var _t=class{constructor(e,t={}){if(!e)throw Error(`a player needs a non-empty id`);this.id=e,this.padIndex=t.padIndex}scoped(e){return`${this.id}:${e}`}bind(e,t){Me(this.scoped(e),t)}bindButton(e,t){if(this.padIndex===void 0)throw Error(`player "${this.id}" has no padIndex to bind a gamepad button to`);it(this.scoped(e),this.padIndex,t)}bindAxis(e,t,n){if(this.padIndex===void 0)throw Error(`player "${this.id}" has no padIndex to bind a gamepad axis to`);at(this.scoped(e),this.padIndex,t,n)}bindTouch(e,t=e){lt(this.scoped(e),`${this.id}:${t}`)}pressTouch(e){ut(`${this.id}:${e}`)}releaseTouch(e){dt(`${this.id}:${e}`)}isDown(e){return Ue(this.scoped(e))}justPressed(e){return We(this.scoped(e))}justReleased(e){return Ge(this.scoped(e))}keysFor(e){return Ie(this.scoped(e))}};function vt(e,t){if(!t)throw Error(`scramble needs a non-empty key`);let n=new TextEncoder().encode(e),r=new TextEncoder().encode(t),i=new Uint8Array(n.length);for(let e=0;e<n.length;e++)i[e]=n[e]^r[e%r.length];return bt(i)}function yt(e,t){if(!t)throw Error(`scramble needs a non-empty key`);let n=xt(e),r=new TextEncoder().encode(t),i=new Uint8Array(n.length);for(let e=0;e<n.length;e++)i[e]=n[e]^r[e%r.length];return new TextDecoder(`utf-8`,{fatal:!0}).decode(i)}function bt(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t)}function xt(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}var St=10485760;function Ct(e,t={}){let n=t.maxBytes??St,r=typeof e==`string`?new TextEncoder().encode(e).length:e.length;if(r>n)throw Error(`inbound data exceeds the ${n}-byte limit (${r} bytes)`)}function wt(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n!==9&&n!==10&&n!==13&&(n<=31||n===127))throw Error(`inbound data contains a control character (0x${n.toString(16).padStart(2,`0`)}) at index ${t}`)}}function Tt(e,t={}){return Ct(e,t),wt(e),e}var Et=new Set([`__proto__`,`constructor`,`prototype`]);function Dt(e,t=`$`){if(Array.isArray(e)){e.forEach((e,n)=>Dt(e,`${t}[${n}]`));return}if(typeof e==`object`&&e)for(let n of Object.keys(e)){if(Et.has(n))throw Error(`${t} contains a forbidden key "${n}"`);Dt(e[n],`${t}.${n}`)}}function Ot(e,t,n=`$`){if(e===void 0){if(t.optional)return;throw Error(`${n} is required`)}switch(t.type){case`string`:if(typeof e!=`string`)throw Error(`${n} must be a string`);return;case`number`:if(typeof e!=`number`||!Number.isFinite(e))throw Error(`${n} must be a finite number`);if(t.min!==void 0&&e<t.min)throw Error(`${n} must be >= ${t.min}`);if(t.max!==void 0&&e>t.max)throw Error(`${n} must be <= ${t.max}`);return;case`boolean`:if(typeof e!=`boolean`)throw Error(`${n} must be a boolean`);return;case`array`:if(!Array.isArray(e))throw Error(`${n} must be an array`);if(t.maxLength!==void 0&&e.length>t.maxLength)throw Error(`${n} exceeds its maximum length of ${t.maxLength}`);e.forEach((e,r)=>Ot(e,t.items,`${n}[${r}]`));return;case`object`:if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`${n} must be an object`);for(let t of Object.keys(e))if(Et.has(t))throw Error(`${n} contains a forbidden key "${t}"`);for(let[r,i]of Object.entries(t.fields))Ot(e[r],i,`${n}.${r}`);return}}function kt(e,t={}){let n=t.label??`inbound data`;Tt(e,t);try{return JSON.parse(e,(e,t)=>{if(Et.has(e))throw new At(e);return t})}catch(e){throw e instanceof At?Error(`${n} contains a forbidden key "${e.key}"`):Error(`${n} is not valid JSON (${e instanceof Error?e.message:String(e)})`)}}var At=class{constructor(e){this.key=e}};function jt(e,t){let n=kt(e,{label:t}),r=n?.meta;if(typeof n!=`object`||!n||Array.isArray(n)||!(`state`in n))throw Error(`${t} is not save data (expected { meta, state })`);if(typeof r!=`object`||!r||!Number.isSafeInteger(r.version)||r.version<0)throw Error(`${t} has no valid meta.version`);if(typeof r.savedAt!=`number`||!Number.isFinite(r.savedAt))throw Error(`${t} has no valid meta.savedAt`);return n}var Mt=class{constructor(){this.data=new Map}read(e){return this.data.get(e)??null}write(e,t){this.data.set(e,t)}remove(e){this.data.delete(e)}keys(){return[...this.data.keys()]}};function Nt(){return typeof localStorage>`u`?new Mt:{read:e=>localStorage.getItem(e),write:(e,t)=>localStorage.setItem(e,t),remove:e=>localStorage.removeItem(e),keys:()=>Object.keys(localStorage)}}var Pt=class{constructor(e){this.namespace=e.namespace,this.version=e.version,this.migrations=e.migrations??{},this.storage=e.storage??Nt()}key(e){return`mwg-save:${this.namespace}:${e}`}save(e,t,n){let r={meta:{version:this.version,savedAt:Date.now(),preview:n},state:t};this.storage.write(this.key(e),JSON.stringify(r))}load(e){let t=this.storage.read(this.key(e));if(!t)return null;try{let n=jt(t,`save slot "${e}"`),r=n.state;for(let e=n.meta.version;e<this.version;e++)r=(this.migrations[e]??(e=>e))(r);return{meta:{...n.meta,version:this.version},state:r}}catch{return null}}importExternal(e,t,n,r){Ct(t);let i=n(t);for(let e=0;e<this.version;e++)i=(this.migrations[e]??(e=>e))(i);let a={meta:{version:this.version,savedAt:Date.now(),preview:r},state:i};this.storage.write(this.key(e),JSON.stringify(a))}delete(e){this.storage.remove(this.key(e))}exportSlot(e,t){let n=this.storage.read(this.key(e));return n===null?null:t?vt(n,t):n}importSlot(e,t,n){Ct(t);let r=jt(n?yt(t,n):t,`SaveSystem.importSlot: payload`),i=r.state;for(let e=r.meta.version;e<this.version;e++)i=(this.migrations[e]??(e=>e))(i);let a={meta:{...r.meta,version:this.version},state:i};this.storage.write(this.key(e),JSON.stringify(a))}list(){let e=`mwg-save:${this.namespace}:`,t=[];for(let n of this.storage.keys()){if(!n.startsWith(e))continue;let r=this.storage.read(n);if(r)try{t.push({slot:n.slice(e.length),meta:jt(r,n).meta})}catch{}}return t}};function Ft(e,t=`value`){return It(e,t,new Set)}function It(e,t,n){if(typeof e==`function`||typeof e==`symbol`)return t;if(typeof e!=`object`||!e||n.has(e)||(n.add(e),Lt(e)))return null;let r=[];if(e instanceof Map)for(let[n,i]of e)r.push([`${t}.get(${JSON.stringify(n)??String(n)})`,i]);else if(e instanceof Set)for(let n of e)r.push([`${t}.item`,n]);else if(Array.isArray(e))e.forEach((e,n)=>r.push([`${t}[${n}]`,e]));else for(let[n,i]of Object.entries(e))r.push([`${t}.${n}`,i]);for(let[e,t]of r){let r=It(t,e,n);if(r)return r}return t}function Lt(e){try{return structuredClone(e),!0}catch{return!1}}function Rt(e,t){try{return structuredClone(e)}catch(n){let r=Ft(e,t)??t;throw TypeError(`${r} cannot be structured-cloned (${n instanceof Error?n.message:String(n)}). Journals, snapshots and undo checkpoints copy their contents with structuredClone, so they must hold plain data: refer to a live object (an actor, anything carrying callbacks such as a ReactionTable) by its id and resolve it inside the rule.`,{cause:n})}}var zt=class{constructor(e,t={}){this._state=Rt(e,`initial state`),this.version=t.version??1,this.migrations=t.migrations??{},this.extensions=t.extensions??new Bt}get state(){return structuredClone(this._state)}set(e){this._state=Rt(e,`state`)}update(e){let t=e(this.state);return this.set(t),this.state}snapshot(){let e=this.extensions.snapshot();return{version:this.version,state:this.state,extensions:e.extensions,extensionVersions:e.versions}}restore(e,t={}){if(!Number.isSafeInteger(e.version)||e.version<1)throw Error(`canonical state snapshot version must be a positive integer`);if(e.version>this.version)throw Error(`canonical state snapshot version ${e.version} is newer than ${this.version}`);let n=this.snapshot();try{let n=Rt(e.state,`snapshot.state`);for(let t=e.version;t<this.version;t++){let e=this.migrations[t+1];if(!e)throw Error(`missing canonical state migration to version ${t+1}`);n=e(n)}return this._state=Rt(n,`migrated state`),this.extensions.restore({extensions:e.extensions,versions:e.extensionVersions},t)}catch(e){throw this._state=structuredClone(n.state),this.extensions.restore({extensions:n.extensions,versions:n.extensionVersions},{missing:`keep`}),e}}transaction(e){let t=this.snapshot();try{return e(this)}catch(e){throw this.restore(t),e}}},Bt=class{constructor(){this.extensions=new Map}register(e){if(!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(e.id))throw Error(`invalid state extension id: ${e.id}`);if(this.extensions.has(e.id))throw Error(`state extension already registered: ${e.id}`);return this.extensions.set(e.id,{id:e.id,capture:()=>e.capture(),restore:t=>e.restore(t),version:e.version??1,migrations:e.migrations,reset:e.reset,remove:e.remove}),()=>this.extensions.delete(e.id)}snapshot(){let e={};for(let[t,n]of this.extensions)e[t]=Rt(n.capture(),`extension ${t}`);let t={};for(let[e,n]of this.extensions)t[e]=n.version??1;return{extensions:e,versions:t}}restore(e,t={}){let n=this.snapshot(),r=[];try{for(let[n,i]of this.extensions){if(!(n in e.extensions)){t.missing===`reset`?(i.reset&&i.reset(),r.push({extension:n,from:0,to:i.version??1,status:`reset`})):t.missing===`remove`&&(i.remove&&i.remove(),r.push({extension:n,from:0,to:i.version??1,status:`removed`}));continue}let a=e.versions?.[n]??1,o=i.version??1,s=Rt(e.extensions[n],`snapshot.extensions.${n}`);for(let e=a;e<o;e++){let t=i.migrations?.[e+1];if(!t)throw Error(`missing state migration for ${n} to version ${e+1}`);s=t(s)}i.restore(Rt(s,`migrated extension ${n}`)),r.push({extension:n,from:a,to:o,status:a===o?`unchanged`:`migrated`})}}catch(e){for(let[e,t]of this.extensions)e in n.extensions&&t.restore(structuredClone(n.extensions[e]));throw e}for(let e of r)t.onDiagnostic?.(e);return r}transaction(e){let t=this.snapshot();try{return e()}catch(e){throw this.restore(t),e}}},Vt=new Set([`localhost`,`127.0.0.1`,`[::1]`]);function Ht(e,t,n=!1){if(n||!/^[a-z][a-z0-9+.-]*:/i.test(e))return;let r=new URL(e);if(r.protocol!==`https:`&&r.protocol!==`wss:`&&(r.protocol!==`http:`&&r.protocol!==`ws:`||!Vt.has(r.hostname)))throw Error(`${t} url must use https: or wss: (got ${r.protocol}//${r.host}); pass allowInsecure: true to accept it`)}var Ut=class{constructor(e,t){if(!e.endpoint)throw Error(`${t} endpoint is required`);if(Ht(e.endpoint,`${t} endpoint`,e.allowInsecure),this.endpoint=e.endpoint,this.label=t,this.maxResponseBytes=e.maxResponseBytes??10485760,this.timeoutMs=e.timeoutMs??1e4,!(this.timeoutMs>0))throw Error(`${t} timeout must be positive`);if(this.fetchFn=e.fetch??globalThis.fetch,!this.fetchFn)throw Error(`fetch is unavailable; provide ${t}Options.fetch`)}async withTimeout(e){let t=new AbortController,n=setTimeout(()=>t.abort(),this.timeoutMs);try{return await e(t.signal)}finally{clearTimeout(n)}}async readText(e){let t=this.maxResponseBytes,n=Number(e.headers?.get?.(`content-length`));if(n>t)throw Error(`${this.label} response exceeds the ${t}-byte limit (${n} bytes)`);if(!e.body){let n=await e.text();return Ct(n,{maxBytes:t}),n}let r=e.body.getReader(),i=[],a=0;for(;;){let{done:e,value:n}=await r.read();if(e)break;if(a+=n.byteLength,a>t)throw await r.cancel(),Error(`${this.label} response exceeds the ${t}-byte limit`);i.push(n)}let o=new Uint8Array(a),s=0;for(let e of i)o.set(e,s),s+=e.byteLength;return new TextDecoder().decode(o)}async readJson(e,t){return kt(await this.readText(e),{maxBytes:this.maxResponseBytes,label:`${this.label} ${t}`})}},Wt=class extends Ut{constructor(e){super(e,`save sync`)}async upload(e,t){if(!e)throw Error(`save sync slot name is required`);if(!t)throw Error(`save sync payload cannot be empty`);return this.withTimeout(async n=>{let r=await this.fetchFn(this.slotUrl(e),{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({payload:t}),signal:n});if(!r.ok)throw Error(`save upload failed with HTTP ${r.status}`);return{ok:!0,status:r.status}})}async download(e){if(!e)throw Error(`save sync slot name is required`);return this.withTimeout(async t=>{let n=await this.fetchFn(this.slotUrl(e),{signal:t});if(!n.ok)throw Error(`save download failed with HTTP ${n.status}`);let r=await this.readJson(n,`download`);if(typeof r?.payload!=`string`)throw Error(`save download response missing a string payload`);return r.payload})}async list(){return this.withTimeout(async e=>{let t=await this.fetchFn(this.endpoint,{signal:e});if(!t.ok)throw Error(`save slot list failed with HTTP ${t.status}`);let n=await this.readJson(t,`slot list`);if(!Array.isArray(n?.slots)||!n.slots.every(e=>typeof e==`string`))throw Error(`save slot list response missing a string array of slots`);return n.slots})}slotUrl(e){let t=this.endpoint.includes(`?`)?`&`:`?`;return`${this.endpoint}${t}slot=${encodeURIComponent(e)}`}},Gt=1,Kt=class{constructor(e){if(this.onWelcome=new p,this.onTick=new p,this.onReject=new p,this.onDesync=new p,this.onClose=new p,this.onProtocolError=new p,this.socket=null,this._id=null,!e.url)throw Error(`lockstep client url is required`);Ht(e.url,`lockstep client`,e.allowInsecure),this.url=e.url,this.createSocket=e.create??(e=>new WebSocket(e)),this.validateInput=e.validateInput,this.maxMessageBytes=e.maxMessageBytes??1048576}get id(){return this._id}get connected(){return this.socket!==null&&this.socket.readyState===Gt}connect(){if(this.socket)throw Error(`lockstep client is already connected`);let e=this.createSocket(this.url);e.onmessage=e=>this.handleMessage(e.data),e.onclose=()=>{this.socket=null,this._id=null,this.onClose.dispatch()},this.socket=e}submitInput(e,t){if(!this.connected)return;let n=this.validateInput?.(e);if(n===!1||typeof n==`string`){this.onReject.dispatch({reason:n===!1?`input rejected by client validation`:n});return}this.socket?.send(JSON.stringify({type:`input`,payload:e,...t===void 0?{}:{checksum:t}}))}close(){this.socket?.close()}handleMessage(e){let t;try{if(typeof e!=`string`)throw Error(`lockstep message is not text`);t=Jt(kt(e,{maxBytes:this.maxMessageBytes,label:`lockstep message`}))}catch(e){this.onProtocolError.dispatch({reason:e instanceof Error?e.message:String(e)});return}if(t.type===`welcome`)this._id=t.id,this.onWelcome.dispatch({id:t.id,...t.seed===void 0?{}:{seed:t.seed},...t.initialState===void 0?{}:{initialState:t.initialState}});else if(t.type===`tick`){let e={tick:t.tick,inputs:t.inputs,...t.checksums===void 0?{}:{checksums:t.checksums}};if(this.onTick.dispatch(e),t.checksums){let e=Object.values(t.checksums);e.some(t=>t!==e[0])&&this.onDesync.dispatch({tick:t.tick,checksums:t.checksums})}}else this.onReject.dispatch({reason:t.reason??`input rejected by server`})}},qt=e=>typeof e==`object`&&!!e&&!Array.isArray(e);function Jt(e){if(!qt(e)||typeof e.type!=`string`)throw Error(`lockstep message has no type`);switch(e.type){case`welcome`:if(typeof e.id!=`string`||e.id===``)throw Error(`welcome needs a string id`);if(e.seed!==void 0&&!Number.isSafeInteger(e.seed))throw Error(`welcome seed must be an integer`);return e;case`tick`:if(!Number.isSafeInteger(e.tick)||e.tick<0)throw Error(`tick needs a non-negative integer tick`);if(!qt(e.inputs))throw Error(`tick needs an inputs object`);if(e.checksums!==void 0&&(!qt(e.checksums)||Object.values(e.checksums).some(e=>typeof e!=`number`)))throw Error(`tick checksums must map ids to numbers`);return e;case`rejected`:if(e.reason!==void 0&&typeof e.reason!=`string`)throw Error(`rejected reason must be a string`);return e;default:throw Error(`unknown lockstep message type "${e.type}"`)}}var Yt=class{constructor(e,t){this.storage=e,this.key=t}read(e){let t=this.storage.read(this.key);return t?kt(t,{label:`stored value "${this.key}"`}):e}write(e){this.storage.write(this.key,JSON.stringify(e))}remove(){this.storage.remove(this.key)}},Xt=class{constructor(e){this.store=new Yt(e.storage??Nt(),`mwg-runs:${e.namespace}`),this.limit=e.limit}readAll(){return this.store.read([])}record(e){let t=this.readAll(),n={id:`${Date.now()}-${t.length}`,endedAt:Date.now(),summary:e};return t.push(n),this.limit!==void 0&&t.length>this.limit&&t.splice(0,t.length-this.limit),this.store.write(t),n}all(){return this.readAll()}ranked(e,t=`desc`){let n=this.readAll(),r=t===`desc`?-1:1;return n.sort((t,n)=>r*(e(t.summary)-e(n.summary)))}clear(){this.store.remove()}},Zt=class{constructor(e){this.store=new Yt(e.storage??Nt(),`mwg-stats:${e.namespace}`),this.initial=e.initial,this.combine=e.combine}get(){return this.store.read(this.initial)}record(e){let t=this.combine(this.get(),e);return this.store.write(t),t}reset(){this.store.remove()}},Qt=class extends Ut{constructor(e){super(e,`telemetry`),this.consented=!1,this.maxStringLength=e.maxStringLength??256,this.maxProperties=e.maxProperties??32,this.allowed=e.allowedProperties?new Set(e.allowedProperties):null}get hasConsent(){return this.consented}setConsent(e){this.consented=e}async send(e){if(!e.name)throw Error(`telemetry event needs a name`);return this.consented?this.withTimeout(async t=>{let n=await this.fetchFn(this.endpoint,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(this.bounded(e)),signal:t});if(!n.ok)throw Error(`telemetry request failed with HTTP ${n.status}`);return{ok:!0,status:n.status}}):null}bounded(e){let t=e=>e.length>this.maxStringLength?e.slice(0,this.maxStringLength):e;if(!e.properties)return{name:t(e.name)};let n={},r=0;for(let[i,a]of Object.entries(e.properties))if(!this.allowed||this.allowed.has(i)){if(r++>=this.maxProperties)break;n[t(i)]=typeof a==`string`?t(a):a}return{name:t(e.name),properties:n}}},$t=class extends Ut{constructor(e){super(e,`news`)}async fetchItems(){return this.withTimeout(async e=>{let t=await this.fetchFn(this.endpoint,{signal:e});if(!t.ok)throw Error(`news request failed with HTTP ${t.status}`);let n=await this.readJson(t,`response`);if(!Array.isArray(n))throw Error(`news response was not an array`);return n.map((e,t)=>en(e,t))})}};function en(e,t){if(typeof e!=`object`||!e)throw Error(`news item ${t} was not an object`);let n=e;if(typeof n.id!=`string`||!n.id)throw Error(`news item ${t} is missing a string id`);if(typeof n.title!=`string`)throw Error(`news item ${t} is missing a string title`);if(typeof n.body!=`string`)throw Error(`news item ${t} is missing a string body`);return{id:n.id,title:n.title,body:n.body,publishedAt:typeof n.publishedAt==`number`?n.publishedAt:void 0}}var tn=class{constructor(e){this.store=new Yt(e.storage??Nt(),`mwg-news-seen:${e.namespace}`)}readSeen(){return new Set(this.store.read([]))}isSeen(e){return this.readSeen().has(e)}markSeen(e){let t=this.readSeen();t.add(e),this.store.write([...t])}unseen(e){let t=this.readSeen();return e.filter(e=>!t.has(e.id))}},nn=class{constructor(e,t={}){if(!e)throw Error(`a collection needs a name`);this.prefix=`mwg-db:${t.namespace??`default`}:${e}:`,this.storage=t.storage??Nt()}get size(){return this.keys().length}all(){return this.keys().map(e=>this.read(e))}get(e){let t=this.storage.read(this.prefix+e);return t===null?void 0:this.parse(t,this.prefix+e)}put(e){if(typeof e!=`object`||!e||Array.isArray(e)||typeof e.id!=`string`||e.id===``)throw Error(`a record must be an object with a string id`);this.storage.write(this.prefix+e.id,JSON.stringify(e))}remove(e){this.storage.remove(this.prefix+e)}where(e){return this.all().filter(e)}clear(){for(let e of this.keys())this.storage.remove(e)}keys(){return this.storage.keys().filter(e=>e.startsWith(this.prefix))}read(e){return this.parse(this.storage.read(e),e)}parse(e,t){return kt(e,{label:`record "${t}"`})}},rn=class{constructor(e,t){this.frame=0,this.recorded=[],this.actions=e,this.frames=t,this.onAction=e=>{this.recorded.push({frame:this.frame,action:e})},this.onFrame=()=>{this.frame++},e.add(this.onAction),t.add(this.onFrame)}get events(){return this.recorded}toJSON(){return this.recorded.map(e=>({frame:e.frame,action:e.action}))}stop(){this.actions.remove(this.onAction),this.frames.remove(this.onFrame)}},an=class{constructor(e,t,n){this.frame=0,this.index=0,this.events=e,this.dispatch=t,this.frames=n,this.onFrame=()=>this.pump(),n.add(this.onFrame)}get done(){return this.index>=this.events.length}stop(){this.frames.remove(this.onFrame)}pump(){for(;this.index<this.events.length&&this.events[this.index].frame<=this.frame;)this.dispatch(this.events[this.index].action),this.index++;this.frame++}};function on(e){return JSON.stringify(e)}function sn(e){let t=JSON.parse(e);if(!Array.isArray(t))throw Error(`a replay must be an array of {frame, action}`);return t.map(e=>{if(typeof e!=`object`||!e||!Number.isInteger(e.frame)||e.frame<0||typeof e.action!=`string`)throw Error(`a replay entry must be {frame: a non-negative integer, action: a string}`);return{frame:e.frame,action:e.action}})}var cn=class e{constructor(){this.entries=[],this.nextSequence=0}append(e,t=[]){let n={sequence:this.nextSequence,action:Rt(e,`action`),events:Rt([...t],`events`)};return this.nextSequence++,this.entries.push(n),structuredClone(n)}get size(){return this.entries.length}get all(){return structuredClone(this.entries)}mark(){return this.nextSequence}since(e){return structuredClone(this.entries.filter(t=>t.sequence>=e))}truncate(e){this.entries=this.entries.filter(t=>t.sequence<e),this.nextSequence=e}toJSON(){return this.all}replace(t){let n=e.fromJSON(t);this.entries=n.entries,this.nextSequence=n.nextSequence}static fromJSON(t){let n=new e,r=0;for(let e of t){if(!Number.isSafeInteger(e.sequence)||e.sequence!==r)throw Error(`action journal sequences must be contiguous from zero`);n.entries.push(structuredClone({sequence:e.sequence,action:e.action,events:[...e.events]})),r++}return n.nextSequence=r,n}};function ln(e){if(e.criteria)return e.criteria;if(e.counter===void 0||e.target===void 0)throw Error(`achievement "${e.id}" needs either counter/target or criteria`);return[{counter:e.counter,target:e.target}]}var un=class e{constructor(){this.definitions=new Map,this.counts=new Map,this.fresh=[]}define(e){this.definitions.set(e.id,e)}count(e){return this.counts.get(e)??0}increment(e,t=1){let n=this.count(e);this.counts.set(e,n+t);let r=[];for(let t of this.definitions.values()){let i=ln(t);i.some(t=>t.counter===e)&&(i.every(t=>t.counter===e?n>=t.target:this.count(t.counter)>=t.target)||i.every(e=>this.count(e.counter)>=e.target)&&(r.push(t.id),this.fresh.push(t.id)))}return r}unlocked(e){let t=this.definitions.get(e);if(!t)throw Error(`no such achievement: "${e}"`);return ln(t).every(e=>this.count(e.counter)>=e.target)}progress(e){let t=this.definitions.get(e);if(!t)throw Error(`no such achievement: "${e}"`);let n=ln(t);if(n.length!==1)throw Error(`achievement "${e}" has several criteria - use subProgress`);return{count:this.count(n[0].counter),target:n[0].target}}subProgress(e){let t=this.definitions.get(e);if(!t)throw Error(`no such achievement: "${e}"`);return ln(t).map(e=>{let t=this.count(e.counter);return{counter:e.counter,count:t,target:e.target,met:t>=e.target}})}drainNew(){let e=this.fresh;return this.fresh=[],e}toJSON(){return{counts:[...this.counts]}}static fromJSON(t,n){let r=new e;for(let e of t)r.define(e);for(let[e,t]of n.counts)r.counts.set(e,t);return r}},dn=class e{constructor(e=[]){this.active=new Set,this.spent=new Set,this.rules=[...e]}add(e){this.rules.push(e)}remove(e){this.rules=this.rules.filter(t=>t.id!==e),this.active.delete(e)}check(e){let t=[];for(let n of this.rules){if(n.once&&this.spent.has(n.id))continue;let r=n.when(e);r&&!this.active.has(n.id)&&(n.action(e),t.push(n.id),n.once&&this.spent.add(n.id)),r?this.active.add(n.id):this.active.delete(n.id)}return t}isActive(e){return this.active.has(e)}reset(){this.active.clear(),this.spent.clear()}toJSON(){return{active:[...this.active],spent:[...this.spent]}}static fromJSON(t,n){let r=new e(t);for(let e of n.active)r.active.add(e);for(let e of n.spent)r.spent.add(e);return r}},fn=class{constructor(e={}){let t=e.storage??Nt(),n=`mwg-session:${e.namespace??`default`}`,r=Number(t.read(n)??`0`);this.launches=(Number.isFinite(r)?r:0)+1,t.write(n,String(this.launches))}};function pn(e,t,n){return e<t?t:e>n?n:e}function mn(){return{musicVolume:1,sfxVolume:1,muted:!1,zoom:1,bindings:bn(je),custom:{}}}function hn(e){return e.muted?0:e.musicVolume}function gn(e){return e.muted?0:e.sfxVolume}var _n=class{constructor(e={}){this.storage=e.storage??Nt(),this.key=`mwg-settings:${e.namespace??`default`}`,this.value=Tn(this.storage,this.key),Re(this.value.bindings)}get current(){return{...this.value,bindings:bn(this.value.bindings),custom:{...this.value.custom}}}getCustom(e,t){return this.value.custom[e]??t}setCustom(e,t){this.value.custom[e]=t,En(this.storage,this.key,this.value)}setMusicVolume(e){this.update({musicVolume:e})}setSfxVolume(e){this.update({sfxVolume:e})}setMuted(e){this.update({muted:e})}setZoom(e){this.update({zoom:e})}setBindings(e){this.update({bindings:e})}update(e){e.musicVolume!==void 0&&(this.value.musicVolume=vn(e.musicVolume)),e.sfxVolume!==void 0&&(this.value.sfxVolume=vn(e.sfxVolume)),e.muted!==void 0&&(this.value.muted=e.muted),e.zoom!==void 0&&(this.value.zoom=yn(e.zoom)),e.bindings!==void 0&&(this.value.bindings=xn(e.bindings),Re(this.value.bindings)),e.custom!==void 0&&(this.value.custom=Cn(e.custom)),En(this.storage,this.key,this.value)}applyBindings(){Re(this.value.bindings)}reset(){this.value=mn(),Re(this.value.bindings),En(this.storage,this.key,this.value)}};function vn(e){return Number.isFinite(e)?pn(e,0,1):1}function yn(e){return Number.isFinite(e)?Math.max(.01,e):1}function bn(e){let t={};for(let[n,r]of Object.entries(e))t[n]=[...r];return t}function xn(e){if(typeof e!=`object`||!e||Array.isArray(e))return bn(je);let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r))continue;let e=r.filter(e=>typeof e==`string`);e.length>0&&(t[n]=e)}return Object.keys(t).length>0?t:bn(je)}function Sn(e){let t=typeof e;return t===`string`||t===`number`||t===`boolean`}function Cn(e){if(typeof e!=`object`||!e||Array.isArray(e))return{};let t={};for(let[n,r]of Object.entries(e))Sn(r)&&(t[n]=r);return t}function wn(e){let t=mn();if(typeof e!=`object`||!e||Array.isArray(e))return t;let n=e;return{musicVolume:typeof n.musicVolume==`number`?vn(n.musicVolume):t.musicVolume,sfxVolume:typeof n.sfxVolume==`number`?vn(n.sfxVolume):t.sfxVolume,muted:typeof n.muted==`boolean`?n.muted:t.muted,zoom:typeof n.zoom==`number`?yn(n.zoom):t.zoom,bindings:xn(n.bindings),custom:Cn(n.custom)}}function Tn(e,t){let n=e.read(t);if(!n)return mn();try{return wn(kt(n,{label:`settings`}))}catch{return mn()}}function En(e,t,n){e.write(t,JSON.stringify(n))}var Dn=class extends Ut{constructor(e){super(e,`feedback`)}async submit(e){if(!e.message?.trim())throw Error(`feedback message cannot be empty`);return this.withTimeout(async t=>{let n=await this.fetchFn(this.endpoint,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e),signal:t});if(!n.ok)throw Error(`feedback request failed with HTTP ${n.status}`);return{ok:!0,status:n.status}})}},On=class{constructor(e){this.schedule=[],this.cursor=0,this.elapsed=0,this.startedWaves=new Set,this.completed=!1,this.onSpawn=e.onSpawn,this.onWaveStart=e.onWaveStart,this.onComplete=e.onComplete,e.waves.forEach((e,t)=>{let n=e.entries.reduce((e,t)=>e+t.count,0),r=e.duration??0,i=0;for(let a of e.entries)for(let o=0;o<a.count;o++,i++){let o=n>1&&r>0?i/(n-1)*r:0;this.schedule.push({time:e.delay+o,kind:a.kind,waveIndex:t})}}),this.schedule.sort((e,t)=>e.time-t.time),this.schedule.length===0&&(this.completed=!0,this.onComplete?.())}update(e){if(!this.completed){for(this.elapsed+=e;this.cursor<this.schedule.length&&this.schedule[this.cursor].time<=this.elapsed;){let e=this.schedule[this.cursor];this.startedWaves.has(e.waveIndex)||(this.startedWaves.add(e.waveIndex),this.onWaveStart?.(e.waveIndex)),this.onSpawn(e.kind),this.cursor++}this.cursor>=this.schedule.length&&(this.completed=!0,this.onComplete?.())}}get isComplete(){return this.completed}};function kn(e,t){let n=e,r=t-(e-(e&1))/2;return{x:n,y:-n-r,z:r}}function An(e){return{x:e.x,y:e.z+(e.x-(e.x&1))/2}}var jn=[{x:1,y:-1,z:0},{x:1,y:0,z:-1},{x:0,y:1,z:-1},{x:-1,y:1,z:0},{x:-1,y:0,z:1},{x:0,y:-1,z:1}];function Mn(e,t){let n=kn(e,t);return jn.map(e=>An({x:n.x+e.x,y:n.y+e.y,z:n.z+e.z}))}function Nn(e,t){let n=kn(e.x,e.y),r=kn(t.x,t.y);return Math.max(Math.abs(n.x-r.x),Math.abs(n.y-r.y),Math.abs(n.z-r.z))}function Pn(e){let t=Math.round(e.x),n=Math.round(e.y),r=Math.round(e.z),i=Math.abs(t-e.x),a=Math.abs(n-e.y),o=Math.abs(r-e.z);return i>a&&i>o?t=-n-r:a>o?n=-t-r:r=-t-n,{x:t,y:n,z:r}}function Fn(e,t){let n=Nn(e,t);if(n===0)return[{x:e.x,y:e.y}];let r=kn(e.x,e.y),i=kn(t.x,t.y),a=[];for(let e=0;e<=n;e++){let t=e/n;a.push(An(Pn({x:r.x+(i.x-r.x)*t,y:r.y+(i.y-r.y)*t,z:r.z+(i.z-r.z)*t})))}return a}function In(e,t){let n=kn(e.x,e.y),r=[];for(let e=-t;e<=t;e++)for(let i=Math.max(-t,-e-t);i<=Math.min(t,-e+t);i++){let t=-e-i;r.push(An({x:n.x+e,y:n.y+i,z:n.z+t}))}return r}function Ln(e,t,n,r,i={}){let a=+((i.offset??`odd`)===`odd`);return(i.orientation??`flat-top`)===`pointy-top`?{x:e*n+((t&1)===a?n/2:0)+n/2,y:t*r*.75+r/2}:{x:e*n*.75+n/2,y:t*r+((e&1)===a?r/2:0)+r/2}}function Rn(e,t,n,r,i={}){let a=(i.orientation??`flat-top`)===`pointy-top`,o=a?n:n*.75,s=a?r*.75:r,c=Math.round((e-n/2)/o),l=Math.round((t-r/2)/s),u={x:c,y:l},d=1/0;for(let a=-2;a<=2;a++)for(let o=-2;o<=2;o++){let s={x:c+a,y:l+o},f=Ln(s.x,s.y,n,r,i),p=(f.x-e)**2+(f.y-t)**2;p<d&&(d=p,u=s)}return u}function zn(e,t,n,r){return n>=0&&r>=0&&n<e&&r<t}function Bn(e,t,n){return n*e+t}function Vn(e,t){return t%e}function Hn(e,t){return Math.floor(t/e)}function Un(e,t){return`${e},${t}`}function Wn(e){let t=/^(-?\d+),(-?\d+)$/.exec(e);return t?{x:Number(t[1]),y:Number(t[2])}:null}var Gn=.12,Kn=null,qn,Jn=new p;function Yn(){if(qn===void 0&&(qn=typeof matchMedia==`function`?matchMedia(`(prefers-reduced-motion: reduce)`):null,qn)){let e=()=>{Jn.dispatch(Zn())};typeof qn.addEventListener==`function`?qn.addEventListener(`change`,e):typeof qn.addListener==`function`&&qn.addListener(e)}return qn}function Xn(){return Yn()?.matches??!1}function Zn(){return Kn??Xn()}function Qn(e){Kn=e,Jn.dispatch(Zn())}function $n(e){return Yn(),Jn.add(e),()=>Jn.remove(e)}function er(e,t=`decorative`){return Zn()?t===`meaningful`?Math.min(e,Gn):0:e}var tr=[[0,-1],[1,0],[0,1],[-1,0]],nr=class e{constructor(e,t){this.width=e,this.height=t,this.volume=new Float32Array(e*t)}index(e,t){return e<0||t<0||e>=this.width||t>=this.height?-1:t*this.width+e}volumeAt(e,t){let n=this.index(e,t);return n<0?0:this.volume[n]}total(){let e=0;for(let t=0;t<this.volume.length;t++)e+=this.volume[t];return e}seed(e,t,n){let r=this.index(e,t);r>=0&&(this.volume[r]+=n)}clear(e,t){let n=this.index(e,t);n>=0&&(this.volume[n]=0)}spread(e,t=.25,n=.9){let r=new Float32Array(this.volume.length);for(let n=0;n<this.height;n++)for(let i=0;i<this.width;i++){let a=n*this.width+i,o=this.volume[a];if(o<=0)continue;let s=[];for(let[t,r]of tr){let a=i+t,o=n+r,c=this.index(a,o);c>=0&&e(a,o)&&s.push(c)}if(s.length===0)r[a]+=o;else{let e=o*t/s.length;r[a]+=o-e*s.length;for(let t of s)r[t]+=e}}let i=[];for(let e=0;e<r.length;e++){let t=r[e]*n,a=t<.001?0:t;a===0&&this.volume[e]>0&&i.push({x:e%this.width,y:Math.floor(e/this.width)}),this.volume[e]=a}return i}cellsAbove(e){let t=[];for(let n=0;n<this.height;n++)for(let r=0;r<this.width;r++){let i=this.volume[n*this.width+r];i>=e&&t.push({x:r,y:n,volume:i})}return t}toJSON(){return{width:this.width,height:this.height,volume:[...this.volume]}}static fromJSON(t){let n=new e(t.width,t.height);return n.volume.set(t.volume.slice(0,n.volume.length)),n}},rr={linear:e=>e,easeInQuad:e=>e*e,easeOutQuad:e=>e*(2-e),easeInOutQuad:e=>e<.5?2*e*e:1-(-2*e+2)**2/2,easeInCubic:e=>e*e*e,easeOutCubic:e=>1-(1-e)**3,easeInOutCubic:e=>e<.5?4*e*e*e:1-(-2*e+2)**3/2},ir=class{constructor(){this.tweens=[]}tween(e,t,n=rr.linear){let{ease:r=rr.linear,intent:i=`decorative`,alternate:a}=typeof n==`function`?{ease:n}:n,o=Zn()&&a!==void 0,s=o?a:t,c=er(e,o?`meaningful`:i);return c>0?new Promise(e=>{this.tweens.push({elapsed:0,duration:c,ease:r,apply:s,resolve:e,finishOnReduced:!o&&i===`decorative`})}):(s(1),Promise.resolve())}update(e){if(this.tweens.length!==0)for(let t of[...this.tweens]){if(t.finishOnReduced&&Zn()){this.tweens.splice(this.tweens.indexOf(t),1),t.apply(1),t.resolve();continue}t.elapsed+=e;let n=Math.min(1,t.elapsed/t.duration);t.apply(t.ease(n)),n>=1&&(this.tweens.splice(this.tweens.indexOf(t),1),t.resolve())}}get isBusy(){return this.tweens.length>0}clear(){this.tweens=[]}},ar=class{constructor(e={}){this.history=[],this.cursor=-1,this.limit=Math.max(1,e.limit??50)}push(e){this.history.length=this.cursor+1,this.history.push(e),this.history.length>this.limit&&this.history.shift(),this.cursor=this.history.length-1}get canUndo(){return this.cursor>0}get canRedo(){return this.cursor<this.history.length-1}undo(){return this.canUndo?(this.cursor--,this.history[this.cursor]):null}redo(){return this.canRedo?(this.cursor++,this.history[this.cursor]):null}get current(){return this.cursor>=0?this.history[this.cursor]:null}clear(){this.history=[],this.cursor=-1}};function or(e,t){if(!Number.isFinite(t.maxCost)||t.maxCost<0)return new Map;let n=t.key(e),r=new Map([[n,{cell:e,cost:0}]]),i=[{cell:e,key:n,cost:0}];for(;i.length>0;){let e=cr(i),n=r.get(e.key);if(n&&e.cost===n.cost&&!t.stop?.(e.cell,e.cost))for(let n of t.neighbors(e.cell)){let a=t.cost(e.cell,n);if(!Number.isFinite(a)||a<0)continue;let o=e.cost+a;if(o>t.maxCost||t.canEnter&&!t.canEnter(n,e.cell,o))continue;let s=t.key(n);if(o>=(r.get(s)?.cost??1/0))continue;let c={cell:n,key:s,cost:o};r.set(s,c),sr(i,c)}}return r}function sr(e,t){e.push(t);let n=e.length-1;for(;n>0;){let t=Math.floor((n-1)/2);if(e[t].cost<=e[n].cost)break;[e[t],e[n]]=[e[n],e[t]],n=t}}function cr(e){let t=e[0],n=e.pop();if(!t||!n||e.length===0)return t;e[0]=n;let r=0;for(;;){let t=r*2+1,n=t+1,i=r;if(t<e.length&&e[t].cost<e[i].cost&&(i=t),n<e.length&&e[n].cost<e[i].cost&&(i=n),i===r)break;[e[r],e[i]]=[e[i],e[r]],r=i}return t}var lr=class{constructor(){this.changed=new p,this.tasks=[],this.progress=new Map,this.status_=`idle`,this.current_=null,this.error_=null,this.cancelled=!1}add(e){if(!e.id)throw Error(`load task needs an id`);if(this.tasks.some(t=>t.id===e.id))throw Error(`duplicate load task "${e.id}"`);if(e.weight!==void 0&&!(e.weight>0))throw Error(`load task weight must be positive`);if(this.status_===`loading`)throw Error(`cannot add a task while loading`);return this.tasks.push(e),this.progress.set(e.id,0),this.emit(),this}get snapshot(){let e=this.tasks.reduce((e,t)=>e+(t.weight??1),0),t=this.tasks.reduce((e,t)=>e+(t.weight??1)*(this.progress.get(t.id)??0),0);return{status:this.status_,completed:t,total:e,current:this.current_,error:this.error_}}async start(){if(this.status_===`loading`)throw Error(`load queue is already running`);this.status_=`loading`,this.cancelled=!1,this.error_=null,this.emit();try{for(let e of this.tasks){if(this.cancelled)break;this.current_=e.id,this.emit();let t=this;await e.run({get cancelled(){return t.cancelled},report:t=>this.report(e.id,t)}),this.cancelled||this.report(e.id,1)}this.current_=null,this.status_=this.cancelled?`cancelled`:`ready`,this.emit()}catch(e){throw this.current_=null,this.error_=e,this.status_=`failed`,this.emit(),e}}cancel(){this.status_===`loading`&&(this.cancelled=!0)}retry(){if(this.status_===`loading`)throw Error(`cannot retry while loading`);this.status_=`idle`,this.current_=null,this.error_=null,this.cancelled=!1;for(let e of this.tasks)this.progress.set(e.id,0);this.emit()}report(e,t){if(!Number.isFinite(t))throw Error(`load progress must be finite`);this.progress.set(e,Math.max(0,Math.min(1,t))),this.emit()}emit(){this.changed.dispatch(this.snapshot)}},ur=class{constructor(){this.entities=new Map,this.ids=new Map,this.sequence=0}add(e,t){let n=this.ids.get(e);if(n!==void 0){if(t!==void 0&&t!==n)throw Error(`entity already has id ${n}`);return n}let r=t;if(r!==void 0){if(r.length===0)throw Error(`entity id must not be empty`);if(this.entities.has(r))throw Error(`entity id already exists: ${r}`)}else do r=`e${this.sequence++}`;while(this.entities.has(r));return this.entities.set(r,e),this.ids.set(e,r),r}get(e){return this.entities.get(e)}idOf(e){return this.ids.get(e)}has(e){return this.entities.has(e)}remove(e){let t=this.entities.get(e);return t!==void 0&&(this.entities.delete(e),this.ids.delete(t),!0)}get size(){return this.entities.size}},dr=class{constructor(e){this.queue=[],this.busy=!1,this.remaining=0,this.play=e.play}enqueue(e){this.queue.push(...e),this.busy||this.advance()}update(e){this.busy&&(this.remaining-=e,this.remaining<=0&&this.advance())}get isBusy(){return this.busy}clear(){this.queue=[],this.busy=!1,this.remaining=0}advance(){let e=this.queue.shift();if(e===void 0){this.busy=!1,this.remaining=0;return}this.busy=!0;let t=this.play(e)||0;t>0?this.remaining=t:this.advance()}},fr=2166136261,pr=16777619;function mr(e,t=!1){if(e==null)return`null`;switch(typeof e){case`boolean`:return e?`true`:`false`;case`number`:return Number.isFinite(e)?String(e):`null`;case`string`:return JSON.stringify(e);case`bigint`:return JSON.stringify(e.toString());case`function`:case`symbol`:return t?`null`:`undefined`}return Array.isArray(e)?`[${e.map(e=>mr(e,!0)).join(`,`)}]`:`{${Object.entries(e).filter(([,e])=>e!==void 0&&typeof e!=`function`&&typeof e!=`symbol`).sort(([e],[t])=>e<t?-1:+(e>t)).map(([e,t])=>`${JSON.stringify(e)}:${mr(t)}`).join(`,`)}}`}function hr(e){let t=mr(e),n=fr;for(let e=0;e<t.length;e++)n^=t.charCodeAt(e),n=Math.imul(n,pr)>>>0;return n>>>0}var gr=class{constructor(){this.reference=new Map,this.desyncTick=null}observe(e,t){let n=this.reference.get(e);return n===void 0?(this.reference.set(e,t),!0):n===t||(this.desyncTick===null&&(this.desyncTick=e),!1)}get divergent(){return this.desyncTick!==null}get atTick(){return this.desyncTick}reset(){this.reference.clear(),this.desyncTick=null}};function _r(e,t={}){let n=br(e);if(n.length===0)return[];let[r,...i]=n,a=t.listDelimiter??`;`,o=t.mapDelimiter??`=`;return i.map((e,n)=>{let i={};return r.forEach((r,s)=>{let c=e[s]??``;c!==``&&(i[r]=vr(c,t.columns?.[r]??`string`,r,n,a,o))}),i})}function vr(e,t,n,r,i,a){return yr(e,t,{column:n,rowIndex:r,listDelimiter:i,mapDelimiter:a,error:()=>t===`number`?`CSV row ${r+1}, column "${n}": "${e}" is not a number`:t===`boolean`?`CSV row ${r+1}, column "${n}": "${e}" is not "true" or "false"`:t===`map`?`CSV row ${r+1}, column "${n}": "${e.split(i).map(e=>e.trim()).find(e=>e&&!e.includes(a))??e}" has no "${a}" to split a key from its value`:`CSV row ${r+1}, column "${n}": "${e}" is invalid`})}function yr(e,t,n={}){let r=n.column??`value`,i=n.listDelimiter??`;`,a=n.mapDelimiter??`=`,o=e=>{throw Error(n.error?.(e)??e)};switch(t){case`string`:return e;case`number`:{let t=Number(e);return Number.isFinite(t)||o(`${r} must be a number`),t}case`boolean`:{let t=e.toLowerCase();if(t===`true`)return!0;if(t===`false`)return!1;if(n.acceptYesNo&&t===`yes`)return!0;if(n.acceptYesNo&&t===`no`)return!1;o(`${r} must be true, false${n.acceptYesNo?`, yes, or no`:``}`)}case`list`:return e.split(i).map(e=>e.trim()).filter(e=>e.length>0);case`map`:{let t={};for(let n of e.split(i).map(e=>e.trim()).filter(e=>e.length>0)){let e=n.indexOf(a);e===-1&&o(`${r} map entry must contain ${a}`),t[n.slice(0,e).trim()]=n.slice(e+a.length).trim()}return t}}}function br(e){let t=[],n=[],r=``,i=!1,a=0;for(;a<e.length;){let o=e[a];if(i){if(o===`"`){if(e[a+1]===`"`){r+=`"`,a+=2;continue}i=!1,a++;continue}r+=o,a++;continue}if(o===`"`){i=!0,a++;continue}if(o===`,`){n.push(r),r=``,a++;continue}if(o===`\r`){a++;continue}if(o===`
|
|
1
|
+
var mw_games=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(e){throw n=[e],e}},c=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),l=(e,t)=>{let r={};for(var i in e)n(r,i,{get:e[i],enumerable:!0});return t||n(r,Symbol.toStringTag,{value:`Module`}),r},u=(e,t,a,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=i(t),l=0,u=c.length,d;l<u;l++)d=c[l],!o.call(e,d)&&d!==a&&n(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(s=r(t,d))||s.enumerable});return e},d=(e,r,i)=>(i=e==null?{}:t(a(e)),u(r||!e||!e.__esModule||!o.call(e,`default`)?n(i,`default`,{value:e,enumerable:!0}):i,e)),f=`0.17.1`,p=class{constructor(e=!1){this.listeners=[],this.stackMode=e}add(e){this.listeners.includes(e)||(this.stackMode?this.listeners.unshift(e):this.listeners.push(e))}remove(e){let t=this.listeners.indexOf(e);t!==-1&&this.listeners.splice(t,1)}removeAll(){this.listeners.length=0}get size(){return this.listeners.length}dispatch(e){let t=this.listeners.slice();for(let n of t)if(this.listeners.includes(n)&&n(e)===!0)return!0;return!1}},m=class{constructor(){this.onDestroy=new p,this.destroyed=!1}update(e){}resize(e,t){}onSuspend(){}onResume(e){}destroy(){this.destroyed||(this.destroyed=!0,this.onDestroy.dispatch(),this.onDestroy.removeAll(),this.teardown())}teardown(){}get isDestroyed(){return this.destroyed}},h=class{constructor(){this.scenes=[]}get current(){return this.scenes.length===0?null:this.scenes[this.scenes.length-1]}get depth(){return this.scenes.length}replace(e){for(let e of this.scenes)e.destroy();this.scenes=[e],e.create()}push(e){this.current?.onSuspend(),this.scenes.push(e),e.create()}pop(e){if(this.scenes.length<=1)throw Error(`cannot pop the last scene off the stack - switchScene somewhere instead`);this.scenes.pop()?.destroy(),this.current?.onResume(e)}update(e){this.current?.update(e)}resize(e,t){for(let n of this.scenes)n.resize(e,t)}destroy(){for(let e of this.scenes)e.destroy();this.scenes=[]}},g=class{constructor(){this.items=new Map}register(e,t){if(this.items.has(e))throw Error(`"${e}" is already registered`);this.items.set(e,t)}get(e){let t=this.items.get(e);if(t===void 0)throw Error(`no registration named "${e}"`);return t}has(e){return this.items.has(e)}list(){return[...this.items.keys()]}},_=class{constructor(){this.order=[],this.registry=new g}add(e,t){this.registry.register(e.name,e),this.order.push(e),e.create?.(t)}has(e){return this.registry.has(e)}get(e){return this.registry.get(e)}update(e,t){for(let n of this.order)n.update?.(e,t)}resize(e,t,n){for(let r of this.order)r.resize?.(e,t,n)}onSuspend(e){for(let t of this.order)t.onSuspend?.(e)}onResume(e,t){for(let n of this.order)n.onResume?.(e,t)}destroy(e){for(let t=this.order.length-1;t>=0;t--)this.order[t].destroy?.(e);this.order=[],this.registry=new g}},v={debug:0,info:1,warn:2,error:3},y=class{constructor(e,t={}){if(!e)throw Error(`a logger needs a category`);this.category=e,this.level=t.level??`debug`,this.sink=t.sink??b}setLevel(e){this.level=e}debug(e,t){this.write(`debug`,e,t)}info(e,t){this.write(`info`,e,t)}warn(e,t){this.write(`warn`,e,t)}error(e,t){this.write(`error`,e,t)}write(e,t,n){v[e]<v[this.level]||this.sink({level:e,category:this.category,message:t,data:n,time:Date.now()})}};function b(e){let t=`[${e.category}] ${e.message}`;e.level===`debug`?console.debug(t,e.data??``):e.level===`info`?console.info(t,e.data??``):e.level===`warn`?console.warn(t,e.data??``):console.error(t,e.data??``)}var x=class{constructor(){this.hooks=[]}on(e,t,n){this.hooks.push({event:e,handler:t,source:n})}off(e){this.hooks=this.hooks.filter(t=>t.handler!==e)}offSource(e){this.hooks=this.hooks.filter(t=>t.source!==e)}emit(e,...t){for(let n of[...this.hooks])n.event===e&&n.handler(...t)}get size(){return this.hooks.length}clear(){this.hooks=[]}},S=l({Generator:()=>w,MersenneTwister:()=>ge,RandomStreams:()=>ve,chance:()=>se,element:()=>ce,float:()=>D,int:()=>O,normalRange:()=>oe,pop:()=>ne,push:()=>te,range:()=>ae,reset:()=>ie,shuffle:()=>ue,weighted:()=>le,weightedKey:()=>k,withSeed:()=>re});function C(e){let t=e>>>0;return()=>{t=t+2654435769>>>0;let e=t;return e=Math.imul(e^e>>>16,569420461),e=Math.imul(e^e>>>15,1935289751),(e^e>>>15)>>>0}}var w=class{constructor(e){this.s0=0,this.s1=0,this.s2=0,this.s3=0,this.seed=e===void 0?Math.random()*4294967296>>>0:e>>>0;let t=C(this.seed);this.s0=t(),this.s1=t(),this.s2=t(),this.s3=t(),(this.s0|this.s1|this.s2|this.s3)===0&&(this.s0=1)}nextUint32(){let e=Math.imul(ee(Math.imul(this.s1,5),7),9)>>>0>>>0,t=this.s1<<9>>>0;return this.s2^=this.s0,this.s3^=this.s1,this.s1^=this.s2,this.s0^=this.s3,this.s2^=t,this.s3=ee(this.s3,11),e}float(){return this.nextUint32()/4294967296}int(e){if(e<=0)return 0;let t=4294967296-4294967296%e,n=this.nextUint32();for(;n>=t;)n=this.nextUint32();return n%e}getState(){return[this.s0,this.s1,this.s2,this.s3]}setState(e){[this.s0,this.s1,this.s2,this.s3]=e}};function ee(e,t){return(e<<t|e>>>32-t)>>>0}var T=[new w],E=()=>T[T.length-1];function te(e){let t=new w(e);return T.push(t),t}function ne(){if(T.length===1)throw Error(`the base random generator cannot be popped`);T.pop()}function re(e,t){te(e);try{return t()}finally{ne()}}function ie(){T.length=0,T.push(new w)}function D(e,t){return e===void 0?E().float():t===void 0?E().float()*e:e+E().float()*(t-e)}function O(e,t){return t===void 0?E().int(e):e+E().int(t-e)}function ae(e,t){return e+E().int(t-e+1)}function oe(e,t){return e+Math.floor((E().float()+E().float())*(t-e+1)/2)}function se(e){return E().float()<e}function ce(e){return e.length>0?e[E().int(e.length)]:null}function le(e){let t=0;for(let n of e)t+=n;if(t<=0)return null;let n=E().float()*t;for(let t=0;t<e.length;t++)if(n-=e[t],n<0)return t;return e.length-1}function k(e){let t=[...e.keys()],n=le(t.map(t=>e.get(t)??0));return n===null?null:t[n]}function ue(e){for(let t=e.length-1;t>0;t--){let n=E().int(t+1);[e[t],e[n]]=[e[n],e[t]]}return e}var de=624,fe=397,pe=2567483615,me=2147483648,he=2147483647,ge=class{constructor(e=5489){this.state=new Uint32Array(de),this.index=de,this.seedValue=5489,this.produced=0,this.seed(e)}seed(e){this.seedValue=e>>>0,this.state[0]=this.seedValue;for(let e=1;e<de;e++){let t=this.state[e-1]^this.state[e-1]>>>30;this.state[e]=Math.imul(1812433253,t)+e>>>0}this.index=de,this.produced=0}generate(){for(let e=0;e<de;e++){let t=this.state[e]&me|this.state[(e+1)%de]&he,n=this.state[(e+fe)%de]^t>>>1;t&1&&(n^=pe),this.state[e]=n>>>0}this.index=0}nextUint32(){this.index>=de&&this.generate();let e=this.state[this.index++];return e^=e>>>11,e^=e<<7&2636928640,e^=e<<15&4022730752,e^=e>>>18,this.produced++,e>>>0}float(){return this.nextUint32()/4294967296}int(e){if(e<=0)return 0;let t=4294967296-4294967296%e,n=this.nextUint32();for(;n>=t;)n=this.nextUint32();return n%e}discard(e){for(let t=0;t<e;t++)this.nextUint32()}get discardCount(){return this.produced}getState(){return{seed:this.seedValue,state:[...this.state],index:this.index,discard:this.produced}}setState(e){this.seedValue=e.seed>>>0;for(let t=0;t<de;t++)this.state[t]=(e.state[t]??0)>>>0;this.index=e.index,this.produced=e.discard}};function _e(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619)>>>0;return t>>>0}var ve=class{constructor(e=0){this.streams=new Map,this.baseSeed=e>>>0}stream(e){let t=this.streams.get(e);if(!t){let n=(this.baseSeed^_e(e))>>>0;t={seed:n,engine:new ge(n)},this.streams.set(e,t)}return t.engine}seedOf(e){return this.streams.get(e)?.seed}reseed(e){this.baseSeed=e>>>0,this.streams.clear()}names(){return[...this.streams.keys()]}getState(){let e={};for(let[t,n]of this.streams)e[t]=n.engine.getState();return e}setState(e){for(let[t,n]of Object.entries(e)){let e=new ge(n.seed);e.setState(n),this.streams.set(t,{seed:n.seed,engine:e})}}},ye=l({DEFAULT_BINDINGS:()=>je,actionsForKey:()=>Pe,attach:()=>ht,attachSwipe:()=>mt,bind:()=>Me,bindAxis:()=>at,bindButton:()=>it,bindTouch:()=>lt,detach:()=>gt,dispatchComposition:()=>Ee,dispatchText:()=>Te,endFrame:()=>Ke,exportBindings:()=>Le,gamepadAxisCode:()=>rt,gamepadButtonCode:()=>nt,importBindings:()=>Re,isDown:()=>Ue,justPressed:()=>We,justReleased:()=>Ge,keysFor:()=>Ie,onAction:()=>Se,onComposition:()=>we,onKey:()=>M,onText:()=>Ce,onWheel:()=>De,pollGamepads:()=>ot,pressTouch:()=>ut,releaseTouch:()=>dt,resetBindings:()=>ze,rumble:()=>st,textFromKey:()=>N,touchCode:()=>ct,unbind:()=>Fe,wheelActionFor:()=>Oe}),be=new Map,A=new Set,j=new Set,xe=new Set,Se=new p(!0),M=new p(!0),Ce=new p(!0),we=new p(!0);function N(e){return e.isComposing||e.ctrlKey||e.metaKey||e.altKey?null:e.key.length===1?e.key:null}function Te(e){e.length>0&&Ce.dispatch(e)}function Ee(e){we.dispatch({phase:e.phase,text:e.text})}var De=new p(!0);function Oe(e){return e.ctrlKey||e.metaKey?`zoom`:e.shiftKey?`scrollHorizontal`:`scroll`}function ke(e){let t=Oe(e);t===`zoom`&&e.preventDefault();let n=t===`scrollHorizontal`&&e.deltaX!==0?e.deltaX:e.deltaY;De.dispatch({action:t,delta:n})}var Ae=!1,je={up:[`ArrowUp`,`KeyW`,`Numpad8`],down:[`ArrowDown`,`KeyS`,`Numpad2`],left:[`ArrowLeft`,`KeyA`,`Numpad4`],right:[`ArrowRight`,`KeyD`,`Numpad6`],upLeft:[`Numpad7`],upRight:[`Numpad9`],downLeft:[`Numpad1`],downRight:[`Numpad3`],wait:[`Numpad5`,`Period`],confirm:[`Enter`,`Space`,`NumpadEnter`],cancel:[`Escape`,`Backspace`],menu:[`KeyI`,`Tab`]};function Me(e,t){be.set(e,new Set(t))}function Ne(e,t){let n=be.get(e)??new Set;for(let e of t)n.add(e);be.set(e,n)}function Pe(e){return Be(e)}function Fe(e){be.delete(e)}function Ie(e){return[...be.get(e)??[]]}function Le(){let e={};for(let[t,n]of be)e[t]=[...n];return e}function Re(e){be.clear();for(let[t,n]of Object.entries(e))Me(t,n)}function ze(){Re(je)}ze();function Be(e){let t=[];for(let[n,r]of be)r.has(e)&&t.push(n);return t}function Ve(e){if(!A.has(e)){A.add(e);for(let t of Be(e))j.add(t),Se.dispatch(t)}}function He(e){if(A.has(e)){A.delete(e);for(let t of Be(e))xe.add(t)}}function Ue(e){let t=be.get(e);if(!t)return!1;for(let e of t)if(A.has(e))return!0;return!1}function We(e){return j.has(e)}function Ge(e){return xe.has(e)}function Ke(){j.clear(),xe.clear()}function qe(e){let t=N(e);t!==null&&Te(t)}function Je(e){if(e.repeat){M.dispatch(e),qe(e);return}Ve(e.code),M.dispatch(e),qe(e)}function Ye(e){He(e.code)}function Xe(e){Ee({phase:`start`,text:e.data??``})}function Ze(e){Ee({phase:`update`,text:e.data??``})}function Qe(e){Ee({phase:`end`,text:e.data??``})}function $e(){A.clear(),j.clear(),xe.clear()}var et=.5,tt=new Set;function nt(e,t){return`Gamepad${e}Button${t}`}function rt(e,t,n){return`Gamepad${e}Axis${t}${n>0?`+`:`-`}`}function it(e,t,n){Ne(e,n.map(e=>nt(t,e)))}function at(e,t,n,r){Ne(e,[rt(t,n,r)])}function ot(e=typeof navigator?.getGamepads==`function`?navigator.getGamepads():[]){tt.clear();for(let t of e)if(t){for(let e=0;e<t.buttons.length;e++)t.buttons[e].pressed&&tt.add(nt(t.index,e));for(let e=0;e<t.axes.length;e++){let n=t.axes[e];n>=et?tt.add(rt(t.index,e,1)):n<=-.5&&tt.add(rt(t.index,e,-1))}}for(let e of tt)Ve(e);for(let e of A)!tt.has(e)&&e.startsWith(`Gamepad`)&&He(e)}function st(e,t,n=typeof navigator?.getGamepads==`function`?navigator.getGamepads():[]){(n[e]?.vibrationActuator)?.playEffect(`dual-rumble`,{duration:t.duration,weakMagnitude:t.weakMagnitude??1,strongMagnitude:t.strongMagnitude??1})}function ct(e){return`Touch:${e}`}function lt(e,t=e){Ne(e,[ct(t)])}function ut(e){Ve(ct(e))}function dt(e){He(ct(e))}var ft={up:`up`,down:`down`,left:`left`,right:`right`,upLeft:`upLeft`,upRight:`upRight`,downLeft:`downLeft`,downRight:`downRight`},pt=[`right`,`downRight`,`down`,`downLeft`,`left`,`upLeft`,`up`,`upRight`];function mt(e,t={}){let n={...ft,...t.actions},r=t.minDistance??24;for(let e of[...pt,`tap`]){let t=n[e];t&<(t,`swipe:${e}`)}let i=!1,a=-1,o=0,s=0;function c(e){ut(`swipe:${e}`),dt(`swipe:${e}`)}function l(e){i=!0,a=e.pointerId,o=e.clientX,s=e.clientY}function u(e){if(!i||e.pointerId!==a)return;i=!1;let t=e.clientX-o,l=e.clientY-s;if(Math.hypot(t,l)<r){n.tap&&c(`tap`);return}let u=pt[(Math.round(Math.atan2(l,t)/(Math.PI/4))%8+8)%8];n[u]&&c(u)}return e.addEventListener(`pointerdown`,l),e.addEventListener(`pointerup`,u),e.addEventListener(`pointercancel`,u),()=>{e.removeEventListener(`pointerdown`,l),e.removeEventListener(`pointerup`,u),e.removeEventListener(`pointercancel`,u)}}function ht(e=window){Ae||(Ae=!0,e.addEventListener(`keydown`,Je),e.addEventListener(`keyup`,Ye),e.addEventListener(`compositionstart`,Xe),e.addEventListener(`compositionupdate`,Ze),e.addEventListener(`compositionend`,Qe),window.addEventListener(`blur`,$e),e.addEventListener(`wheel`,ke,{passive:!1}))}function gt(e=window){Ae&&(Ae=!1,e.removeEventListener(`keydown`,Je),e.removeEventListener(`keyup`,Ye),e.removeEventListener(`compositionstart`,Xe),e.removeEventListener(`compositionupdate`,Ze),e.removeEventListener(`compositionend`,Qe),e.removeEventListener(`wheel`,ke),window.removeEventListener(`blur`,$e),$e())}var _t=class{constructor(e,t={}){if(!e)throw Error(`a player needs a non-empty id`);this.id=e,this.padIndex=t.padIndex}scoped(e){return`${this.id}:${e}`}bind(e,t){Me(this.scoped(e),t)}bindButton(e,t){if(this.padIndex===void 0)throw Error(`player "${this.id}" has no padIndex to bind a gamepad button to`);it(this.scoped(e),this.padIndex,t)}bindAxis(e,t,n){if(this.padIndex===void 0)throw Error(`player "${this.id}" has no padIndex to bind a gamepad axis to`);at(this.scoped(e),this.padIndex,t,n)}bindTouch(e,t=e){lt(this.scoped(e),`${this.id}:${t}`)}pressTouch(e){ut(`${this.id}:${e}`)}releaseTouch(e){dt(`${this.id}:${e}`)}isDown(e){return Ue(this.scoped(e))}justPressed(e){return We(this.scoped(e))}justReleased(e){return Ge(this.scoped(e))}keysFor(e){return Ie(this.scoped(e))}};function vt(e,t){if(!t)throw Error(`scramble needs a non-empty key`);let n=new TextEncoder().encode(e),r=new TextEncoder().encode(t),i=new Uint8Array(n.length);for(let e=0;e<n.length;e++)i[e]=n[e]^r[e%r.length];return bt(i)}function yt(e,t){if(!t)throw Error(`scramble needs a non-empty key`);let n=xt(e),r=new TextEncoder().encode(t),i=new Uint8Array(n.length);for(let e=0;e<n.length;e++)i[e]=n[e]^r[e%r.length];return new TextDecoder(`utf-8`,{fatal:!0}).decode(i)}function bt(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t)}function xt(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}var St=10485760;function Ct(e,t={}){let n=t.maxBytes??St,r=typeof e==`string`?new TextEncoder().encode(e).length:e.length;if(r>n)throw Error(`inbound data exceeds the ${n}-byte limit (${r} bytes)`)}function wt(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n!==9&&n!==10&&n!==13&&(n<=31||n===127))throw Error(`inbound data contains a control character (0x${n.toString(16).padStart(2,`0`)}) at index ${t}`)}}function Tt(e,t={}){return Ct(e,t),wt(e),e}var Et=new Set([`__proto__`,`constructor`,`prototype`]);function Dt(e,t=`$`){if(Array.isArray(e)){e.forEach((e,n)=>Dt(e,`${t}[${n}]`));return}if(typeof e==`object`&&e)for(let n of Object.keys(e)){if(Et.has(n))throw Error(`${t} contains a forbidden key "${n}"`);Dt(e[n],`${t}.${n}`)}}function Ot(e,t,n=`$`){if(e===void 0){if(t.optional)return;throw Error(`${n} is required`)}switch(t.type){case`string`:if(typeof e!=`string`)throw Error(`${n} must be a string`);return;case`number`:if(typeof e!=`number`||!Number.isFinite(e))throw Error(`${n} must be a finite number`);if(t.min!==void 0&&e<t.min)throw Error(`${n} must be >= ${t.min}`);if(t.max!==void 0&&e>t.max)throw Error(`${n} must be <= ${t.max}`);return;case`boolean`:if(typeof e!=`boolean`)throw Error(`${n} must be a boolean`);return;case`array`:if(!Array.isArray(e))throw Error(`${n} must be an array`);if(t.maxLength!==void 0&&e.length>t.maxLength)throw Error(`${n} exceeds its maximum length of ${t.maxLength}`);e.forEach((e,r)=>Ot(e,t.items,`${n}[${r}]`));return;case`object`:if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`${n} must be an object`);for(let t of Object.keys(e))if(Et.has(t))throw Error(`${n} contains a forbidden key "${t}"`);for(let[r,i]of Object.entries(t.fields))Ot(e[r],i,`${n}.${r}`);return}}function kt(e,t={}){let n=t.label??`inbound data`;Tt(e,t);try{return JSON.parse(e,(e,t)=>{if(Et.has(e))throw new At(e);return t})}catch(e){throw e instanceof At?Error(`${n} contains a forbidden key "${e.key}"`):Error(`${n} is not valid JSON (${e instanceof Error?e.message:String(e)})`)}}var At=class{constructor(e){this.key=e}};function jt(e,t){let n=kt(e,{label:t}),r=n?.meta;if(typeof n!=`object`||!n||Array.isArray(n)||!(`state`in n))throw Error(`${t} is not save data (expected { meta, state })`);if(typeof r!=`object`||!r||!Number.isSafeInteger(r.version)||r.version<0)throw Error(`${t} has no valid meta.version`);if(typeof r.savedAt!=`number`||!Number.isFinite(r.savedAt))throw Error(`${t} has no valid meta.savedAt`);return n}var Mt=class{constructor(){this.data=new Map}read(e){return this.data.get(e)??null}write(e,t){this.data.set(e,t)}remove(e){this.data.delete(e)}keys(){return[...this.data.keys()]}};function Nt(){return typeof localStorage>`u`?new Mt:{read:e=>localStorage.getItem(e),write:(e,t)=>localStorage.setItem(e,t),remove:e=>localStorage.removeItem(e),keys:()=>Object.keys(localStorage)}}var Pt=class{constructor(e){this.namespace=e.namespace,this.version=e.version,this.migrations=e.migrations??{},this.storage=e.storage??Nt()}key(e){return`mwg-save:${this.namespace}:${e}`}save(e,t,n){let r={meta:{version:this.version,savedAt:Date.now(),preview:n},state:t};this.storage.write(this.key(e),JSON.stringify(r))}load(e){let t=this.storage.read(this.key(e));if(!t)return null;try{let n=jt(t,`save slot "${e}"`),r=n.state;for(let e=n.meta.version;e<this.version;e++)r=(this.migrations[e]??(e=>e))(r);return{meta:{...n.meta,version:this.version},state:r}}catch{return null}}importExternal(e,t,n,r){Ct(t);let i=n(t);for(let e=0;e<this.version;e++)i=(this.migrations[e]??(e=>e))(i);let a={meta:{version:this.version,savedAt:Date.now(),preview:r},state:i};this.storage.write(this.key(e),JSON.stringify(a))}delete(e){this.storage.remove(this.key(e))}exportSlot(e,t){let n=this.storage.read(this.key(e));return n===null?null:t?vt(n,t):n}importSlot(e,t,n){Ct(t);let r=jt(n?yt(t,n):t,`SaveSystem.importSlot: payload`),i=r.state;for(let e=r.meta.version;e<this.version;e++)i=(this.migrations[e]??(e=>e))(i);let a={meta:{...r.meta,version:this.version},state:i};this.storage.write(this.key(e),JSON.stringify(a))}list(){let e=`mwg-save:${this.namespace}:`,t=[];for(let n of this.storage.keys()){if(!n.startsWith(e))continue;let r=this.storage.read(n);if(r)try{t.push({slot:n.slice(e.length),meta:jt(r,n).meta})}catch{}}return t}};function Ft(e,t=`value`){return It(e,t,new Set)}function It(e,t,n){if(typeof e==`function`||typeof e==`symbol`)return t;if(typeof e!=`object`||!e||n.has(e)||(n.add(e),Lt(e)))return null;let r=[];if(e instanceof Map)for(let[n,i]of e)r.push([`${t}.get(${JSON.stringify(n)??String(n)})`,i]);else if(e instanceof Set)for(let n of e)r.push([`${t}.item`,n]);else if(Array.isArray(e))e.forEach((e,n)=>r.push([`${t}[${n}]`,e]));else for(let[n,i]of Object.entries(e))r.push([`${t}.${n}`,i]);for(let[e,t]of r){let r=It(t,e,n);if(r)return r}return t}function Lt(e){try{return structuredClone(e),!0}catch{return!1}}function Rt(e,t){try{return structuredClone(e)}catch(n){let r=Ft(e,t)??t;throw TypeError(`${r} cannot be structured-cloned (${n instanceof Error?n.message:String(n)}). Journals, snapshots and undo checkpoints copy their contents with structuredClone, so they must hold plain data: refer to a live object (an actor, anything carrying callbacks such as a ReactionTable) by its id and resolve it inside the rule.`,{cause:n})}}var zt=class{constructor(e,t={}){this._state=Rt(e,`initial state`),this.version=t.version??1,this.migrations=t.migrations??{},this.extensions=t.extensions??new Bt}get state(){return structuredClone(this._state)}set(e){this._state=Rt(e,`state`)}update(e){let t=e(this.state);return this.set(t),this.state}snapshot(){let e=this.extensions.snapshot();return{version:this.version,state:this.state,extensions:e.extensions,extensionVersions:e.versions}}restore(e,t={}){if(!Number.isSafeInteger(e.version)||e.version<1)throw Error(`canonical state snapshot version must be a positive integer`);if(e.version>this.version)throw Error(`canonical state snapshot version ${e.version} is newer than ${this.version}`);let n=this.snapshot();try{let n=Rt(e.state,`snapshot.state`);for(let t=e.version;t<this.version;t++){let e=this.migrations[t+1];if(!e)throw Error(`missing canonical state migration to version ${t+1}`);n=e(n)}return this._state=Rt(n,`migrated state`),this.extensions.restore({extensions:e.extensions,versions:e.extensionVersions},t)}catch(e){throw this._state=structuredClone(n.state),this.extensions.restore({extensions:n.extensions,versions:n.extensionVersions},{missing:`keep`}),e}}transaction(e){let t=this.snapshot();try{return e(this)}catch(e){throw this.restore(t),e}}},Bt=class{constructor(){this.extensions=new Map}register(e){if(!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(e.id))throw Error(`invalid state extension id: ${e.id}`);if(this.extensions.has(e.id))throw Error(`state extension already registered: ${e.id}`);return this.extensions.set(e.id,{id:e.id,capture:()=>e.capture(),restore:t=>e.restore(t),version:e.version??1,migrations:e.migrations,reset:e.reset,remove:e.remove}),()=>this.extensions.delete(e.id)}snapshot(){let e={};for(let[t,n]of this.extensions)e[t]=Rt(n.capture(),`extension ${t}`);let t={};for(let[e,n]of this.extensions)t[e]=n.version??1;return{extensions:e,versions:t}}restore(e,t={}){let n=this.snapshot(),r=[];try{for(let[n,i]of this.extensions){if(!(n in e.extensions)){t.missing===`reset`?(i.reset&&i.reset(),r.push({extension:n,from:0,to:i.version??1,status:`reset`})):t.missing===`remove`&&(i.remove&&i.remove(),r.push({extension:n,from:0,to:i.version??1,status:`removed`}));continue}let a=e.versions?.[n]??1,o=i.version??1,s=Rt(e.extensions[n],`snapshot.extensions.${n}`);for(let e=a;e<o;e++){let t=i.migrations?.[e+1];if(!t)throw Error(`missing state migration for ${n} to version ${e+1}`);s=t(s)}i.restore(Rt(s,`migrated extension ${n}`)),r.push({extension:n,from:a,to:o,status:a===o?`unchanged`:`migrated`})}}catch(e){for(let[e,t]of this.extensions)e in n.extensions&&t.restore(structuredClone(n.extensions[e]));throw e}for(let e of r)t.onDiagnostic?.(e);return r}transaction(e){let t=this.snapshot();try{return e()}catch(e){throw this.restore(t),e}}},Vt=new Set([`localhost`,`127.0.0.1`,`[::1]`]);function Ht(e,t,n=!1){if(n||!/^[a-z][a-z0-9+.-]*:/i.test(e))return;let r=new URL(e);if(r.protocol!==`https:`&&r.protocol!==`wss:`&&(r.protocol!==`http:`&&r.protocol!==`ws:`||!Vt.has(r.hostname)))throw Error(`${t} url must use https: or wss: (got ${r.protocol}//${r.host}); pass allowInsecure: true to accept it`)}var Ut=class{constructor(e,t){if(!e.endpoint)throw Error(`${t} endpoint is required`);if(Ht(e.endpoint,`${t} endpoint`,e.allowInsecure),this.endpoint=e.endpoint,this.label=t,this.maxResponseBytes=e.maxResponseBytes??10485760,this.timeoutMs=e.timeoutMs??1e4,!(this.timeoutMs>0))throw Error(`${t} timeout must be positive`);if(this.fetchFn=e.fetch??globalThis.fetch,!this.fetchFn)throw Error(`fetch is unavailable; provide ${t}Options.fetch`)}async withTimeout(e){let t=new AbortController,n=setTimeout(()=>t.abort(),this.timeoutMs);try{return await e(t.signal)}finally{clearTimeout(n)}}async readText(e){let t=this.maxResponseBytes,n=Number(e.headers?.get?.(`content-length`));if(n>t)throw Error(`${this.label} response exceeds the ${t}-byte limit (${n} bytes)`);if(!e.body){let n=await e.text();return Ct(n,{maxBytes:t}),n}let r=e.body.getReader(),i=[],a=0;for(;;){let{done:e,value:n}=await r.read();if(e)break;if(a+=n.byteLength,a>t)throw await r.cancel(),Error(`${this.label} response exceeds the ${t}-byte limit`);i.push(n)}let o=new Uint8Array(a),s=0;for(let e of i)o.set(e,s),s+=e.byteLength;return new TextDecoder().decode(o)}async readJson(e,t){return kt(await this.readText(e),{maxBytes:this.maxResponseBytes,label:`${this.label} ${t}`})}},Wt=class extends Ut{constructor(e){super(e,`save sync`)}async upload(e,t){if(!e)throw Error(`save sync slot name is required`);if(!t)throw Error(`save sync payload cannot be empty`);return this.withTimeout(async n=>{let r=await this.fetchFn(this.slotUrl(e),{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({payload:t}),signal:n});if(!r.ok)throw Error(`save upload failed with HTTP ${r.status}`);return{ok:!0,status:r.status}})}async download(e){if(!e)throw Error(`save sync slot name is required`);return this.withTimeout(async t=>{let n=await this.fetchFn(this.slotUrl(e),{signal:t});if(!n.ok)throw Error(`save download failed with HTTP ${n.status}`);let r=await this.readJson(n,`download`);if(typeof r?.payload!=`string`)throw Error(`save download response missing a string payload`);return r.payload})}async list(){return this.withTimeout(async e=>{let t=await this.fetchFn(this.endpoint,{signal:e});if(!t.ok)throw Error(`save slot list failed with HTTP ${t.status}`);let n=await this.readJson(t,`slot list`);if(!Array.isArray(n?.slots)||!n.slots.every(e=>typeof e==`string`))throw Error(`save slot list response missing a string array of slots`);return n.slots})}slotUrl(e){let t=this.endpoint.includes(`?`)?`&`:`?`;return`${this.endpoint}${t}slot=${encodeURIComponent(e)}`}},Gt=1,Kt=class{constructor(e){if(this.onWelcome=new p,this.onTick=new p,this.onReject=new p,this.onDesync=new p,this.onClose=new p,this.onProtocolError=new p,this.socket=null,this._id=null,!e.url)throw Error(`lockstep client url is required`);Ht(e.url,`lockstep client`,e.allowInsecure),this.url=e.url,this.createSocket=e.create??(e=>new WebSocket(e)),this.validateInput=e.validateInput,this.maxMessageBytes=e.maxMessageBytes??1048576}get id(){return this._id}get connected(){return this.socket!==null&&this.socket.readyState===Gt}connect(){if(this.socket)throw Error(`lockstep client is already connected`);let e=this.createSocket(this.url);e.onmessage=e=>this.handleMessage(e.data),e.onclose=()=>{this.socket=null,this._id=null,this.onClose.dispatch()},this.socket=e}submitInput(e,t){if(!this.connected)return;let n=this.validateInput?.(e);if(n===!1||typeof n==`string`){this.onReject.dispatch({reason:n===!1?`input rejected by client validation`:n});return}this.socket?.send(JSON.stringify({type:`input`,payload:e,...t===void 0?{}:{checksum:t}}))}close(){this.socket?.close()}handleMessage(e){let t;try{if(typeof e!=`string`)throw Error(`lockstep message is not text`);t=Jt(kt(e,{maxBytes:this.maxMessageBytes,label:`lockstep message`}))}catch(e){this.onProtocolError.dispatch({reason:e instanceof Error?e.message:String(e)});return}if(t.type===`welcome`)this._id=t.id,this.onWelcome.dispatch({id:t.id,...t.seed===void 0?{}:{seed:t.seed},...t.initialState===void 0?{}:{initialState:t.initialState}});else if(t.type===`tick`){let e={tick:t.tick,inputs:t.inputs,...t.checksums===void 0?{}:{checksums:t.checksums}};if(this.onTick.dispatch(e),t.checksums){let e=Object.values(t.checksums);e.some(t=>t!==e[0])&&this.onDesync.dispatch({tick:t.tick,checksums:t.checksums})}}else this.onReject.dispatch({reason:t.reason??`input rejected by server`})}},qt=e=>typeof e==`object`&&!!e&&!Array.isArray(e);function Jt(e){if(!qt(e)||typeof e.type!=`string`)throw Error(`lockstep message has no type`);switch(e.type){case`welcome`:if(typeof e.id!=`string`||e.id===``)throw Error(`welcome needs a string id`);if(e.seed!==void 0&&!Number.isSafeInteger(e.seed))throw Error(`welcome seed must be an integer`);return e;case`tick`:if(!Number.isSafeInteger(e.tick)||e.tick<0)throw Error(`tick needs a non-negative integer tick`);if(!qt(e.inputs))throw Error(`tick needs an inputs object`);if(e.checksums!==void 0&&(!qt(e.checksums)||Object.values(e.checksums).some(e=>typeof e!=`number`)))throw Error(`tick checksums must map ids to numbers`);return e;case`rejected`:if(e.reason!==void 0&&typeof e.reason!=`string`)throw Error(`rejected reason must be a string`);return e;default:throw Error(`unknown lockstep message type "${e.type}"`)}}var Yt=class{constructor(e,t){this.storage=e,this.key=t}read(e){let t=this.storage.read(this.key);return t?kt(t,{label:`stored value "${this.key}"`}):e}write(e){this.storage.write(this.key,JSON.stringify(e))}remove(){this.storage.remove(this.key)}},Xt=class{constructor(e){this.store=new Yt(e.storage??Nt(),`mwg-runs:${e.namespace}`),this.limit=e.limit}readAll(){return this.store.read([])}record(e){let t=this.readAll(),n={id:`${Date.now()}-${t.length}`,endedAt:Date.now(),summary:e};return t.push(n),this.limit!==void 0&&t.length>this.limit&&t.splice(0,t.length-this.limit),this.store.write(t),n}all(){return this.readAll()}ranked(e,t=`desc`){let n=this.readAll(),r=t===`desc`?-1:1;return n.sort((t,n)=>r*(e(t.summary)-e(n.summary)))}clear(){this.store.remove()}},Zt=class{constructor(e){this.store=new Yt(e.storage??Nt(),`mwg-stats:${e.namespace}`),this.initial=e.initial,this.combine=e.combine}get(){return this.store.read(this.initial)}record(e){let t=this.combine(this.get(),e);return this.store.write(t),t}reset(){this.store.remove()}},Qt=class extends Ut{constructor(e){super(e,`telemetry`),this.consented=!1,this.maxStringLength=e.maxStringLength??256,this.maxProperties=e.maxProperties??32,this.allowed=e.allowedProperties?new Set(e.allowedProperties):null}get hasConsent(){return this.consented}setConsent(e){this.consented=e}async send(e){if(!e.name)throw Error(`telemetry event needs a name`);return this.consented?this.withTimeout(async t=>{let n=await this.fetchFn(this.endpoint,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(this.bounded(e)),signal:t});if(!n.ok)throw Error(`telemetry request failed with HTTP ${n.status}`);return{ok:!0,status:n.status}}):null}bounded(e){let t=e=>e.length>this.maxStringLength?e.slice(0,this.maxStringLength):e;if(!e.properties)return{name:t(e.name)};let n={},r=0;for(let[i,a]of Object.entries(e.properties))if(!this.allowed||this.allowed.has(i)){if(r++>=this.maxProperties)break;n[t(i)]=typeof a==`string`?t(a):a}return{name:t(e.name),properties:n}}},$t=class extends Ut{constructor(e){super(e,`news`)}async fetchItems(){return this.withTimeout(async e=>{let t=await this.fetchFn(this.endpoint,{signal:e});if(!t.ok)throw Error(`news request failed with HTTP ${t.status}`);let n=await this.readJson(t,`response`);if(!Array.isArray(n))throw Error(`news response was not an array`);return n.map((e,t)=>en(e,t))})}};function en(e,t){if(typeof e!=`object`||!e)throw Error(`news item ${t} was not an object`);let n=e;if(typeof n.id!=`string`||!n.id)throw Error(`news item ${t} is missing a string id`);if(typeof n.title!=`string`)throw Error(`news item ${t} is missing a string title`);if(typeof n.body!=`string`)throw Error(`news item ${t} is missing a string body`);return{id:n.id,title:n.title,body:n.body,publishedAt:typeof n.publishedAt==`number`?n.publishedAt:void 0}}var tn=class{constructor(e){this.store=new Yt(e.storage??Nt(),`mwg-news-seen:${e.namespace}`)}readSeen(){return new Set(this.store.read([]))}isSeen(e){return this.readSeen().has(e)}markSeen(e){let t=this.readSeen();t.add(e),this.store.write([...t])}unseen(e){let t=this.readSeen();return e.filter(e=>!t.has(e.id))}},nn=class{constructor(e,t={}){if(!e)throw Error(`a collection needs a name`);this.prefix=`mwg-db:${t.namespace??`default`}:${e}:`,this.storage=t.storage??Nt()}get size(){return this.keys().length}all(){return this.keys().map(e=>this.read(e))}get(e){let t=this.storage.read(this.prefix+e);return t===null?void 0:this.parse(t,this.prefix+e)}put(e){if(typeof e!=`object`||!e||Array.isArray(e)||typeof e.id!=`string`||e.id===``)throw Error(`a record must be an object with a string id`);this.storage.write(this.prefix+e.id,JSON.stringify(e))}remove(e){this.storage.remove(this.prefix+e)}where(e){return this.all().filter(e)}clear(){for(let e of this.keys())this.storage.remove(e)}keys(){return this.storage.keys().filter(e=>e.startsWith(this.prefix))}read(e){return this.parse(this.storage.read(e),e)}parse(e,t){return kt(e,{label:`record "${t}"`})}},rn=class{constructor(e,t){this.frame=0,this.recorded=[],this.actions=e,this.frames=t,this.onAction=e=>{this.recorded.push({frame:this.frame,action:e})},this.onFrame=()=>{this.frame++},e.add(this.onAction),t.add(this.onFrame)}get events(){return this.recorded}toJSON(){return this.recorded.map(e=>({frame:e.frame,action:e.action}))}stop(){this.actions.remove(this.onAction),this.frames.remove(this.onFrame)}},an=class{constructor(e,t,n){this.frame=0,this.index=0,this.events=e,this.dispatch=t,this.frames=n,this.onFrame=()=>this.pump(),n.add(this.onFrame)}get done(){return this.index>=this.events.length}stop(){this.frames.remove(this.onFrame)}pump(){for(;this.index<this.events.length&&this.events[this.index].frame<=this.frame;)this.dispatch(this.events[this.index].action),this.index++;this.frame++}};function on(e){return JSON.stringify(e)}function sn(e){let t=JSON.parse(e);if(!Array.isArray(t))throw Error(`a replay must be an array of {frame, action}`);return t.map(e=>{if(typeof e!=`object`||!e||!Number.isInteger(e.frame)||e.frame<0||typeof e.action!=`string`)throw Error(`a replay entry must be {frame: a non-negative integer, action: a string}`);return{frame:e.frame,action:e.action}})}var cn=class e{constructor(){this.entries=[],this.nextSequence=0}append(e,t=[]){let n={sequence:this.nextSequence,action:Rt(e,`action`),events:Rt([...t],`events`)};return this.nextSequence++,this.entries.push(n),structuredClone(n)}get size(){return this.entries.length}get all(){return structuredClone(this.entries)}mark(){return this.nextSequence}since(e){return structuredClone(this.entries.filter(t=>t.sequence>=e))}truncate(e){this.entries=this.entries.filter(t=>t.sequence<e),this.nextSequence=e}toJSON(){return this.all}replace(t){let n=e.fromJSON(t);this.entries=n.entries,this.nextSequence=n.nextSequence}static fromJSON(t){let n=new e,r=0;for(let e of t){if(!Number.isSafeInteger(e.sequence)||e.sequence!==r)throw Error(`action journal sequences must be contiguous from zero`);n.entries.push(structuredClone({sequence:e.sequence,action:e.action,events:[...e.events]})),r++}return n.nextSequence=r,n}};function ln(e){if(e.criteria)return e.criteria;if(e.counter===void 0||e.target===void 0)throw Error(`achievement "${e.id}" needs either counter/target or criteria`);return[{counter:e.counter,target:e.target}]}var un=class e{constructor(){this.definitions=new Map,this.counts=new Map,this.fresh=[]}define(e){this.definitions.set(e.id,e)}count(e){return this.counts.get(e)??0}increment(e,t=1){let n=this.count(e);this.counts.set(e,n+t);let r=[];for(let t of this.definitions.values()){let i=ln(t);i.some(t=>t.counter===e)&&(i.every(t=>t.counter===e?n>=t.target:this.count(t.counter)>=t.target)||i.every(e=>this.count(e.counter)>=e.target)&&(r.push(t.id),this.fresh.push(t.id)))}return r}unlocked(e){let t=this.definitions.get(e);if(!t)throw Error(`no such achievement: "${e}"`);return ln(t).every(e=>this.count(e.counter)>=e.target)}progress(e){let t=this.definitions.get(e);if(!t)throw Error(`no such achievement: "${e}"`);let n=ln(t);if(n.length!==1)throw Error(`achievement "${e}" has several criteria - use subProgress`);return{count:this.count(n[0].counter),target:n[0].target}}subProgress(e){let t=this.definitions.get(e);if(!t)throw Error(`no such achievement: "${e}"`);return ln(t).map(e=>{let t=this.count(e.counter);return{counter:e.counter,count:t,target:e.target,met:t>=e.target}})}drainNew(){let e=this.fresh;return this.fresh=[],e}toJSON(){return{counts:[...this.counts]}}static fromJSON(t,n){let r=new e;for(let e of t)r.define(e);for(let[e,t]of n.counts)r.counts.set(e,t);return r}},dn=class e{constructor(e=[]){this.active=new Set,this.spent=new Set,this.rules=[...e]}add(e){this.rules.push(e)}remove(e){this.rules=this.rules.filter(t=>t.id!==e),this.active.delete(e)}check(e){let t=[];for(let n of this.rules){if(n.once&&this.spent.has(n.id))continue;let r=n.when(e);r&&!this.active.has(n.id)&&(n.action(e),t.push(n.id),n.once&&this.spent.add(n.id)),r?this.active.add(n.id):this.active.delete(n.id)}return t}isActive(e){return this.active.has(e)}reset(){this.active.clear(),this.spent.clear()}toJSON(){return{active:[...this.active],spent:[...this.spent]}}static fromJSON(t,n){let r=new e(t);for(let e of n.active)r.active.add(e);for(let e of n.spent)r.spent.add(e);return r}},fn=class{constructor(e={}){let t=e.storage??Nt(),n=`mwg-session:${e.namespace??`default`}`,r=Number(t.read(n)??`0`);this.launches=(Number.isFinite(r)?r:0)+1,t.write(n,String(this.launches))}};function pn(e,t,n){return e<t?t:e>n?n:e}function mn(){return{musicVolume:1,sfxVolume:1,muted:!1,zoom:1,bindings:bn(je),custom:{}}}function hn(e){return e.muted?0:e.musicVolume}function gn(e){return e.muted?0:e.sfxVolume}var _n=class{constructor(e={}){this.storage=e.storage??Nt(),this.key=`mwg-settings:${e.namespace??`default`}`,this.value=Tn(this.storage,this.key),Re(this.value.bindings)}get current(){return{...this.value,bindings:bn(this.value.bindings),custom:{...this.value.custom}}}getCustom(e,t){return this.value.custom[e]??t}setCustom(e,t){this.value.custom[e]=t,En(this.storage,this.key,this.value)}setMusicVolume(e){this.update({musicVolume:e})}setSfxVolume(e){this.update({sfxVolume:e})}setMuted(e){this.update({muted:e})}setZoom(e){this.update({zoom:e})}setBindings(e){this.update({bindings:e})}update(e){e.musicVolume!==void 0&&(this.value.musicVolume=vn(e.musicVolume)),e.sfxVolume!==void 0&&(this.value.sfxVolume=vn(e.sfxVolume)),e.muted!==void 0&&(this.value.muted=e.muted),e.zoom!==void 0&&(this.value.zoom=yn(e.zoom)),e.bindings!==void 0&&(this.value.bindings=xn(e.bindings),Re(this.value.bindings)),e.custom!==void 0&&(this.value.custom=Cn(e.custom)),En(this.storage,this.key,this.value)}applyBindings(){Re(this.value.bindings)}reset(){this.value=mn(),Re(this.value.bindings),En(this.storage,this.key,this.value)}};function vn(e){return Number.isFinite(e)?pn(e,0,1):1}function yn(e){return Number.isFinite(e)?Math.max(.01,e):1}function bn(e){let t={};for(let[n,r]of Object.entries(e))t[n]=[...r];return t}function xn(e){if(typeof e!=`object`||!e||Array.isArray(e))return bn(je);let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r))continue;let e=r.filter(e=>typeof e==`string`);e.length>0&&(t[n]=e)}return Object.keys(t).length>0?t:bn(je)}function Sn(e){let t=typeof e;return t===`string`||t===`number`||t===`boolean`}function Cn(e){if(typeof e!=`object`||!e||Array.isArray(e))return{};let t={};for(let[n,r]of Object.entries(e))Sn(r)&&(t[n]=r);return t}function wn(e){let t=mn();if(typeof e!=`object`||!e||Array.isArray(e))return t;let n=e;return{musicVolume:typeof n.musicVolume==`number`?vn(n.musicVolume):t.musicVolume,sfxVolume:typeof n.sfxVolume==`number`?vn(n.sfxVolume):t.sfxVolume,muted:typeof n.muted==`boolean`?n.muted:t.muted,zoom:typeof n.zoom==`number`?yn(n.zoom):t.zoom,bindings:xn(n.bindings),custom:Cn(n.custom)}}function Tn(e,t){let n=e.read(t);if(!n)return mn();try{return wn(kt(n,{label:`settings`}))}catch{return mn()}}function En(e,t,n){e.write(t,JSON.stringify(n))}var Dn=class extends Ut{constructor(e){super(e,`feedback`)}async submit(e){if(!e.message?.trim())throw Error(`feedback message cannot be empty`);return this.withTimeout(async t=>{let n=await this.fetchFn(this.endpoint,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e),signal:t});if(!n.ok)throw Error(`feedback request failed with HTTP ${n.status}`);return{ok:!0,status:n.status}})}},On=class{constructor(e){this.schedule=[],this.cursor=0,this.elapsed=0,this.startedWaves=new Set,this.completed=!1,this.onSpawn=e.onSpawn,this.onWaveStart=e.onWaveStart,this.onComplete=e.onComplete,e.waves.forEach((e,t)=>{let n=e.entries.reduce((e,t)=>e+t.count,0),r=e.duration??0,i=0;for(let a of e.entries)for(let o=0;o<a.count;o++,i++){let o=n>1&&r>0?i/(n-1)*r:0;this.schedule.push({time:e.delay+o,kind:a.kind,waveIndex:t})}}),this.schedule.sort((e,t)=>e.time-t.time),this.schedule.length===0&&(this.completed=!0,this.onComplete?.())}update(e){if(!this.completed){for(this.elapsed+=e;this.cursor<this.schedule.length&&this.schedule[this.cursor].time<=this.elapsed;){let e=this.schedule[this.cursor];this.startedWaves.has(e.waveIndex)||(this.startedWaves.add(e.waveIndex),this.onWaveStart?.(e.waveIndex)),this.onSpawn(e.kind),this.cursor++}this.cursor>=this.schedule.length&&(this.completed=!0,this.onComplete?.())}}get isComplete(){return this.completed}};function kn(e,t){let n=e,r=t-(e-(e&1))/2;return{x:n,y:-n-r,z:r}}function An(e){return{x:e.x,y:e.z+(e.x-(e.x&1))/2}}var jn=[{x:1,y:-1,z:0},{x:1,y:0,z:-1},{x:0,y:1,z:-1},{x:-1,y:1,z:0},{x:-1,y:0,z:1},{x:0,y:-1,z:1}];function Mn(e,t){let n=kn(e,t);return jn.map(e=>An({x:n.x+e.x,y:n.y+e.y,z:n.z+e.z}))}function Nn(e,t){let n=kn(e.x,e.y),r=kn(t.x,t.y);return Math.max(Math.abs(n.x-r.x),Math.abs(n.y-r.y),Math.abs(n.z-r.z))}function Pn(e){let t=Math.round(e.x),n=Math.round(e.y),r=Math.round(e.z),i=Math.abs(t-e.x),a=Math.abs(n-e.y),o=Math.abs(r-e.z);return i>a&&i>o?t=-n-r:a>o?n=-t-r:r=-t-n,{x:t,y:n,z:r}}function Fn(e,t){let n=Nn(e,t);if(n===0)return[{x:e.x,y:e.y}];let r=kn(e.x,e.y),i=kn(t.x,t.y),a=[];for(let e=0;e<=n;e++){let t=e/n;a.push(An(Pn({x:r.x+(i.x-r.x)*t,y:r.y+(i.y-r.y)*t,z:r.z+(i.z-r.z)*t})))}return a}function In(e,t){let n=kn(e.x,e.y),r=[];for(let e=-t;e<=t;e++)for(let i=Math.max(-t,-e-t);i<=Math.min(t,-e+t);i++){let t=-e-i;r.push(An({x:n.x+e,y:n.y+i,z:n.z+t}))}return r}function Ln(e,t,n,r,i={}){let a=+((i.offset??`odd`)===`odd`);return(i.orientation??`flat-top`)===`pointy-top`?{x:e*n+((t&1)===a?n/2:0)+n/2,y:t*r*.75+r/2}:{x:e*n*.75+n/2,y:t*r+((e&1)===a?r/2:0)+r/2}}function Rn(e,t,n,r,i={}){let a=(i.orientation??`flat-top`)===`pointy-top`,o=a?n:n*.75,s=a?r*.75:r,c=Math.round((e-n/2)/o),l=Math.round((t-r/2)/s),u={x:c,y:l},d=1/0;for(let a=-2;a<=2;a++)for(let o=-2;o<=2;o++){let s={x:c+a,y:l+o},f=Ln(s.x,s.y,n,r,i),p=(f.x-e)**2+(f.y-t)**2;p<d&&(d=p,u=s)}return u}function zn(e,t,n,r){return n>=0&&r>=0&&n<e&&r<t}function Bn(e,t,n){return n*e+t}function Vn(e,t){return t%e}function Hn(e,t){return Math.floor(t/e)}function Un(e,t){return`${e},${t}`}function Wn(e){let t=/^(-?\d+),(-?\d+)$/.exec(e);return t?{x:Number(t[1]),y:Number(t[2])}:null}var Gn=.12,Kn=null,qn,Jn=new p;function Yn(){if(qn===void 0&&(qn=typeof matchMedia==`function`?matchMedia(`(prefers-reduced-motion: reduce)`):null,qn)){let e=()=>{Jn.dispatch(Zn())};typeof qn.addEventListener==`function`?qn.addEventListener(`change`,e):typeof qn.addListener==`function`&&qn.addListener(e)}return qn}function Xn(){return Yn()?.matches??!1}function Zn(){return Kn??Xn()}function Qn(e){Kn=e,Jn.dispatch(Zn())}function $n(e){return Yn(),Jn.add(e),()=>Jn.remove(e)}function er(e,t=`decorative`){return Zn()?t===`meaningful`?Math.min(e,Gn):0:e}var tr=[[0,-1],[1,0],[0,1],[-1,0]],nr=class e{constructor(e,t){this.width=e,this.height=t,this.volume=new Float32Array(e*t)}index(e,t){return e<0||t<0||e>=this.width||t>=this.height?-1:t*this.width+e}volumeAt(e,t){let n=this.index(e,t);return n<0?0:this.volume[n]}total(){let e=0;for(let t=0;t<this.volume.length;t++)e+=this.volume[t];return e}seed(e,t,n){let r=this.index(e,t);r>=0&&(this.volume[r]+=n)}clear(e,t){let n=this.index(e,t);n>=0&&(this.volume[n]=0)}spread(e,t=.25,n=.9){let r=new Float32Array(this.volume.length);for(let n=0;n<this.height;n++)for(let i=0;i<this.width;i++){let a=n*this.width+i,o=this.volume[a];if(o<=0)continue;let s=[];for(let[t,r]of tr){let a=i+t,o=n+r,c=this.index(a,o);c>=0&&e(a,o)&&s.push(c)}if(s.length===0)r[a]+=o;else{let e=o*t/s.length;r[a]+=o-e*s.length;for(let t of s)r[t]+=e}}let i=[];for(let e=0;e<r.length;e++){let t=r[e]*n,a=t<.001?0:t;a===0&&this.volume[e]>0&&i.push({x:e%this.width,y:Math.floor(e/this.width)}),this.volume[e]=a}return i}cellsAbove(e){let t=[];for(let n=0;n<this.height;n++)for(let r=0;r<this.width;r++){let i=this.volume[n*this.width+r];i>=e&&t.push({x:r,y:n,volume:i})}return t}toJSON(){return{width:this.width,height:this.height,volume:[...this.volume]}}static fromJSON(t){let n=new e(t.width,t.height);return n.volume.set(t.volume.slice(0,n.volume.length)),n}},rr={linear:e=>e,easeInQuad:e=>e*e,easeOutQuad:e=>e*(2-e),easeInOutQuad:e=>e<.5?2*e*e:1-(-2*e+2)**2/2,easeInCubic:e=>e*e*e,easeOutCubic:e=>1-(1-e)**3,easeInOutCubic:e=>e<.5?4*e*e*e:1-(-2*e+2)**3/2},ir=class{constructor(){this.tweens=[]}tween(e,t,n=rr.linear){let{ease:r=rr.linear,intent:i=`decorative`,alternate:a}=typeof n==`function`?{ease:n}:n,o=Zn()&&a!==void 0,s=o?a:t,c=er(e,o?`meaningful`:i);return c>0?new Promise(e=>{this.tweens.push({elapsed:0,duration:c,ease:r,apply:s,resolve:e,finishOnReduced:!o&&i===`decorative`})}):(s(1),Promise.resolve())}update(e){if(this.tweens.length!==0)for(let t of[...this.tweens]){if(t.finishOnReduced&&Zn()){this.tweens.splice(this.tweens.indexOf(t),1),t.apply(1),t.resolve();continue}t.elapsed+=e;let n=Math.min(1,t.elapsed/t.duration);t.apply(t.ease(n)),n>=1&&(this.tweens.splice(this.tweens.indexOf(t),1),t.resolve())}}get isBusy(){return this.tweens.length>0}clear(){this.tweens=[]}},ar=class{constructor(e={}){this.history=[],this.cursor=-1,this.limit=Math.max(1,e.limit??50)}push(e){this.history.length=this.cursor+1,this.history.push(e),this.history.length>this.limit&&this.history.shift(),this.cursor=this.history.length-1}get canUndo(){return this.cursor>0}get canRedo(){return this.cursor<this.history.length-1}undo(){return this.canUndo?(this.cursor--,this.history[this.cursor]):null}redo(){return this.canRedo?(this.cursor++,this.history[this.cursor]):null}get current(){return this.cursor>=0?this.history[this.cursor]:null}clear(){this.history=[],this.cursor=-1}};function or(e,t){if(!Number.isFinite(t.maxCost)||t.maxCost<0)return new Map;let n=t.key(e),r=new Map([[n,{cell:e,cost:0}]]),i=[{cell:e,key:n,cost:0}];for(;i.length>0;){let e=cr(i),n=r.get(e.key);if(n&&e.cost===n.cost&&!t.stop?.(e.cell,e.cost))for(let n of t.neighbors(e.cell)){let a=t.cost(e.cell,n);if(!Number.isFinite(a)||a<0)continue;let o=e.cost+a;if(o>t.maxCost||t.canEnter&&!t.canEnter(n,e.cell,o))continue;let s=t.key(n);if(o>=(r.get(s)?.cost??1/0))continue;let c={cell:n,key:s,cost:o};r.set(s,c),sr(i,c)}}return r}function sr(e,t){e.push(t);let n=e.length-1;for(;n>0;){let t=Math.floor((n-1)/2);if(e[t].cost<=e[n].cost)break;[e[t],e[n]]=[e[n],e[t]],n=t}}function cr(e){let t=e[0],n=e.pop();if(!t||!n||e.length===0)return t;e[0]=n;let r=0;for(;;){let t=r*2+1,n=t+1,i=r;if(t<e.length&&e[t].cost<e[i].cost&&(i=t),n<e.length&&e[n].cost<e[i].cost&&(i=n),i===r)break;[e[r],e[i]]=[e[i],e[r]],r=i}return t}var lr=class{constructor(){this.changed=new p,this.tasks=[],this.progress=new Map,this.status_=`idle`,this.current_=null,this.error_=null,this.cancelled=!1}add(e){if(!e.id)throw Error(`load task needs an id`);if(this.tasks.some(t=>t.id===e.id))throw Error(`duplicate load task "${e.id}"`);if(e.weight!==void 0&&!(e.weight>0))throw Error(`load task weight must be positive`);if(this.status_===`loading`)throw Error(`cannot add a task while loading`);return this.tasks.push(e),this.progress.set(e.id,0),this.emit(),this}get snapshot(){let e=this.tasks.reduce((e,t)=>e+(t.weight??1),0),t=this.tasks.reduce((e,t)=>e+(t.weight??1)*(this.progress.get(t.id)??0),0);return{status:this.status_,completed:t,total:e,current:this.current_,error:this.error_}}async start(){if(this.status_===`loading`)throw Error(`load queue is already running`);this.status_=`loading`,this.cancelled=!1,this.error_=null,this.emit();try{for(let e of this.tasks){if(this.cancelled)break;this.current_=e.id,this.emit();let t=this;await e.run({get cancelled(){return t.cancelled},report:t=>this.report(e.id,t)}),this.cancelled||this.report(e.id,1)}this.current_=null,this.status_=this.cancelled?`cancelled`:`ready`,this.emit()}catch(e){throw this.current_=null,this.error_=e,this.status_=`failed`,this.emit(),e}}cancel(){this.status_===`loading`&&(this.cancelled=!0)}retry(){if(this.status_===`loading`)throw Error(`cannot retry while loading`);this.status_=`idle`,this.current_=null,this.error_=null,this.cancelled=!1;for(let e of this.tasks)this.progress.set(e.id,0);this.emit()}report(e,t){if(!Number.isFinite(t))throw Error(`load progress must be finite`);this.progress.set(e,Math.max(0,Math.min(1,t))),this.emit()}emit(){this.changed.dispatch(this.snapshot)}},ur=class{constructor(){this.entities=new Map,this.ids=new Map,this.sequence=0}add(e,t){let n=this.ids.get(e);if(n!==void 0){if(t!==void 0&&t!==n)throw Error(`entity already has id ${n}`);return n}let r=t;if(r!==void 0){if(r.length===0)throw Error(`entity id must not be empty`);if(this.entities.has(r))throw Error(`entity id already exists: ${r}`)}else do r=`e${this.sequence++}`;while(this.entities.has(r));return this.entities.set(r,e),this.ids.set(e,r),r}get(e){return this.entities.get(e)}idOf(e){return this.ids.get(e)}has(e){return this.entities.has(e)}remove(e){let t=this.entities.get(e);return t!==void 0&&(this.entities.delete(e),this.ids.delete(t),!0)}get size(){return this.entities.size}},dr=class{constructor(e){this.queue=[],this.busy=!1,this.remaining=0,this.play=e.play}enqueue(e){this.queue.push(...e),this.busy||this.advance()}update(e){this.busy&&(this.remaining-=e,this.remaining<=0&&this.advance())}get isBusy(){return this.busy}clear(){this.queue=[],this.busy=!1,this.remaining=0}advance(){let e=this.queue.shift();if(e===void 0){this.busy=!1,this.remaining=0;return}this.busy=!0;let t=this.play(e)||0;t>0?this.remaining=t:this.advance()}},fr=2166136261,pr=16777619;function mr(e,t=!1){if(e==null)return`null`;switch(typeof e){case`boolean`:return e?`true`:`false`;case`number`:return Number.isFinite(e)?String(e):`null`;case`string`:return JSON.stringify(e);case`bigint`:return JSON.stringify(e.toString());case`function`:case`symbol`:return t?`null`:`undefined`}return Array.isArray(e)?`[${e.map(e=>mr(e,!0)).join(`,`)}]`:`{${Object.entries(e).filter(([,e])=>e!==void 0&&typeof e!=`function`&&typeof e!=`symbol`).sort(([e],[t])=>e<t?-1:+(e>t)).map(([e,t])=>`${JSON.stringify(e)}:${mr(t)}`).join(`,`)}}`}function hr(e){let t=mr(e),n=fr;for(let e=0;e<t.length;e++)n^=t.charCodeAt(e),n=Math.imul(n,pr)>>>0;return n>>>0}var gr=class{constructor(){this.reference=new Map,this.desyncTick=null}observe(e,t){let n=this.reference.get(e);return n===void 0?(this.reference.set(e,t),!0):n===t||(this.desyncTick===null&&(this.desyncTick=e),!1)}get divergent(){return this.desyncTick!==null}get atTick(){return this.desyncTick}reset(){this.reference.clear(),this.desyncTick=null}};function _r(e,t={}){let n=br(e);if(n.length===0)return[];let[r,...i]=n,a=t.listDelimiter??`;`,o=t.mapDelimiter??`=`;return i.map((e,n)=>{let i={};return r.forEach((r,s)=>{let c=e[s]??``;c!==``&&(i[r]=vr(c,t.columns?.[r]??`string`,r,n,a,o))}),i})}function vr(e,t,n,r,i,a){return yr(e,t,{column:n,rowIndex:r,listDelimiter:i,mapDelimiter:a,error:()=>t===`number`?`CSV row ${r+1}, column "${n}": "${e}" is not a number`:t===`boolean`?`CSV row ${r+1}, column "${n}": "${e}" is not "true" or "false"`:t===`map`?`CSV row ${r+1}, column "${n}": "${e.split(i).map(e=>e.trim()).find(e=>e&&!e.includes(a))??e}" has no "${a}" to split a key from its value`:`CSV row ${r+1}, column "${n}": "${e}" is invalid`})}function yr(e,t,n={}){let r=n.column??`value`,i=n.listDelimiter??`;`,a=n.mapDelimiter??`=`,o=e=>{throw Error(n.error?.(e)??e)};switch(t){case`string`:return e;case`number`:{let t=Number(e);return Number.isFinite(t)||o(`${r} must be a number`),t}case`boolean`:{let t=e.toLowerCase();if(t===`true`)return!0;if(t===`false`)return!1;if(n.acceptYesNo&&t===`yes`)return!0;if(n.acceptYesNo&&t===`no`)return!1;o(`${r} must be true, false${n.acceptYesNo?`, yes, or no`:``}`)}case`list`:return e.split(i).map(e=>e.trim()).filter(e=>e.length>0);case`map`:{let t={};for(let n of e.split(i).map(e=>e.trim()).filter(e=>e.length>0)){let e=n.indexOf(a);e===-1&&o(`${r} map entry must contain ${a}`),t[n.slice(0,e).trim()]=n.slice(e+a.length).trim()}return t}}}function br(e){let t=[],n=[],r=``,i=!1,a=0;for(;a<e.length;){let o=e[a];if(i){if(o===`"`){if(e[a+1]===`"`){r+=`"`,a+=2;continue}i=!1,a++;continue}r+=o,a++;continue}if(o===`"`){i=!0,a++;continue}if(o===`,`){n.push(r),r=``,a++;continue}if(o===`\r`){a++;continue}if(o===`
|
|
2
2
|
`){n.push(r),t.push(n),n=[],r=``,a++;continue}r+=o,a++}return(r.length>0||n.length>0)&&(n.push(r),t.push(n)),t.filter(e=>e.length!==1||e[0]!==``)}function xr(e){let t=[],n=[],r,i=e=>{if(!n.includes(e)){if(n.length>=2)throw Error(`dialogue text supports at most two speakers for the "-" shorthand; found a third speaker "${e}" after "${n[0]}" and "${n[1]}" were already established`);n.push(e)}};for(let a of e.split(`
|
|
3
3
|
`)){let e=a.trim();if(e===``)continue;let o=/^@(\S+)(?:\s+(.*))?$/.exec(e);if(o){let[,e,n]=o;i(e),n&&(t.push({text:n.trim(),speaker:e}),r=e);continue}if(e.startsWith(`-`)){if(n.length<2)throw Error(`a "-" line needs two established speakers first (write two "@id text" lines before it)`);let i=e.slice(1).trim(),a=n.find(e=>e!==r)??n[0];t.push({text:i,speaker:a}),r=a;continue}t.push({text:e}),r=void 0}return t}function Sr(e){let t=Cr(e);if(t.length===0)throw Error(`this twee source has no passages - passages start with ":: Name"`);let n={},r,i;for(let e of t){if(e.name===`StoryTitle`){r=e.body.trim()||void 0;continue}if(e.name===`StoryData`){i=Tr(e.body);continue}if(Object.prototype.hasOwnProperty.call(n,e.name))throw Error(`this twee source defines "${e.name}" twice`);n[e.name]=Er(e.name,e.body)}let a=Object.keys(n);if(a.length===0)throw Error(`this twee source has no story passages, only StoryTitle/StoryData`);if(i!==void 0&&!Object.prototype.hasOwnProperty.call(n,i))throw Error(`StoryData starts at "${i}", which is not a passage in this file`);for(let[e,t]of Object.entries(n))for(let r of t)if(`ask`in r){for(let t of r.choices)if(t.goto!==void 0&&!Object.prototype.hasOwnProperty.call(n,t.goto))throw Error(`passage "${e}" links to "${t.goto}", which is not a passage in this file`)}return{story:n,start:i??a[0],title:r}}function Cr(e){let t=[],n=null,r=[],i=()=>{n!==null&&t.push({name:n,body:r.join(`
|
|
4
4
|
`)})};for(let t of e.split(`
|
package/dist/version.d.ts
CHANGED
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
* this from `package.json` automatically, chosen because this project's own build already
|
|
10
10
|
* has no step before `tsc`/`vite` that this would need to run ahead of.
|
|
11
11
|
*/
|
|
12
|
-
export declare const version = "0.17.
|
|
12
|
+
export declare const version = "0.17.1";
|
|
13
13
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
* this from `package.json` automatically, chosen because this project's own build already
|
|
10
10
|
* has no step before `tsc`/`vite` that this would need to run ahead of.
|
|
11
11
|
*/
|
|
12
|
-
export const version = '0.17.
|
|
12
|
+
export const version = '0.17.1';
|
|
13
13
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datamoc/mw_games",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "A local-file game framework: renderer-free game logic, drawn through PixiJS in 2D or Babylon.js in 3D, with mobile and desktop packaging.",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"repository": {
|
package/sbom.cdx.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.6",
|
|
4
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"serialNumber": "urn:uuid:7a8a2023-3df2-5ef0-b33f-e868b0c9b4a1",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
7
|
"tools": {
|
|
@@ -10,16 +10,16 @@
|
|
|
10
10
|
"type": "application",
|
|
11
11
|
"group": "datamoc",
|
|
12
12
|
"name": "tools/sbom.mjs",
|
|
13
|
-
"version": "0.17.
|
|
13
|
+
"version": "0.17.1"
|
|
14
14
|
}
|
|
15
15
|
]
|
|
16
16
|
},
|
|
17
17
|
"component": {
|
|
18
18
|
"type": "library",
|
|
19
|
-
"bom-ref": "pkg:npm/%40datamoc/mw_games@0.17.
|
|
19
|
+
"bom-ref": "pkg:npm/%40datamoc/mw_games@0.17.1",
|
|
20
20
|
"name": "@datamoc/mw_games",
|
|
21
|
-
"version": "0.17.
|
|
22
|
-
"purl": "pkg:npm/%40datamoc/mw_games@0.17.
|
|
21
|
+
"version": "0.17.1",
|
|
22
|
+
"purl": "pkg:npm/%40datamoc/mw_games@0.17.1",
|
|
23
23
|
"description": "A local-file game framework: renderer-free game logic, drawn through PixiJS in 2D or Babylon.js in 3D, with mobile and desktop packaging.",
|
|
24
24
|
"licenses": [
|
|
25
25
|
{
|
|
@@ -4453,7 +4453,7 @@
|
|
|
4453
4453
|
]
|
|
4454
4454
|
},
|
|
4455
4455
|
{
|
|
4456
|
-
"ref": "pkg:npm/%40datamoc/mw_games@0.17.
|
|
4456
|
+
"ref": "pkg:npm/%40datamoc/mw_games@0.17.1",
|
|
4457
4457
|
"dependsOn": [
|
|
4458
4458
|
"pkg:npm/%40babylonjs/core@9.26.0",
|
|
4459
4459
|
"pkg:npm/%40babylonjs/loaders@9.26.0",
|
package/tools/csp.mjs
CHANGED
|
@@ -21,7 +21,16 @@ import { createHash } from 'node:crypto';
|
|
|
21
21
|
* extra script texts to allow by hash (a single-file loader's unpacked scripts)
|
|
22
22
|
*/
|
|
23
23
|
export function contentSecurityPolicy(html, { connect = [], eval: allowEval = true, scripts = [] } = {}) {
|
|
24
|
-
|
|
24
|
+
//The HTML parser normalises newlines before it hashes an inline script: CRLF and lone CR
|
|
25
|
+
//become LF. A checkout with core.autocrlf=true (every Windows clone) hands the source page
|
|
26
|
+
//over with CRLF, so hashing the bytes on disk here would emit a policy Chrome computes
|
|
27
|
+
//differently from the file it just parsed, and the page refuses its own script while
|
|
28
|
+
//`file://` on Linux stays quiet. Hash the text the browser will see.
|
|
29
|
+
const inline = [...html.matchAll(/<script(?![^>]*\bsrc=)[^>]*>([\s\S]*?)<\/script>/gi)].map((match) =>
|
|
30
|
+
match[1].replace(/\r\n?/g, '\n'),
|
|
31
|
+
);
|
|
32
|
+
//`scripts` are texts the standalone page's unpacker sets on a script element at runtime
|
|
33
|
+
//(`s.text = code`), where no parser runs: those are hashed exactly as they are written.
|
|
25
34
|
const hashes = [...new Set([...inline, ...scripts].map((text) => `'sha256-${sha256(text)}'`))];
|
|
26
35
|
const directives = {
|
|
27
36
|
'default-src': ["'none'"],
|
package/tools/sbom.mjs
CHANGED
|
@@ -313,7 +313,9 @@ async function main(argv) {
|
|
|
313
313
|
|
|
314
314
|
if (argv.includes('--check')) {
|
|
315
315
|
const committed = await readFile(out, 'utf8').catch(() => undefined);
|
|
316
|
-
|
|
316
|
+
//CRLF is a Windows checkout's doing, not a difference in the BOM itself (and a missing
|
|
317
|
+
//file still reads as out of date: '' never equals the serialized BOM)
|
|
318
|
+
if ((committed ?? '').replace(/\r\n/g, '\n') !== json.replace(/\r\n/g, '\n')) {
|
|
317
319
|
console.error(`${name} is out of date with package-lock.json. Run "npm run sbom" and commit the result.`);
|
|
318
320
|
process.exitCode = 1;
|
|
319
321
|
} else {
|