diff --git a/asset-manifest.json b/asset-manifest.json index e7c1907..5bd2809 100644 --- a/asset-manifest.json +++ b/asset-manifest.json @@ -3,8 +3,8 @@ "static/js/0.ded40b31.chunk.js": "/diabloweb/static/js/0.ded40b31.chunk.js", "static/js/0.ded40b31.chunk.js.map": "/diabloweb/static/js/0.ded40b31.chunk.js.map", "main.css": "/diabloweb/static/css/main.9fcbefb1.chunk.css", - "main.js": "/diabloweb/static/js/main.21ca9033.chunk.js", - "main.js.map": "/diabloweb/static/js/main.21ca9033.chunk.js.map", + "main.js": "/diabloweb/static/js/main.d7e3eea7.chunk.js", + "main.js.map": "/diabloweb/static/js/main.d7e3eea7.chunk.js.map", "runtime~main.js": "/diabloweb/static/js/runtime~main.bf17ce54.js", "runtime~main.js.map": "/diabloweb/static/js/runtime~main.bf17ce54.js.map", "runtime~storage.js": "/diabloweb/static/js/runtime~storage.83a78cef.js", @@ -16,7 +16,7 @@ "54277a9e96a084857713.worker.js": "/diabloweb/54277a9e96a084857713.worker.js", "54277a9e96a084857713.worker.js.map": "/diabloweb/54277a9e96a084857713.worker.js.map", "index.html": "/diabloweb/index.html", - "precache-manifest.1e3c4731c4d8a2b5b0e5bc790bbdd684.js": "/diabloweb/precache-manifest.1e3c4731c4d8a2b5b0e5bc790bbdd684.js", + "precache-manifest.e96dbf8295345a790e35eaa74f93c9cd.js": "/diabloweb/precache-manifest.e96dbf8295345a790e35eaa74f93c9cd.js", "service-worker.js": "/diabloweb/service-worker.js", "static/css/main.9fcbefb1.chunk.css.map": "/diabloweb/static/css/main.9fcbefb1.chunk.css.map", "static/media/Diablo.wasm": "/diabloweb/static/media/Diablo.9c99d371.wasm", diff --git a/index.html b/index.html index 699d166..0856adf 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -DIABLO
\ No newline at end of file +DIABLO
\ No newline at end of file diff --git a/precache-manifest.1e3c4731c4d8a2b5b0e5bc790bbdd684.js b/precache-manifest.e96dbf8295345a790e35eaa74f93c9cd.js similarity index 88% rename from precache-manifest.1e3c4731c4d8a2b5b0e5bc790bbdd684.js rename to precache-manifest.e96dbf8295345a790e35eaa74f93c9cd.js index 73f878a..a0aca80 100644 --- a/precache-manifest.1e3c4731c4d8a2b5b0e5bc790bbdd684.js +++ b/precache-manifest.e96dbf8295345a790e35eaa74f93c9cd.js @@ -4,11 +4,11 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([ "url": "/diabloweb/54277a9e96a084857713.worker.js" }, { - "revision": "c8f4d79e5e9d7cfbae980d19f195be20", + "revision": "9532a0620aff405264f3c4a00ea02e0d", "url": "/diabloweb/index.html" }, { - "revision": "ccfdd318825889f9e0bb", + "revision": "4d682fbe6f889ac05131", "url": "/diabloweb/static/css/main.9fcbefb1.chunk.css" }, { @@ -20,8 +20,8 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([ "url": "/diabloweb/static/js/5.bb4b864b.chunk.js" }, { - "revision": "ccfdd318825889f9e0bb", - "url": "/diabloweb/static/js/main.21ca9033.chunk.js" + "revision": "4d682fbe6f889ac05131", + "url": "/diabloweb/static/js/main.d7e3eea7.chunk.js" }, { "revision": "077fe45e700d7971de0b", diff --git a/service-worker.js b/service-worker.js index e63c4f4..151d7b0 100644 --- a/service-worker.js +++ b/service-worker.js @@ -14,7 +14,7 @@ importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); importScripts( - "/diabloweb/precache-manifest.1e3c4731c4d8a2b5b0e5bc790bbdd684.js" + "/diabloweb/precache-manifest.e96dbf8295345a790e35eaa74f93c9cd.js" ); self.addEventListener('message', (event) => { diff --git a/static/js/main.21ca9033.chunk.js.map b/static/js/main.21ca9033.chunk.js.map deleted file mode 100644 index dbfebe4..0000000 --- a/static/js/main.21ca9033.chunk.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["api/game.worker.js","serviceWorker.js","api/load_spawn.js","api/loader.js","api/sound.js","App.js","index.js","fs.js"],"names":["module","exports","Worker","__webpack_require__","p","isLocalhost","Boolean","window","location","hostname","match","registerValidSW","swUrl","config","navigator","serviceWorker","register","then","registration","onupdatefound","installingWorker","installing","onstatechange","state","controller","console","log","onUpdate","onSuccess","catch","error","SpawnSize","load_spawn","_x","_x2","_load_spawn","apply","this","arguments","_callee","api","fs","file","spawn","data","regenerator_default","a","wrap","_context","prev","next","files","get","byteLength","delete","axios","request","url","process","responseType","onDownloadProgress","e","onProgress","text","loaded","total","headers","Cache-Control","sent","Error","Uint8Array","set","update","slice","abrupt","stop","onRender","ctx","_ref","bitmap","images","clip","belt","transferFromImageBitmap","_iteratorNormalCompletion","_didIteratorError","_iteratorError","undefined","_step","_iterator","Symbol","iterator","done","_ref5","value","x","y","w","h","image","createImageData","putImageData","err","return","length","save","font","x0","y0","x1","y1","beginPath","rect","_iteratorNormalCompletion2","_didIteratorError2","_iteratorError2","_step2","_iterator2","_ref4","str","color","r","g","b","fillStyle","concat","fillText","restore","updateBelt","audio","mpq","context","offscreen","name","canvas","getContext","alpha","Promise","resolve","reject","worker","addEventListener","_ref6","action","func","_len","params","Array","_key","postMessage","batch","Object","toConsumableArray","_iteratorNormalCompletion3","_didIteratorError3","_iteratorError3","_step3","_iterator3","_ref8","setCursorPos","openKeyboard","open","onError","transfer","_iteratorNormalCompletion4","_didIteratorError4","_iteratorError4","_step4","_iterator4","_ref11","slicedToArray","push","buffer","load_game","do_load_game","AudioContext","webkitAudioContext","create_sound","duplicate_sound","play_sound","set_volume","stop_sound","delete_sound","sounds","Map","id","channels","rate","createBuffer","i","copyToChannel","subarray","gain","createGain","panner","StereoPannerNode","pan","srcId","src","volume","loop","source","Math","pow","relVolume","createBufferSource","connect","destination","start","init_sound","TOUCH_MOVE","TOUCH_RMB","Link","children","props","objectWithoutProperties","react_default","createElement","assign","target","rel","App","_this","classCallCheck","possibleConstructorReturn","getPrototypeOf","call","started","loading","touch","dropping","has_spawn","cursorPos","touchButtons","touchCtx","touchMods","touchBelt","create_fs","onDrop","dataTransfer","items","kind","getAsFile","getDropFile","preventDefault","setState","onDragEnter","setDropping","onDragOver","isDropFile","onDragLeave","onResize","document","exitPointerLock","onPointerLockChange","screen","innerHeight","height","pointerLocked","game","onMouseMove","_this$mousePos","mousePos","eventMods","onMouseDown","_this$mousePos2","requestPointerLock","mouseButton","onMouseUp","_this$mousePos3","onKeyDown","keyCode","key","showKeyboard","charCodeAt","clearKeySel","onMenu","onKeyUp","onKeyboard","_this2","keyboard","valid","join","substring","values","map","_","parseFile","touchButton","touchCanvas","onFullscreenChange","fullscreenElement","element","onTouchStart","updateTouchButton","touches","_this$mousePos4","onTouchMove","_this$mousePos5","onTouchEnd","prevTc","_this$mousePos6","index","setTouchButton","requestFullscreen","setCanvas","setElement","setKeyboard","setTouch0","setTouch_","bind","assertThisInitialized","setTouch1","setTouch2","setTouch3","setTouchBelt_","setTouch4","setTouch5","_this3","inc","_ref2","max","classList","add","focus","remove","blur","_this4","getBoundingClientRect","left","right","top","bottom","setTimeout","progress","idx","slot","style","display","drawImage","used","Set","pos","has","drawBelt","_this5","removeEventListener","passive","capture","message","pointerLockElement","mozPointerLockElement","min","movementX","movementY","clientX","clientY","round","button","shiftKey","ctrlKey","altKey","len","setSelectionRange","use","toggle","now","performance","beltTime","release","_this6","touchOther","btn","_loop","_ref3","identifier","stick","find","t","panPos","v","indexOf","original","_ret","setTouchMod","dx","dy","step","offsetHeight","abs","width","appendChild","_this7","_this$state","className","classNames","ref","active","type","onChange","spellCheck","App_Link","href","htmlFor","accept","onClick","React","Component","ReactDOM","render","src_App_0","getElementById","URL","origin","fetch","response","contentType","status","ready","unregister","reload","checkValidServiceWorker","importStorage","frame","method","contentWindow","body","downloadFile","store","blob","lnk","C_Projects_diabloweb_diabloweb_node_modules_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_1___default","toLowerCase","Blob","createObjectURL","setAttribute","click","removeChild","revokeObjectURL","_x3","_create_fs","_callee2","load","_i","_Object$entries","_ref7","_name","_data","_files","_context2","IdbKvStore","t0","json","t1","entries","C_Projects_diabloweb_diabloweb_node_modules_babel_runtime_helpers_esm_slicedToArray__WEBPACK_IMPORTED_MODULE_0__","t2","finish","DownloadFile","clear","t3"],"mappings":"4EAAAA,EAAAC,QAAA,WACA,WAAAC,OAAoBC,EAAAC,EAAuB,8LCWrCC,SAAcC,QACW,cAA7BC,OAAOC,SAASC,UAEe,UAA7BF,OAAOC,SAASC,UAEhBF,OAAOC,SAASC,SAASC,MACvB,4DAsCN,SAASC,EAAgBC,EAAOC,GAC9BC,UAAUC,cACPC,SAASJ,GACTK,KAAK,SAAAC,GACJA,EAAaC,cAAgB,WAC3B,IAAMC,EAAmBF,EAAaG,WACd,MAApBD,IAGJA,EAAiBE,cAAgB,WACA,cAA3BF,EAAiBG,QACfT,UAAUC,cAAcS,YAI1BC,QAAQC,IACN,iHAKEb,GAAUA,EAAOc,UACnBd,EAAOc,SAAST,KAMlBO,QAAQC,IAAI,sCAGRb,GAAUA,EAAOe,WACnBf,EAAOe,UAAUV,UAO5BW,MAAM,SAAAC,GACLL,QAAQK,MAAM,4CAA6CA,0KC9F3DC,EAAY,SAIH,SAAeC,EAA9BC,EAAAC,GAAA,OAAAC,EAAAC,MAAAC,KAAAC,sDAAe,SAAAC,EAA0BC,EAAKC,GAA/B,IAAAC,EAAAC,EAAAC,EAAA,OAAAC,EAAAC,EAAAC,KAAA,SAAAC,GAAA,cAAAA,EAAAC,KAAAD,EAAAE,MAAA,YACTR,EAAOD,EAAGU,MAAMC,IAAI,eACZV,EAAKW,aAAetB,EAFnB,CAAAiB,EAAAE,KAAA,eAGXT,EAAGU,MAAMG,OAAO,aAHLN,EAAAE,KAAA,EAILT,EAAGa,OAAO,aAJL,OAKXZ,EAAO,KALI,UAORA,EAPQ,CAAAM,EAAAE,KAAA,gBAAAF,EAAAE,KAAA,EAQSK,IAAMC,QAAQ,CAChCC,IAAKC,uBACLC,aAAc,cACdC,mBAAoB,SAAAC,GACdrB,EAAIsB,YACNtB,EAAIsB,WAAW,CAACC,KAAM,iBAAkBC,OAAQH,EAAEG,OAAQC,MAAOJ,EAAEI,OAASlC,KAGhFmC,QAAS,CACPC,gBAAiB,sBAjBV,WAQLxB,EARKK,EAAAoB,MAoBDxB,KAAKS,aAAetB,EApBnB,CAAAiB,EAAAE,KAAA,eAqBHmB,MAAM,uEArBH,QAuBLzB,EAAO,IAAI0B,WAAW3B,EAAMC,MAClCH,EAAGU,MAAMoB,IAAI,YAAa3B,GAC1BH,EAAG+B,OAAO,YAAa5B,EAAK6B,SAzBjB,eAAAzB,EAAA0B,OAAA,SA2BNjC,GA3BM,yBAAAO,EAAA2B,SAAApC,6BCFf,SAASqC,EAASpC,EAAKqC,EAAvBC,GAAgE,IAAnCC,EAAmCD,EAAnCC,OAAQC,EAA2BF,EAA3BE,OAAQjB,EAAmBe,EAAnBf,KAAMkB,EAAaH,EAAbG,KAAMC,EAAOJ,EAAPI,KACvD,GAAIH,EACFF,EAAIM,wBAAwBJ,OACvB,KAAAK,GAAA,EAAAC,GAAA,EAAAC,OAAAC,EAAA,IACL,QAAAC,EAAAC,EAA+BT,EAA/BU,OAAAC,cAAAP,GAAAI,EAAAC,EAAAvC,QAAA0C,MAAAR,GAAA,EAAuC,KAAAS,EAAAL,EAAAM,MAA7BC,EAA6BF,EAA7BE,EAAGC,EAA0BH,EAA1BG,EAAGC,EAAuBJ,EAAvBI,EAAGC,EAAoBL,EAApBK,EAAGtD,EAAiBiD,EAAjBjD,KACduD,EAAQtB,EAAIuB,gBAAgBH,EAAGC,GACrCC,EAAMvD,KAAK2B,IAAI3B,GACfiC,EAAIwB,aAAaF,EAAOJ,EAAGC,IAJxB,MAAAM,GAAAjB,GAAA,EAAAC,EAAAgB,EAAA,YAAAlB,GAAA,MAAAK,EAAAc,QAAAd,EAAAc,SAAA,WAAAlB,EAAA,MAAAC,GAML,GAAIvB,EAAKyC,OAAQ,CAGf,GAFA3B,EAAI4B,OACJ5B,EAAI6B,KAAO,4BACPzB,EAAM,KACD0B,EAAkB1B,EAAlB0B,GAAIC,EAAc3B,EAAd2B,GAAIC,EAAU5B,EAAV4B,GAAIC,EAAM7B,EAAN6B,GACnBjC,EAAIkC,YACJlC,EAAImC,KAAKL,EAAIC,EAAIC,EAAKF,EAAIG,EAAKF,GAC/B/B,EAAII,OAPS,IAAAgC,GAAA,EAAAC,GAAA,EAAAC,OAAA5B,EAAA,IASf,QAAA6B,EAAAC,EAAqCtD,EAArC2B,OAAAC,cAAAsB,GAAAG,EAAAC,EAAAnE,QAAA0C,MAAAqB,GAAA,EAA2C,KAAAK,EAAAF,EAAAtB,MAAjCC,EAAiCuB,EAAjCvB,EAAGC,EAA8BsB,EAA9BtB,EAASuB,EAAqBD,EAA3BvD,KAAWyD,EAAgBF,EAAhBE,MACnBC,EAAMD,GAAS,GAAM,IACrBE,EAAMF,GAAS,EAAK,IACpBG,EAAa,IAARH,EACX3C,EAAI+C,UAAJ,OAAAC,OAAuBJ,EAAvB,MAAAI,OAA6BH,EAA7B,MAAAG,OAAmCF,EAAnC,KACA9C,EAAIiD,SAASP,EAAKxB,EAAGC,EAAI,KAdZ,MAAAM,GAAAY,GAAA,EAAAC,EAAAb,EAAA,YAAAW,GAAA,MAAAI,EAAAd,QAAAc,EAAAd,SAAA,WAAAW,EAAA,MAAAC,GAgBftC,EAAIkD,WAIRvF,EAAIwF,WAAW9C,8CAejB,SAAA3C,EAA4BC,EAAKyF,EAAOC,GAAxC,IAAAzF,EAAAE,EAAAwF,EAAAC,EAAA,OAAAvF,EAAAC,EAAAC,KAAA,SAAAC,GAAA,cAAAA,EAAAC,KAAAD,EAAAE,MAAA,cAAAF,EAAAE,KAAA,EACmBV,EAAIC,GADvB,UACQA,EADRO,EAAAoB,KAEMzB,GAAQ,GACRuF,EAHN,CAAAlF,EAAAE,KAAA,QAISgF,EAAIG,KAAK3H,MAAM,mBAClBiC,GAAQ,EACRF,EAAGU,MAAMG,OAAO,cANtBN,EAAAE,KAAA,uBAAAF,EAAAE,KAAA,GASUlB,EAAWQ,EAAKC,GAT1B,eAYM0F,EAAU,KAAMC,GAAY,EAK9BD,EAAU3F,EAAI8F,OAAOC,WAAW,KAAM,CAACC,OAAO,IAjBlDxF,EAAAE,KAAA,GAmBe,IAAIuF,QAAQ,SAACC,EAASC,GACjC,IACE,IAAMC,EAAS,IAAI1I,IACnB0I,EAAOC,iBAAiB,UAAW,SAAAC,GAAY,IAAVlG,EAAUkG,EAAVlG,KACnC,OAAQA,EAAKmG,QACb,IAAK,SACHL,EAAQ,SAACM,GAAD,QAAAC,EAAA3G,UAAAkE,OAAU0C,EAAV,IAAAC,MAAAF,EAAA,EAAAA,EAAA,KAAAG,EAAA,EAAAA,EAAAH,EAAAG,IAAUF,EAAVE,EAAA,GAAA9G,UAAA8G,GAAA,OAAqBR,EAAOS,YAAY,CAACN,OAAQ,QAASC,OAAME,aACxE,MACF,IAAK,SACHtE,EAASpC,EAAK2F,EAASvF,EAAK0G,OAC5B,MACF,IAAK,QACHrB,EAAMrF,EAAKoG,MAAX5G,MAAA6F,EAAKsB,OAAAC,EAAA,EAAAD,CAAe3G,EAAKsG,SACzB,MACF,IAAK,aAAL,IAAAO,GAAA,EAAAC,GAAA,EAAAC,OAAApE,EAAA,IACE,QAAAqE,EAAAC,EAA2BjH,EAAK0G,MAAhC5D,OAAAC,cAAA8D,GAAAG,EAAAC,EAAA3G,QAAA0C,MAAA6D,GAAA,EAAuC,KAAAK,EAAAF,EAAA9D,MAA7BkD,EAA6Bc,EAA7Bd,KAAME,EAAuBY,EAAvBZ,OACdjB,EAAMe,GAAN5G,MAAA6F,EAAKsB,OAAAC,EAAA,EAAAD,CAAUL,KAFnB,MAAA5C,GAAAoD,GAAA,EAAAC,EAAArD,EAAA,YAAAmD,GAAA,MAAAI,EAAAtD,QAAAsD,EAAAtD,SAAA,WAAAmD,EAAA,MAAAC,GAIE,MACF,IAAK,KACHlH,EAAGG,EAAKoG,MAAR5G,MAAAK,EAAE8G,OAAAC,EAAA,EAAAD,CAAe3G,EAAKsG,SACtB,MACF,IAAK,SACH1G,EAAIuH,aAAanH,EAAKmD,EAAGnD,EAAKoD,GAC9B,MACF,IAAK,WACHxD,EAAIwH,aAAapH,EAAKqH,MACtB,MACF,IAAK,QACHzH,EAAI0H,QAAQtH,EAAKd,OACjB,MACF,IAAK,SACH6G,EAAOtE,MAAMzB,EAAKd,QAClB,MACF,IAAK,WACHU,EAAIsB,WAAW,CAACC,KAAMnB,EAAKmB,KAAMC,OAAQpB,EAAKoB,OAAQC,MAAOrB,EAAKqB,WAKtE,IAAMkG,EAAU,GAvCdC,GAAA,EAAAC,GAAA,EAAAC,OAAA/E,EAAA,IAwCF,QAAAgF,EAAAC,EAAqB/H,EAAGU,MAAxBuC,OAAAC,cAAAyE,GAAAG,EAAAC,EAAAtH,QAAA0C,MAAAwE,GAAA,EAA+B,KAAAK,EAAAF,EAAAzE,MAAnBpD,EAAmB6G,OAAAmB,EAAA,EAAAnB,CAAAkB,EAAA,MAC7BN,EAASQ,KAAKjI,EAAKkI,SAzCnB,MAAAtE,GAAA+D,GAAA,EAAAC,EAAAhE,EAAA,YAAA8D,GAAA,MAAAI,EAAAjE,QAAAiE,EAAAjE,SAAA,WAAA8D,EAAA,MAAAC,GA2CF1B,EAAOS,YAAY,CAACN,OAAQ,OAAQ5F,MAAOV,EAAGU,MAAO+E,MAAKvF,QAAOyF,aAAY+B,UACtE1H,EAAGU,MACV,MAAOU,GACP8E,EAAO9E,MAlEb,eAAAb,EAAA0B,OAAA,SAAA1B,EAAAoB,MAAA,yBAAApB,EAAA2B,SAAApC,6BAuEe,SAASsI,EAAUrI,EAAK0F,GAErC,sDAAO4C,CAAatI,EC9GP,WACb,IAAMuI,EAAexK,OAAOwK,cAAgBxK,OAAOyK,mBACnD,IAAKD,EACH,MAbK,CACLE,aAAc,kBAAM,GACpBC,gBAAiB,kBAAM,GACvBC,WAAY,aACZC,WAAY,aACZC,WAAY,aACZC,aAAc,cAUhB,IAAMnD,EAAU,IAAI4C,EACdQ,EAAS,IAAIC,IAEnB,MAAO,CACLP,aADK,SACQQ,EAAI7I,EAAM4D,EAAQkF,EAAUC,GAEvC,IADA,IAAMf,EAASzC,EAAQyD,aAAaF,EAAUlF,EAAQmF,GAC7CE,EAAI,EAAGA,EAAIH,IAAYG,EAC9BjB,EAAOkB,cAAclJ,EAAKmJ,SAASF,EAAIrF,EAAQqF,EAAIrF,EAASA,GAASqF,GAEvEN,EAAOhH,IAAIkH,EAAI,CACbb,SACAoB,KAAM7D,EAAQ8D,aACdC,OAAQ,IAAIC,iBAAiBhE,EAAS,CAACiE,IAAK,OAGhDlB,gBAZK,SAYWO,EAAIY,GAClB,IAAMC,EAAMf,EAAOnI,IAAIiJ,GAClBC,GAGLf,EAAOhH,IAAIkH,EAAI,CACbb,OAAQ0B,EAAI1B,OACZoB,KAAM7D,EAAQ8D,aACdC,OAAQ,IAAIC,iBAAiBhE,EAAS,CAACiE,IAAK,OAGhDjB,WAvBK,SAuBMM,EAAIc,EAAQH,EAAKI,GAC1B,IAAMF,EAAMf,EAAOnI,IAAIqI,GACvB,GAAIa,EAAK,CACHA,EAAIG,QACNH,EAAIG,OAAO9H,OAEb2H,EAAIN,KAAKA,KAAKlG,MAAQ4G,KAAKC,IAAI,EAAKJ,EAAS,KAC7C,IAAMK,EAAYF,KAAKC,IAAI,EAAKP,EAAM,KACtCE,EAAIJ,OAAOE,IAAItG,MAAQ,EAAM,GAAO,EAAM8G,GAC1CN,EAAIG,OAAStE,EAAQ0E,qBACrBP,EAAIG,OAAO7B,OAAS0B,EAAI1B,OACxB0B,EAAIG,OAAOD,OAASA,EACpBF,EAAIG,OAAOK,QAAQR,EAAIN,MAAMc,QAAQR,EAAIJ,QAAQY,QAAQ3E,EAAQ4E,aACjET,EAAIG,OAAOO,UAGf5B,WAvCK,SAuCMK,EAAIc,GACb,IAAMD,EAAMf,EAAOnI,IAAIqI,GACnBa,IACFA,EAAIN,KAAKA,KAAKlG,MAAQ4G,KAAKC,IAAI,EAAKJ,EAAS,OAGjDlB,WA7CK,SA6CMI,GACT,IAAMa,EAAMf,EAAOnI,IAAIqI,GACnBa,GAAOA,EAAIG,SACbH,EAAIG,OAAO9H,cACJ2H,EAAIG,SAGfnB,aApDK,SAoDQG,GACX,IAAMa,EAAMf,EAAOnI,IAAIqI,GACnBa,GAAOA,EAAIG,QACbH,EAAIG,OAAO9H,OAEb4G,EAAOjI,OAAOmI,KD2CJwB,GACkB/E,GEzFlC,IAAMgF,EAAa,EACbC,EAAY,EAGZC,EAAO,SAAAtI,GAAA,IAAEuI,EAAFvI,EAAEuI,SAAaC,EAAf/D,OAAAgE,EAAA,EAAAhE,CAAAzE,EAAA,qBAA0B0I,EAAA1K,EAAA2K,cAAA,IAAAlE,OAAAmE,OAAA,CAAGC,OAAO,SAASC,IAAI,uBAA0BN,GAAQD,IAgfjFQ,cAleb,SAAAA,EAAYP,GAAO,IAAAQ,EAAA,OAAAvE,OAAAwE,EAAA,EAAAxE,CAAAlH,KAAAwL,IACjBC,EAAAvE,OAAAyE,EAAA,EAAAzE,CAAAlH,KAAAkH,OAAA0E,EAAA,EAAA1E,CAAAsE,GAAAK,KAAA7L,KAAMiL,KAZRnK,MAAQ,IAAIqI,IAWOsC,EAVnBvM,MAAQ,CAAC4M,SAAS,EAAOC,SAAS,EAAOC,OAAO,EAAOC,SAAU,EAAGC,WAAW,GAU5DT,EATnBU,UAAY,CAACzI,EAAG,EAAGC,EAAG,GASH8H,EAPnBW,aAAe,CAAC,KAAM,KAAM,KAAM,KAAM,KAAM,MAO3BX,EANnBY,SAAW,CAAC,KAAM,KAAM,KAAM,KAAM,KAAM,MAMvBZ,EALnBa,UAAY,EAAC,GAAO,GAAO,GAAO,GAAO,GAAO,GAK7Bb,EAJnBc,UAAY,EAAE,GAAI,GAAI,GAAI,GAAI,GAAI,GAIfd,EAFnBrL,GAAKoM,aAAU,GAEIf,EAyBnBgB,OAAS,SAAAjL,GACP,IAAMnB,EAxDV,SAAqBmB,GACnB,GAAIA,EAAEkL,aAAaC,MACjB,IAAK,IAAInD,EAAI,EAAGA,EAAIhI,EAAEkL,aAAaC,MAAMxI,SAAUqF,EACjD,GAAqC,SAAjChI,EAAEkL,aAAaC,MAAMnD,GAAGoD,KAC1B,OAAOpL,EAAEkL,aAAaC,MAAMnD,GAAGqD,YAGnC,GAAIrL,EAAEkL,aAAa5L,MAAMqD,OACzB,OAAO3C,EAAEkL,aAAa5L,MAAM,GAgDfgM,CAAYtL,GACrBnB,IACFmB,EAAEuL,iBACFtB,EAAKd,MAAMtK,IAEboL,EAAKuB,SAAS,CAACf,SAAU,KA/BRR,EAiCnBwB,YAAc,SAAAzL,GACZA,EAAEuL,iBACFtB,EAAKyB,YAAY,IAnCAzB,EAqCnB0B,WAAa,SAAA3L,IA/Ef,SAAoBA,GAClB,GAAIA,EAAEkL,aAAaC,MACjB,IAAK,IAAInD,EAAI,EAAGA,EAAIhI,EAAEkL,aAAaC,MAAMxI,SAAUqF,EACjD,GAAqC,SAAjChI,EAAEkL,aAAaC,MAAMnD,GAAGoD,KAC1B,OAAO,EAGX,QAAIpL,EAAEkL,aAAa5L,MAAMqD,QAyErBiJ,CAAW5L,IACbA,EAAEuL,kBAvCatB,EA0CnB4B,YAAc,SAAA7L,GACZiK,EAAKyB,aAAa,IA3CDzB,EAgLnB6B,SAAW,WACTC,SAASC,mBAjLQ/B,EAoLnBgC,oBAAsB,WAChBvP,OAAOwP,QAAUxP,OAAOyP,cAAgBzP,OAAOwP,OAAOE,SAAWnC,EAAKoC,kBAExEpC,EAAKqC,KAAK,WAAY,EAAG,EAAG,IAC5BrC,EAAKqC,KAAK,WAAY,EAAG,EAAG,MAxLbrC,EA4LnBsC,YAAc,SAAAvM,GACZ,GAAKiK,EAAKxF,OAAV,CADiB,IAAA+H,EAEFvC,EAAKwC,SAASzM,GAAtBkC,EAFUsK,EAEVtK,EAAGC,EAFOqK,EAEPrK,EACV8H,EAAKqC,KAAK,aAAc,EAAG,EAAGrC,EAAKyC,UAAU1M,GAAIkC,EAAGC,GACpDnC,EAAEuL,mBAhMetB,EAmMnB0C,YAAc,SAAA3M,GACZ,GAAKiK,EAAKxF,OAAV,CADiB,IAAAmI,EAEF3C,EAAKwC,SAASzM,GAAtBkC,EAFU0K,EAEV1K,EAAGC,EAFOyK,EAEPzK,EACNzF,OAAOwP,QAAUxP,OAAOyP,cAAgBzP,OAAOwP,OAAOE,SAEnDnC,EAAKoC,iBACRpC,EAAKxF,OAAOoI,sBAGhB5C,EAAKqC,KAAK,aAAc,EAAGrC,EAAK6C,YAAY9M,GAAIiK,EAAKyC,UAAU1M,GAAIkC,EAAGC,GACtEnC,EAAEuL,mBA7MetB,EAgNnB8C,UAAY,SAAA/M,GACV,GAAKiK,EAAKxF,OAAV,CADe,IAAAuI,EAEA/C,EAAKwC,SAASzM,GAAtBkC,EAFQ8K,EAER9K,EAAGC,EAFK6K,EAEL7K,EACV8H,EAAKqC,KAAK,aAAc,EAAGrC,EAAK6C,YAAY9M,GAAIiK,EAAKyC,UAAU1M,GAAIkC,EAAGC,GACtEnC,EAAEuL,mBApNetB,EAuNnBgD,UAAY,SAAAjN,GACLiK,EAAKxF,SACVwF,EAAKqC,KAAK,WAAY,EAAGrC,EAAKyC,UAAU1M,GAAIA,EAAEkN,SAC1ClN,EAAEkN,SAAW,IAAuB,IAAjBlN,EAAEmN,IAAIxK,SAAiBsH,EAAKmD,cACjDnD,EAAKqC,KAAK,YAAatM,EAAEmN,IAAIE,WAAW,IAE1CpD,EAAKqD,cACArD,EAAKmD,cACU,IAAdpN,EAAEkN,SAA+B,MAAdlN,EAAEkN,SAAiC,MAAdlN,EAAEkN,SAC5ClN,EAAEuL,mBAhOWtB,EAqOnBsD,OAAS,SAAAvN,GACPA,EAAEuL,kBAtOetB,EAyOnBuD,QAAU,SAAAxN,GACHiK,EAAKxF,SACVwF,EAAKqC,KAAK,WAAY,EAAGrC,EAAKyC,UAAU1M,GAAIA,EAAEkN,SAC9CjD,EAAKqD,gBA5OYrD,EAsPnBwD,WAAa,WACX,GAAIxD,EAAKmD,aAAc,KAAAM,EACfxN,EAAO+J,EAAK0D,SAAS1L,MACrB2L,GAAS1N,EAAKrD,MAAM,iBAAmB,IAAIgR,KAAK,IAAIC,UAAU,EAAG,IACnE5N,IAAS0N,IACX3D,EAAK0D,SAAS1L,MAAQ2L,GAExB3D,EAAKqD,cACL,IAAMS,EAASrI,OAAAC,EAAA,EAAAD,CAAIJ,MAAM,KAAK0I,IAAI,SAACC,EAAGjG,GAAJ,OAAUA,EAAI4F,EAAMjL,OAASiL,EAAMP,WAAWrF,GAAK,KACrF0F,EAAAzD,GAAKqC,KAAL/N,MAAAmP,EAAA,CAAU,iBAAV1J,OAAA0B,OAAAC,EAAA,EAAAD,CAA8BqI,OA/Pf9D,EAmQnBiE,UAAY,SAAAlO,GACV,IAAMV,EAAQU,EAAE8J,OAAOxK,MACnBA,EAAMqD,OAAS,GACjBsH,EAAKd,MAAM7J,EAAM,KAtQF2K,EA0QnBkE,YAAc,KA1QKlE,EA2QnBmE,YAAc,KA3QKnE,EA6QnBoE,mBAAqB,WACnBpE,EAAKuB,SAAS,CAAChB,MAAQuB,SAASuC,oBAAsBrE,EAAKsE,WA9Q1CtE,EA2WnBuE,aAAe,SAAAxO,GACb,GAAKiK,EAAKxF,SACVzE,EAAEuL,iBACEtB,EAAKwE,kBAAkBzO,EAAE0O,SAAS,IAAQ,KAAAC,EAC7B1E,EAAKwC,SAASxC,EAAKmE,aAA3BlM,EADqCyM,EACrCzM,EAAGC,EADkCwM,EAClCxM,EACV8H,EAAKqC,KAAK,aAAc,EAAG,EAAGrC,EAAKyC,UAAU1M,GAAIkC,EAAGC,GAC/C8H,EAAKa,UAAUzB,IAClBY,EAAKqC,KAAK,aAAc,EAAGrC,EAAKa,UAAUxB,GAAa,EAAI,EAAGW,EAAKyC,UAAU1M,GAAIkC,EAAGC,KAlXvE8H,EAsXnB2E,YAAc,SAAA5O,GACZ,GAAKiK,EAAKxF,SACVzE,EAAEuL,iBACEtB,EAAKwE,kBAAkBzO,EAAE0O,SAAS,IAAQ,KAAAG,EAC7B5E,EAAKwC,SAASxC,EAAKmE,aAA3BlM,EADqC2M,EACrC3M,EAAGC,EADkC0M,EAClC1M,EACV8H,EAAKqC,KAAK,aAAc,EAAG,EAAGrC,EAAKyC,UAAU1M,GAAIkC,EAAGC,KA3XrC8H,EA8XnB6E,WAAa,SAAA9O,GACX,GAAKiK,EAAKxF,OAAV,CACAzE,EAAEuL,iBACF,IAAMwD,EAAS9E,EAAKmE,YAEpB,GADAnE,EAAKwE,kBAAkBzO,EAAE0O,SAAS,GAC9BK,IAAW9E,EAAKmE,YAAa,KAAAY,EAChB/E,EAAKwC,SAASsC,GAAtB7M,EADwB8M,EACxB9M,EAAGC,EADqB6M,EACrB7M,EACV8H,EAAKqC,KAAK,aAAc,EAAG,EAAGrC,EAAKyC,UAAU1M,GAAIkC,EAAGC,GACpD8H,EAAKqC,KAAK,aAAc,EAAG,EAAGrC,EAAKyC,UAAU1M,GAAIkC,EAAGC,IAEhD8H,EAAKa,UAAUxB,IAAgBW,EAAKkE,aAAelE,EAAKkE,YAAYc,QAAU3F,GAChFW,EAAKiF,eAAe5F,GAAW,GAG9ByC,SAASuC,mBACZrE,EAAKsE,QAAQY,sBA7YElF,EAiZnBmF,UAAY,SAAApP,GAAC,OAAIiK,EAAKxF,OAASzE,GAjZZiK,EAkZnBoF,WAAa,SAAArP,GAAC,OAAIiK,EAAKsE,QAAUvO,GAlZdiK,EAmZnBqF,YAAc,SAAAtP,GAAC,OAAIiK,EAAK0D,SAAW3N,GAhZjCiK,EAAKsF,UAAYtF,EAAKuF,UAAUC,KAAf/J,OAAAgK,EAAA,EAAAhK,CAAAuE,GAA0B,GAC3CA,EAAK0F,UAAY1F,EAAKuF,UAAUC,KAAf/J,OAAAgK,EAAA,EAAAhK,CAAAuE,GAA0B,GAC3CA,EAAK2F,UAAY3F,EAAKuF,UAAUC,KAAf/J,OAAAgK,EAAA,EAAAhK,CAAAuE,GAA0B,GAC3CA,EAAK4F,UAAY5F,EAAK6F,cAAcL,KAAnB/J,OAAAgK,EAAA,EAAAhK,CAAAuE,GAA8B,GAC/CA,EAAK8F,UAAY9F,EAAK6F,cAAcL,KAAnB/J,OAAAgK,EAAA,EAAAhK,CAAAuE,GAA8B,GAC/CA,EAAK+F,UAAY/F,EAAK6F,cAAcL,KAAnB/J,OAAAgK,EAAA,EAAAhK,CAAAuE,GAA8B,GAR9BA,mFAWC,IAAAgG,EAAAzR,KAClBuN,SAAS/G,iBAAiB,OAAQxG,KAAKyM,QAAQ,GAC/Cc,SAAS/G,iBAAiB,WAAYxG,KAAKmN,YAAY,GACvDI,SAAS/G,iBAAiB,YAAaxG,KAAKiN,aAAa,GACzDM,SAAS/G,iBAAiB,YAAaxG,KAAKqN,aAAa,GAEzDrN,KAAKI,GAAGxB,KAAK,SAAAwB,GACX,IAAME,EAAQF,EAAGU,MAAMC,IAAI,aACvBT,GAASA,EAAMU,aAAetB,GAChC+R,EAAKzE,SAAS,CAACd,WAAW,0CAyBpBwF,GACV1R,KAAKgN,SAAS,SAAA2E,GAAA,IAAE1F,EAAF0F,EAAE1F,SAAF,MAAiB,CAACA,SAAU5B,KAAKuH,IAAI3F,EAAWyF,EAAK,sCAG7DhQ,GACN1B,KAAKgN,SAAS,CAACvN,MAAOiC,yCAGXkG,GACPA,GACF5H,KAAK4O,cAAe,EACpB5O,KAAK+P,QAAQ8B,UAAUC,IAAI,YAC3B9R,KAAKmP,SAAS4C,UAEd/R,KAAK4O,cAAe,EACpB5O,KAAK+P,QAAQ8B,UAAUG,OAAO,YAC9BhS,KAAKmP,SAAS8C,6CAILvO,EAAGC,GAAG,IAAAuO,EAAAlS,KACX2E,EAAO3E,KAAKiG,OAAOkM,wBACzBnS,KAAKmM,UAAY,CACfzI,EAAGiB,EAAKyN,MAAQzN,EAAK0N,MAAQ1N,EAAKyN,MAAQ1O,EAAI,IAC9CC,EAAGgB,EAAK2N,KAAO3N,EAAK4N,OAAS5N,EAAK2N,KAAO3O,EAAI,KAE/C6O,WAAW,WACTN,EAAKpE,KAAK,aAAc,EAAG,EAAG,EAAGpK,EAAGC,wCAI7B8O,GACTzS,KAAKgN,SAAS,CAACyF,8CAGRC,EAAKC,GACP3S,KAAKoM,aAAasG,KAGvB1S,KAAKuM,UAAUmG,GAAOC,EAClBA,GAAQ,GACV3S,KAAKoM,aAAasG,GAAKE,MAAMC,QAAU,QACvC7S,KAAKqM,SAASqG,GAAKI,UAAU9S,KAAKiG,OAAQ,IAAM,GAAK0M,EAAM,IAAK,GAAI,GAAI,EAAG,EAAG,GAAI,KAElF3S,KAAKoM,aAAasG,GAAKE,MAAMC,QAAU,2CAIhChQ,GACT,GAAIA,EAAM,CAGR,IAFA,IAAMkQ,EAAO,IAAIC,IACbC,EAAM,EACDzJ,EAAI,EAAGA,EAAI3G,EAAKsB,QAAU8O,EAAM,IAAKzJ,EACxC3G,EAAK2G,IAAM,IAAMuJ,EAAKG,IAAIrQ,EAAK2G,MACjCxJ,KAAKmT,SAASF,IAAOzJ,GACrBuJ,EAAKjB,IAAIjP,EAAK2G,KAGlB,KAAOyJ,EAAM,IAAKA,EAChBjT,KAAKmT,SAASF,GAAM,QAGtBjT,KAAKmT,SAAS,GAAI,GAClBnT,KAAKmT,SAAS,GAAI,GAClBnT,KAAKmT,SAAS,GAAI,iCAIhB9S,GAAM,IAAA+S,EAAApT,KACVuN,SAAS8F,oBAAoB,OAAQrT,KAAKyM,QAAQ,GAClDc,SAAS8F,oBAAoB,WAAYrT,KAAKmN,YAAY,GAC1DI,SAAS8F,oBAAoB,YAAarT,KAAKiN,aAAa,GAC5DM,SAAS8F,oBAAoB,YAAarT,KAAKqN,aAAa,GAC5DrN,KAAKgN,SAAS,CAACf,SAAU,IAEzBjM,KAAKgN,SAAS,CAACjB,SAAS,IAExBvD,EAAUxI,KAAMK,GAAMzB,KAAK,SAAAkP,GACzBsF,EAAKtF,KAAOA,EAEZP,SAAS/G,iBAAiB,YAAa4M,EAAKrF,aAAa,GACzDR,SAAS/G,iBAAiB,YAAa4M,EAAKjF,aAAa,GACzDZ,SAAS/G,iBAAiB,UAAW4M,EAAK7E,WAAW,GACrDhB,SAAS/G,iBAAiB,UAAW4M,EAAK3E,WAAW,GACrDlB,SAAS/G,iBAAiB,QAAS4M,EAAKpE,SAAS,GACjDzB,SAAS/G,iBAAiB,cAAe4M,EAAKrE,QAAQ,GAEtDxB,SAAS/G,iBAAiB,aAAc4M,EAAKpD,aAAc,CAACsD,SAAS,EAAOC,SAAS,IACrFhG,SAAS/G,iBAAiB,YAAa4M,EAAKhD,YAAa,CAACkD,SAAS,EAAOC,SAAS,IACnFhG,SAAS/G,iBAAiB,WAAY4M,EAAK9C,WAAY,CAACgD,SAAS,EAAOC,SAAS,IAEjFhG,SAAS/G,iBAAiB,oBAAqB4M,EAAK3F,qBACpDF,SAAS/G,iBAAiB,mBAAoB4M,EAAKvD,oBACnD3R,OAAOsI,iBAAiB,SAAU4M,EAAK9F,UAEvC8F,EAAKpG,SAAS,CAAClB,SAAS,KACvB,SAAAtK,GAAC,OAAI4R,EAAKvL,QAAQrG,EAAEgS,mDAIvB,OAAOjG,SAASkG,qBAAuBzT,KAAKiG,QAAUsH,SAASmG,wBAA0B1T,KAAKiG,wCAGvFzE,GACP,IAAMmD,EAAO3E,KAAKiG,OAAOkM,wBAOzB,OANInS,KAAK6N,iBACP7N,KAAKmM,UAAUzI,EAAI2G,KAAKuH,IAAIjN,EAAKyN,KAAM/H,KAAKsJ,IAAIhP,EAAK0N,MAAOrS,KAAKmM,UAAUzI,EAAIlC,EAAEoS,YACjF5T,KAAKmM,UAAUxI,EAAI0G,KAAKuH,IAAIjN,EAAK2N,IAAKjI,KAAKsJ,IAAIhP,EAAK4N,OAAQvS,KAAKmM,UAAUxI,EAAInC,EAAEqS,aAEjF7T,KAAKmM,UAAY,CAACzI,EAAGlC,EAAEsS,QAASnQ,EAAGnC,EAAEuS,SAEhC,CACLrQ,EAAG2G,KAAKuH,IAAI,EAAGvH,KAAKsJ,IAAItJ,KAAK2J,OAAOhU,KAAKmM,UAAUzI,EAAIiB,EAAKyN,OAASzN,EAAK0N,MAAQ1N,EAAKyN,MAAQ,KAAM,MACrGzO,EAAG0G,KAAKuH,IAAI,EAAGvH,KAAKsJ,IAAItJ,KAAK2J,OAAOhU,KAAKmM,UAAUxI,EAAIgB,EAAK2N,MAAQ3N,EAAK4N,OAAS5N,EAAK2N,KAAO,KAAM,2CAI5F9Q,GACV,OAAQA,EAAEyS,QACV,KAAK,EAAG,OAAO,EACf,KAAK,EAAG,OAAO,EACf,KAAK,EAAG,OAAO,EACf,KAAK,EAAG,OAAO,EACf,KAAK,EAAG,OAAO,EACf,QAAS,OAAO,qCAGRzS,GACR,OAASA,EAAE0S,UAAYlU,KAAKsM,UA7LZ,GA6LsC,EAAI,IAAM9K,EAAE2S,QAAU,EAAI,IAAM3S,EAAE4S,OAAS,EAAI,IAAM5S,EAAE0O,QAAU,EAAI,yCAmE3H,GAAIlQ,KAAK4O,aAAc,CACrB,IAAMyF,EAAMrU,KAAKmP,SAAS1L,MAAMU,OAChCnE,KAAKmP,SAASmF,kBAAkBD,EAAKA,wCA+B7B5D,EAAOhN,EAAO8Q,GACxB,GAAI9D,EAAQ,EACVzQ,KAAKsM,UAAUmE,GAAShN,EACpBzD,KAAKoM,aAAaqE,IACpBzQ,KAAKoM,aAAaqE,GAAOoB,UAAU2C,OAAO,SAAU/Q,QAEjD,GAAI8Q,GAAOvU,KAAKuM,UAAUkE,IAAU,EAAG,CAC5C,IAAMgE,EAAMC,YAAYD,QACnBzU,KAAK2U,UAAYF,EAAMzU,KAAK2U,SAAW,OAC1C3U,KAAK8N,KAAK,YAAa,GAAK9N,KAAKuM,UAAUkE,IAC3CzQ,KAAK2U,SAAWF,8CAKJvE,EAAS0E,GAAS,IAAAC,EAAA7U,KAC9B8U,EAAa,KACXC,EAAM/U,KAAK2P,YAFiB5M,GAAA,EAAAC,GAAA,EAAAC,OAAAC,EAAA,IAGlC,IAHkC,IAGlCC,EAHkC6R,EAAA,eAAAC,EAAA9R,EAAAM,MAGxB6H,EAHwB2J,EAGxB3J,OAAQ4J,EAHgBD,EAGhBC,WAAYpB,EAHImB,EAGJnB,QAASC,EAHLkB,EAGKlB,QACrC,GAAIgB,GAAOA,EAAI3L,KAAO8L,GAAcL,EAAKzI,aAAa2I,EAAItE,SAAWnF,EAWnE,OAVI4E,EAAQ/L,OAAS,IACnB4Q,EAAII,OAAQ,GAEdJ,EAAIjB,QAAUA,EACdiB,EAAIhB,QAAUA,EACdc,EAAKjF,YAAc1I,OAAAC,EAAA,EAAAD,CAAIgJ,GAASkF,KAAK,SAAAC,GAAC,OAAIA,EAAEH,aAAeA,IACvDL,EAAKjF,cACPiF,EAAKjF,YAAc,CAACkE,QAASe,EAAKjF,YAAYkE,QAASC,QAASc,EAAKjF,YAAYmE,iBAE5Ec,EAAKS,OACZ,CAAAC,EAA2B,MAApBV,EAAKjF,aAEd,IAAM8C,EAAMmC,EAAKzI,aAAaoJ,QAAQlK,GAClCoH,GAAO,IAAMoC,IACfA,EAAa,CAAC1L,GAAI8L,EAAYzE,MAAOiC,EAAKyC,OAAO,EAAMM,SAAUZ,EAAKvI,UAAUoG,GAAMoB,UAASC,aAhBnG3Q,EAAmD8M,EAAnD7M,OAAAC,cAAAP,GAAAI,EAAAC,EAAAvC,QAAA0C,MAAAR,GAAA,EAA4D,KAAA2S,EAAAV,IAAA,qBAAAU,EAAA,OAAAA,EAAAH,GAH1B,MAAAtR,GAAAjB,GAAA,EAAAC,EAAAgB,EAAA,YAAAlB,GAAA,MAAAK,EAAAc,QAAAd,EAAAc,SAAA,WAAAlB,EAAA,MAAAC,GAsBlC,GAAI8R,IAAQD,GAAcF,GAAWG,EAAII,MAAO,CAC9C,IAAMxQ,EAAO3E,KAAKoM,aAAa2I,EAAItE,OAAO0B,wBACnC2B,EAAoBiB,EAApBjB,QAASC,EAAWgB,EAAXhB,QACZD,GAAWnP,EAAKyN,MAAQ0B,EAAUnP,EAAK0N,OAAS0B,GAAWpP,EAAK2N,KAAOyB,EAAUpP,EAAK4N,OACxFvS,KAAK2V,YAAYZ,EAAItE,OAAQsE,EAAIU,UAAU,GAE3CzV,KAAK2V,YAAYZ,EAAItE,MAAOsE,EAAIU,eAEzBV,GACT/U,KAAK2V,YAAYZ,EAAItE,OAAO,GAG9B,GADAzQ,KAAK2P,YAAcmF,EACfA,EACF9U,KAAK2V,YAAYb,EAAWrE,OAAO,GAC/BqE,EAAWrE,QAAU5F,EACvB7K,KAAK2V,YAAY7K,GAAW,GACnBgK,EAAWrE,QAAU3F,GAC9B9K,KAAK2V,YAAY9K,GAAY,UAExB7K,KAAKsV,WACP,IAAuB,IAAnBpF,EAAQ/L,OAAc,CAC/B,IAAMT,GAAKwM,EAAQ,GAAG4D,QAAU5D,EAAQ,GAAG4D,SAAW,EAAGnQ,GAAKuM,EAAQ,GAAG6D,QAAU7D,EAAQ,GAAG6D,SAAW,EACzG,GAAI/T,KAAKsV,OAAQ,CACf,IAGM3G,EAHAiH,EAAKlS,EAAI1D,KAAKsV,OAAO5R,EAAGmS,EAAKlS,EAAI3D,KAAKsV,OAAO3R,EAC7CmS,EAAO9V,KAAKiG,OAAO8P,aAAe,GACxC,GAAI1L,KAAKuH,IAAIvH,KAAK2L,IAAIJ,GAAKvL,KAAK2L,IAAIH,IAAOC,EAGvCnH,EADEtE,KAAK2L,IAAIJ,GAAMvL,KAAK2L,IAAIH,GACnBD,EAAK,EAAI,GAAO,GAEhBC,EAAK,EAAI,GAAO,GAEzB7V,KAAK8N,KAAK,WAAY,EAAG,EAAGa,GAE5B3O,KAAKsV,OAAS,CAAC5R,IAAGC,UAGpB3D,KAAK8N,KAAK,aAAc,EAAG,EAAG,GAAI,IAAK,KACvC9N,KAAK8N,KAAK,aAAc,EAAG,EAAG,GAAI,IAAK,KACvC9N,KAAKsV,OAAS,CAAC5R,IAAGC,KAGpB,OADA3D,KAAK4P,YAAc,MACZ,SAEA5P,KAAKsV,OAMd,OAJAtV,KAAK4P,YAAc1I,OAAAC,EAAA,EAAAD,CAAIgJ,GAASkF,KAAK,SAAAC,GAAC,OAAKP,GAAcO,EAAEH,aAAeJ,EAAW1L,KACjFpJ,KAAK4P,cACP5P,KAAK4P,YAAc,CAACkE,QAAS9T,KAAK4P,YAAYkE,QAASC,QAAS/T,KAAK4P,YAAYmE,UAExD,MAApB/T,KAAK4P,8CA4CJpG,EAAGhI,GACXxB,KAAKoM,aAAa5C,GAAKhI,wCAEXgI,EAAGhI,GAEf,GADAxB,KAAKoM,aAAa5C,GAAKhI,EACnBA,EAAG,CACL,IAAMyE,EAASsH,SAASnC,cAAc,UACtCnF,EAAOgQ,MAAQ,GACfhQ,EAAO2H,OAAS,GAChBpM,EAAE0U,YAAYjQ,GACdjG,KAAKqM,SAAS7C,GAAKvD,EAAOC,WAAW,WAErClG,KAAKqM,SAAS7C,GAAK,sCAId,IAAA2M,EAAAnW,KAAAoW,EACiEpW,KAAKd,MAAtE4M,EADAsK,EACAtK,QAASC,EADTqK,EACSrK,QAAStM,EADlB2W,EACkB3W,MAAOgT,EADzB2D,EACyB3D,SAAUxG,EADnCmK,EACmCnK,SAAUD,EAD7CoK,EAC6CpK,MAAOE,EADpDkK,EACoDlK,UAC3D,OACEf,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAWC,IAAW,MAAO,CAACtK,QAAOF,UAASG,WAAUkD,SAAUnP,KAAK4O,eAAgB2H,IAAKvW,KAAK6Q,YACpG1F,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAU,uBACblL,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAWC,IAAW,eAAgB,iBAAkB,CAACE,OAAQxW,KAAKsM,UAAU,KAAMiK,IAAKvW,KAAK+Q,YACrG5F,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAWC,IAAW,eAAgB,iBAAkB,CAACE,OAAQxW,KAAKsM,UAAU,KAAMiK,IAAKvW,KAAKmR,YACrGhG,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAWC,IAAW,eAAgB,iBAAkB,CAACE,OAAQxW,KAAKsM,UAAU,KAAMiK,IAAKvW,KAAKoR,aAEvGjG,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAU,uBACblL,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAWC,IAAW,eAAgB,kBAAmBC,IAAKvW,KAAKqR,YACxElG,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAWC,IAAW,eAAgB,kBAAmBC,IAAKvW,KAAKuR,YACxEpG,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAWC,IAAW,eAAgB,kBAAmBC,IAAKvW,KAAKwR,aAE1ErG,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAU,SACX5W,GAAS0L,EAAA1K,EAAA2K,cAAA,UAAQmL,IAAKvW,KAAK4Q,UAAWqF,MAAO,IAAKrI,OAAQ,MAC5DzC,EAAA1K,EAAA2K,cAAA,SAAOqL,KAAK,OAAOJ,UAAU,WAAWK,SAAU1W,KAAKiP,WAAYsH,IAAKvW,KAAK8Q,YAAa6F,YAAY,KAExGxL,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAU,WACV5W,GACD0L,EAAA1K,EAAA2K,cAACwL,EAAD,CAAMP,UAAU,QAAQQ,KAAK,8CAC3B1L,EAAA1K,EAAA2K,cAAA,KAAGiL,UAAU,UAAb,qCACAlL,EAAA1K,EAAA2K,cAAA,KAAGiL,UAAU,QAAQ5W,GACrB0L,EAAA1K,EAAA2K,cAAA,KAAGiL,UAAU,UAAb,mCAGDtK,IAAYD,IAAYrM,GACzB0L,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAU,WACX5D,GAAYA,EAAS/Q,MAAS,aACnB,MAAZ+Q,KAAsBA,EAAS7Q,OAC9BuJ,EAAA1K,EAAA2K,cAAA,QAAMiL,UAAU,eAAclL,EAAA1K,EAAA2K,cAAA,YAAMD,EAAA1K,EAAA2K,cAAA,QAAMwH,MAAO,CAACqD,MAAK,GAAAzQ,OAAK6E,KAAK2J,MAAM,IAAMvB,EAAS9Q,OAAS8Q,EAAS7Q,OAAjD,YAI3DkK,IAAYC,IAAYtM,GACxB0L,EAAA1K,EAAA2K,cAAA,OAAKiL,UAAU,SACblL,EAAA1K,EAAA2K,cAAA,kIAEkCD,EAAA1K,EAAA2K,cAACwL,EAAD,CAAMC,KAAK,6CAAX,8CAElC1L,EAAA1K,EAAA2K,cAAA,0KAEiCD,EAAA1K,EAAA2K,cAACwL,EAAD,CAAMC,KAAK,mCAAX,OAFjC,MAIE3K,GACAf,EAAA1K,EAAA2K,cAAA,4EAIFD,EAAA1K,EAAA2K,cAAA,YACED,EAAA1K,EAAA2K,cAAA,SAAO0L,QAAQ,WAAWT,UAAU,eAApC,cACAlL,EAAA1K,EAAA2K,cAAA,SAAO2L,OAAO,OAAON,KAAK,OAAOrN,GAAG,WAAWwJ,MAAO,CAACC,QAAS,QAAS6D,SAAU1W,KAAK0P,aAE1FvE,EAAA1K,EAAA2K,cAAA,QAAMiL,UAAU,cAAcW,QAAS,kBAAMb,EAAKxL,UAAlD,4BAreIsM,IAAMC,WC/BxBC,IAASC,OAAOjM,EAAA1K,EAAA2K,cAACiM,EAAD,MAAS9J,SAAS+J,eAAe,SLe1C,SAAkB9Y,GACvB,GAA6C,kBAAmBC,UAAW,CAGzE,GADkB,IAAI8Y,IAAIlW,aAAwBnD,OAAOC,SAAS0Y,MACpDW,SAAWtZ,OAAOC,SAASqZ,OAIvC,OAGFtZ,OAAOsI,iBAAiB,OAAQ,WAC9B,IAAMjI,EAAK,GAAAiH,OAAMnE,aAAN,sBAEPrD,GAgEV,SAAiCO,EAAOC,GAEtCiZ,MAAMlZ,GACHK,KAAK,SAAA8Y,GAEJ,IAAMC,EAAcD,EAAS7V,QAAQd,IAAI,gBAEnB,MAApB2W,EAASE,QACO,MAAfD,IAA8D,IAAvCA,EAAYnC,QAAQ,cAG5C/W,UAAUC,cAAcmZ,MAAMjZ,KAAK,SAAAC,GACjCA,EAAaiZ,aAAalZ,KAAK,WAC7BV,OAAOC,SAAS4Z,aAKpBzZ,EAAgBC,EAAOC,KAG1BgB,MAAM,WACLJ,QAAQC,IACN,mEArFA2Y,CAAwBzZ,EAAOC,GAI/BC,UAAUC,cAAcmZ,MAAMjZ,KAAK,WACjCQ,QAAQC,IACN,gHAMJf,EAAgBC,EAAOC,MKzC/BE,qHCPMuZ,EAAgB,kBAAM,IAAI7R,QAAQ,SAACC,EAASC,GAChD,IAAI/C,GAAO,EACL2U,EAAQ3K,SAASnC,cAAc,UACrClN,OAAOsI,iBAAiB,UAAW,SAAA/D,GAAY,IAAVlC,EAAUkC,EAAVlC,KACf,YAAhBA,EAAK4X,QAAyB5U,IAChCA,GAAO,EACP8C,EAAQ9F,EAAKO,OACboX,EAAME,cAAcpR,YAAY,CAACmR,OAAQ,SAAU,QAGvDD,EAAM1R,iBAAiB,OAAQ,WAC7B0R,EAAME,cAAcpR,YAAY,CAACmR,OAAQ,YAAa,OAExDD,EAAM1R,iBAAiB,QAAS,WACzBjD,IACHA,GAAO,EACP8C,EAAQ,SAGZ6R,EAAMjO,IAAM,0CACZiO,EAAMtF,MAAMC,QAAU,OACtBtF,SAAS8K,KAAKnC,YAAYgC,GAC1B1F,WAAW,WACJjP,IACHA,GAAO,EACP8C,EAAQ,QAET,iBAGUiS,iFAAf,SAAApY,EAA4BqY,EAAOvS,GAAnC,IAAA3F,EAAAmY,EAAApX,EAAAqX,EAAA,OAAAC,EAAAjY,EAAAC,KAAA,SAAAC,GAAA,cAAAA,EAAAC,KAAAD,EAAAE,MAAA,cAAAF,EAAAE,KAAA,EACqB0X,EAAMxX,IAAIiF,EAAK2S,eADpC,QACQtY,EADRM,EAAAoB,OAGUyW,EAAO,IAAII,KAAK,CAACvY,GAAO,CAACoW,KAAM,wBAC/BrV,EAAMmW,IAAIsB,gBAAgBL,IAC1BC,EAAMlL,SAASnC,cAAc,MAC/B0N,aAAa,OAAQ1X,GACzBqX,EAAIK,aAAa,WAAY9S,GAC7BuH,SAAS8K,KAAKnC,YAAYuC,GAC1BA,EAAIM,QACJxL,SAAS8K,KAAKW,YAAYP,GAC1BlB,IAAI0B,gBAAgB7X,IAEpBhC,QAAQK,MAAR,QAAA+F,OAAsBQ,EAAtB,oBAbJ,wBAAArF,EAAA2B,SAAApC,6BAiBe,SAAesM,EAA9B0M,GAAA,OAAAC,EAAApZ,MAAAC,KAAAC,sDAAe,SAAAmZ,EAAyBC,GAAzB,IAAAd,EAAAzX,EAAAwY,EAAAC,EAAAC,EAAAvE,EAAAwE,EAAAC,EAAAC,EAAA5W,EAAAC,EAAAC,EAAAG,EAAAD,EAAAsD,EAAAjD,EAAAwC,EAAAzF,EAAA,OAAAmY,EAAAjY,EAAAC,KAAA,SAAAkZ,GAAA,cAAAA,EAAAhZ,KAAAgZ,EAAA/Y,MAAA,cAAA+Y,EAAAhZ,KAAA,EAEL2X,EAAQ,IAAIsB,IAAW,aACvB/Y,EAAQ,IAAIqI,IAHPmQ,EAAA,EAAAM,EAAAE,GAIc5S,OAJd0S,EAAA/Y,KAAA,EAImC0X,EAAMwB,OAJzC,OAAAH,EAAAI,GAAAJ,EAAA7X,KAAAwX,EAAAK,EAAAE,GAIqBG,QAJrBpO,KAAA+N,EAAAE,GAAAF,EAAAI,IAAA,YAAAV,EAAAC,EAAApV,QAAA,CAAAyV,EAAA/Y,KAAA,SAAA2Y,EAAAD,EAAAD,GAAArE,EAAA/N,OAAAgT,EAAA,EAAAhT,CAAAsS,EAAA,GAIDxT,EAJCiP,EAAA,GAIK1U,EAJL0U,EAAA,GAKTnU,EAAMoB,IAAI8D,EAAMzF,GALP,QAAA+Y,IAAAM,EAAA/Y,KAAA,oBAOPwY,EAPO,CAAAO,EAAA/Y,KAAA,gBAAA+Y,EAAA/Y,KAAA,GAQWoX,IARX,aAQHnX,EARG8Y,EAAA7X,MAAA,CAAA6X,EAAA/Y,KAAA,SAUP,IAVOkC,GAAA,EAAAC,GAAA,EAAAC,OAAAC,EAAA0W,EAAAhZ,KAAA,GAUPwC,EAAyBtC,EAAzBuC,OAAAC,cAAAP,GAAAI,EAAAC,EAAAvC,QAAA0C,MAAAR,GAAA,EAAgC0D,EAAAtD,EAAAM,MAAAD,EAAA0D,OAAAgT,EAAA,EAAAhT,CAAAT,EAAA,GAAtBT,EAAsBxC,EAAA,GAAhBjD,EAAgBiD,EAAA,GAC9B1C,EAAMoB,IAAI8D,EAAMzF,GAChBgY,EAAMrW,IAAI8D,EAAMzF,GAZXqZ,EAAA/Y,KAAA,iBAAA+Y,EAAAhZ,KAAA,GAAAgZ,EAAAO,GAAAP,EAAA,UAAA5W,GAAA,EAAAC,EAAA2W,EAAAO,GAAA,QAAAP,EAAAhZ,KAAA,GAAAgZ,EAAAhZ,KAAA,GAAAmC,GAAA,MAAAK,EAAAc,QAAAd,EAAAc,SAAA,WAAA0V,EAAAhZ,KAAA,IAAAoC,EAAA,CAAA4W,EAAA/Y,KAAA,eAAAoC,EAAA,eAAA2W,EAAAQ,OAAA,mBAAAR,EAAAQ,OAAA,mBAgBXlc,OAAOmc,aAAe,SAAArU,GAAI,OAAIsS,EAAaC,EAAOvS,IAhBvC4T,EAAAvX,OAAA,SAiBJ,CACLvB,QACAqB,OAAQ,SAAC6D,EAAMzF,GAAP,OAAgBgY,EAAMrW,IAAI8D,EAAMzF,IACxCU,OAAQ,SAAA+E,GAAI,OAAIuS,EAAMvG,OAAOhM,IAC7BsU,MAAO,kBAAM/B,EAAM+B,WArBV,eAAAV,EAAAhZ,KAAA,GAAAgZ,EAAAW,GAAAX,EAAA,SAwBX1b,OAAOmc,aAAe,kBAAMjb,QAAQK,MAAM,+BAxB/Bma,EAAAvX,OAAA,SAyBJ,CACLvB,MAAO,IAAIqI,IACXhH,OAAQ,kBAAMiE,QAAQC,WACtBpF,OAAQ,kBAAMmF,QAAQC,WACtBiU,MAAO,kBAAMlU,QAAQC,aA7BZ,yBAAAuT,EAAAtX,SAAA8W,EAAA","file":"static/js/main.21ca9033.chunk.js","sourcesContent":["module.exports = function() {\n return new Worker(__webpack_public_path__ + \"54277a9e96a084857713.worker.js\");\n};","// This optional code is used to register a service worker.\r\n// register() is not called by default.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on subsequent visits to a page, after all the\r\n// existing tabs open on the page have been closed, since previously cached\r\n// resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model and instructions on how to\r\n// opt-in, read https://bit.ly/CRA-PWA\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.1/8 is considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\nexport function register(config) {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Let's check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, config);\r\n\r\n // Add some additional logging to localhost, pointing developers to the\r\n // service worker/PWA documentation.\r\n navigator.serviceWorker.ready.then(() => {\r\n console.log(\r\n 'This web app is being served cache-first by a service ' +\r\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\r\n );\r\n });\r\n } else {\r\n // Is not localhost. Just register service worker\r\n registerValidSW(swUrl, config);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl, config) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n if (installingWorker == null) {\r\n return;\r\n }\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the updated precached content has been fetched,\r\n // but the previous service worker will still serve the older\r\n // content until all client tabs are closed.\r\n console.log(\r\n 'New content is available and will be used when all ' +\r\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\r\n );\r\n\r\n // Execute callback\r\n if (config && config.onUpdate) {\r\n config.onUpdate(registration);\r\n }\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n\r\n // Execute callback\r\n if (config && config.onSuccess) {\r\n config.onSuccess(registration);\r\n }\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl, config) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl)\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n const contentType = response.headers.get('content-type');\r\n if (\r\n response.status === 404 ||\r\n (contentType != null && contentType.indexOf('javascript') === -1)\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, config);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister();\r\n });\r\n }\r\n}\r\n","import axios from 'axios';\r\n\r\nconst SpawnSize = 50274091;\r\n\r\nexport { SpawnSize };\r\n\r\nexport default async function load_spawn(api, fs) {\r\n let file = fs.files.get('spawn.mpq');\r\n if (file && file.byteLength !== SpawnSize) {\r\n fs.files.delete('spawn.mpq');\r\n await fs.delete('spawn.mpq');\r\n file = null;\r\n }\r\n if (!file) {\r\n const spawn = await axios.request({\r\n url: process.env.PUBLIC_URL + '/spawn.mpq',\r\n responseType: 'arraybuffer',\r\n onDownloadProgress: e => {\r\n if (api.onProgress) {\r\n api.onProgress({text: 'Downloading...', loaded: e.loaded, total: e.total || SpawnSize});\r\n }\r\n },\r\n headers: {\r\n 'Cache-Control': 'max-age=31536000'\r\n }\r\n });\r\n if (spawn.data.byteLength !== SpawnSize) {\r\n throw Error(\"Invalid spawn.mpq size. Try clearing cache and refreshing the page.\");\r\n }\r\n const data = new Uint8Array(spawn.data);\r\n fs.files.set('spawn.mpq', data);\r\n fs.update('spawn.mpq', data.slice());\r\n }\r\n return fs;\r\n}\r\n","import Worker from './game.worker.js';\r\nimport init_sound from './sound';\r\nimport load_spawn from './load_spawn';\r\n\r\nfunction onRender(api, ctx, {bitmap, images, text, clip, belt}) {\r\n if (bitmap) {\r\n ctx.transferFromImageBitmap(bitmap);\r\n } else {\r\n for (let {x, y, w, h, data} of images) {\r\n const image = ctx.createImageData(w, h);\r\n image.data.set(data);\r\n ctx.putImageData(image, x, y);\r\n }\r\n if (text.length) {\r\n ctx.save();\r\n ctx.font = 'bold 13px Times New Roman';\r\n if (clip) {\r\n const {x0, y0, x1, y1} = clip;\r\n ctx.beginPath();\r\n ctx.rect(x0, y0, x1 - x0, y1 - y0);\r\n ctx.clip();\r\n }\r\n for (let {x, y, text: str, color} of text) {\r\n const r = ((color >> 16) & 0xFF);\r\n const g = ((color >> 8) & 0xFF);\r\n const b = (color & 0xFF);\r\n ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;\r\n ctx.fillText(str, x, y + 22);\r\n }\r\n ctx.restore();\r\n }\r\n }\r\n\r\n api.updateBelt(belt);\r\n}\r\n\r\nfunction testOffscreen() {\r\n return false;\r\n /*try {\r\n const canvas = document.createElement(\"canvas\");\r\n const offscreen = canvas.transferControlToOffscreen();\r\n const context = offscreen.getContext(\"2d\");\r\n return context != null;\r\n } catch (e) {\r\n return false;\r\n }*/\r\n}\r\n\r\nasync function do_load_game(api, audio, mpq) {\r\n const fs = await api.fs;\r\n let spawn = true;\r\n if (mpq) {\r\n if (!mpq.name.match(/^spawn\\.mpq$/i)) {\r\n spawn = false;\r\n fs.files.delete('spawn.mpq');\r\n }\r\n } else {\r\n await load_spawn(api, fs);\r\n }\r\n\r\n let context = null, offscreen = false;\r\n if (testOffscreen()) {\r\n context = api.canvas.getContext(\"bitmaprenderer\");\r\n offscreen = true;\r\n } else {\r\n context = api.canvas.getContext(\"2d\", {alpha: false});\r\n }\r\n return await new Promise((resolve, reject) => {\r\n try {\r\n const worker = new Worker();\r\n worker.addEventListener(\"message\", ({data}) => {\r\n switch (data.action) {\r\n case \"loaded\":\r\n resolve((func, ...params) => worker.postMessage({action: \"event\", func, params}));\r\n break;\r\n case \"render\":\r\n onRender(api, context, data.batch);\r\n break;\r\n case \"audio\":\r\n audio[data.func](...data.params);\r\n break;\r\n case \"audioBatch\":\r\n for (let {func, params} of data.batch) {\r\n audio[func](...params);\r\n }\r\n break;\r\n case \"fs\":\r\n fs[data.func](...data.params);\r\n break;\r\n case \"cursor\":\r\n api.setCursorPos(data.x, data.y);\r\n break;\r\n case \"keyboard\":\r\n api.openKeyboard(data.open);\r\n break;\r\n case \"error\":\r\n api.onError(data.error);\r\n break;\r\n case \"failed\":\r\n reject(Error(data.error));\r\n break;\r\n case \"progress\":\r\n api.onProgress({text: data.text, loaded: data.loaded, total: data.total});\r\n break;\r\n default:\r\n }\r\n });\r\n const transfer= [];\r\n for (let [, file] of fs.files) {\r\n transfer.push(file.buffer);\r\n }\r\n worker.postMessage({action: \"init\", files: fs.files, mpq, spawn, offscreen}, transfer);\r\n delete fs.files;\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n}\r\n\r\nexport default function load_game(api, mpq) {\r\n const audio = init_sound();\r\n return do_load_game(api, audio, mpq);\r\n}\r\n","function no_sound() {\r\n return {\r\n create_sound: () => 0,\r\n duplicate_sound: () => 0,\r\n play_sound: () => undefined,\r\n set_volume: () => undefined,\r\n stop_sound: () => undefined,\r\n delete_sound: () => undefined,\r\n };\r\n}\r\n\r\nexport default function init_sound() {\r\n const AudioContext = window.AudioContext || window.webkitAudioContext;\r\n if (!AudioContext) {\r\n return no_sound();\r\n }\r\n\r\n const context = new AudioContext();\r\n const sounds = new Map();\r\n\r\n return {\r\n create_sound(id, data, length, channels, rate) {\r\n const buffer = context.createBuffer(channels, length, rate);\r\n for (let i = 0; i < channels; ++i) {\r\n buffer.copyToChannel(data.subarray(i * length, i * length + length), i);\r\n }\r\n sounds.set(id, {\r\n buffer,\r\n gain: context.createGain(),\r\n panner: new StereoPannerNode(context, {pan: 0}),\r\n });\r\n },\r\n duplicate_sound(id, srcId) {\r\n const src = sounds.get(srcId);\r\n if (!src) {\r\n return;\r\n }\r\n sounds.set(id, {\r\n buffer: src.buffer,\r\n gain: context.createGain(),\r\n panner: new StereoPannerNode(context, {pan: 0}),\r\n });\r\n },\r\n play_sound(id, volume, pan, loop) {\r\n const src = sounds.get(id);\r\n if (src) {\r\n if (src.source) {\r\n src.source.stop();\r\n }\r\n src.gain.gain.value = Math.pow(2.0, volume / 1000.0);\r\n const relVolume = Math.pow(2.0, pan / 1000.0);\r\n src.panner.pan.value = 1.0 - 2.0 / (1.0 + relVolume);\r\n src.source = context.createBufferSource();\r\n src.source.buffer = src.buffer;\r\n src.source.loop = !!loop;\r\n src.source.connect(src.gain).connect(src.panner).connect(context.destination);\r\n src.source.start();\r\n }\r\n },\r\n set_volume(id, volume) {\r\n const src = sounds.get(id);\r\n if (src) {\r\n src.gain.gain.value = Math.pow(2.0, volume / 1000.0);\r\n }\r\n },\r\n stop_sound(id) {\r\n const src = sounds.get(id);\r\n if (src && src.source) {\r\n src.source.stop();\r\n delete src.source;\r\n }\r\n },\r\n delete_sound(id) {\r\n const src = sounds.get(id);\r\n if (src && src.source) {\r\n src.source.stop();\r\n }\r\n sounds.delete(id);\r\n },\r\n };\r\n}\r\n","import React from 'react';\r\nimport './App.scss';\r\nimport classNames from 'classnames';\r\n\r\nimport create_fs from './fs';\r\nimport load_game from './api/loader';\r\nimport { SpawnSize } from './api/load_spawn';\r\n\r\nfunction isDropFile(e) {\r\n if (e.dataTransfer.items) {\r\n for (let i = 0; i < e.dataTransfer.items.length; ++i) {\r\n if (e.dataTransfer.items[i].kind === \"file\") {\r\n return true;\r\n }\r\n }\r\n } if (e.dataTransfer.files.length) {\r\n return true;\r\n }\r\n return false;\r\n}\r\nfunction getDropFile(e) {\r\n if (e.dataTransfer.items) {\r\n for (let i = 0; i < e.dataTransfer.items.length; ++i) {\r\n if (e.dataTransfer.items[i].kind === \"file\") {\r\n return e.dataTransfer.items[i].getAsFile();\r\n }\r\n }\r\n } if (e.dataTransfer.files.length) {\r\n return e.dataTransfer.files[0];\r\n }\r\n}\r\n\r\nconst TOUCH_MOVE = 0;\r\nconst TOUCH_RMB = 1;\r\nconst TOUCH_SHIFT = 2;\r\n\r\nconst Link = ({children, ...props}) => {children};\r\n\r\nclass App extends React.Component {\r\n files = new Map();\r\n state = {started: false, loading: false, touch: false, dropping: 0, has_spawn: false};\r\n cursorPos = {x: 0, y: 0};\r\n\r\n touchButtons = [null, null, null, null, null, null];\r\n touchCtx = [null, null, null, null, null, null];\r\n touchMods = [false, false, false, false, false, false];\r\n touchBelt = [-1, -1, -1, -1, -1, -1];\r\n\r\n fs = create_fs(true);\r\n\r\n constructor(props) {\r\n super(props);\r\n\r\n this.setTouch0 = this.setTouch_.bind(this, 0);\r\n this.setTouch1 = this.setTouch_.bind(this, 1);\r\n this.setTouch2 = this.setTouch_.bind(this, 2);\r\n this.setTouch3 = this.setTouchBelt_.bind(this, 3);\r\n this.setTouch4 = this.setTouchBelt_.bind(this, 4);\r\n this.setTouch5 = this.setTouchBelt_.bind(this, 5);\r\n }\r\n\r\n componentDidMount() {\r\n document.addEventListener(\"drop\", this.onDrop, true);\r\n document.addEventListener(\"dragover\", this.onDragOver, true);\r\n document.addEventListener(\"dragenter\", this.onDragEnter, true);\r\n document.addEventListener(\"dragleave\", this.onDragLeave, true);\r\n\r\n this.fs.then(fs => {\r\n const spawn = fs.files.get('spawn.mpq');\r\n if (spawn && spawn.byteLength === SpawnSize) {\r\n this.setState({has_spawn: true});\r\n }\r\n });\r\n }\r\n\r\n onDrop = e => {\r\n const file = getDropFile(e);\r\n if (file) {\r\n e.preventDefault();\r\n this.start(file);\r\n }\r\n this.setState({dropping: 0});\r\n }\r\n onDragEnter = e => {\r\n e.preventDefault();\r\n this.setDropping(1);\r\n }\r\n onDragOver = e => {\r\n if (isDropFile(e)) {\r\n e.preventDefault();\r\n }\r\n }\r\n onDragLeave = e => {\r\n this.setDropping(-1);\r\n }\r\n setDropping(inc) {\r\n this.setState(({dropping}) => ({dropping: Math.max(dropping + inc, 0)}));\r\n }\r\n\r\n onError(text) {\r\n this.setState({error: text});\r\n }\r\n\r\n openKeyboard(open) {\r\n if (open) {\r\n this.showKeyboard = true;\r\n this.element.classList.add(\"keyboard\");\r\n this.keyboard.focus();\r\n } else {\r\n this.showKeyboard = false;\r\n this.element.classList.remove(\"keyboard\");\r\n this.keyboard.blur();\r\n }\r\n }\r\n\r\n setCursorPos(x, y) {\r\n const rect = this.canvas.getBoundingClientRect();\r\n this.cursorPos = {\r\n x: rect.left + (rect.right - rect.left) * x / 640,\r\n y: rect.top + (rect.bottom - rect.top) * y / 480,\r\n };\r\n setTimeout(() => {\r\n this.game(\"DApi_Mouse\", 0, 0, 0, x, y);\r\n });\r\n }\r\n\r\n onProgress(progress) {\r\n this.setState({progress});\r\n }\r\n\r\n drawBelt(idx, slot) {\r\n if (!this.touchButtons[idx]) {\r\n return;\r\n }\r\n this.touchBelt[idx] = slot;\r\n if (slot >= 0) {\r\n this.touchButtons[idx].style.display = \"block\";\r\n this.touchCtx[idx].drawImage(this.canvas, 205 + 29 * slot, 357, 28, 28, 0, 0, 28, 28);\r\n } else {\r\n this.touchButtons[idx].style.display = \"none\";\r\n }\r\n }\r\n\r\n updateBelt(belt) {\r\n if (belt) {\r\n const used = new Set();\r\n let pos = 3;\r\n for (let i = 0; i < belt.length && pos < 6; ++i) {\r\n if (belt[i] >= 0 && !used.has(belt[i])) {\r\n this.drawBelt(pos++, i);\r\n used.add(belt[i]);\r\n }\r\n }\r\n for (; pos < 6; ++pos) {\r\n this.drawBelt(pos, -1);\r\n }\r\n } else {\r\n this.drawBelt(3, -1);\r\n this.drawBelt(4, -1);\r\n this.drawBelt(5, -1);\r\n }\r\n }\r\n\r\n start(file) {\r\n document.removeEventListener(\"drop\", this.onDrop, true);\r\n document.removeEventListener(\"dragover\", this.onDragOver, true);\r\n document.removeEventListener(\"dragenter\", this.onDragEnter, true);\r\n document.removeEventListener(\"dragleave\", this.onDragLeave, true);\r\n this.setState({dropping: 0});\r\n\r\n this.setState({loading: true});\r\n\r\n load_game(this, file).then(game => {\r\n this.game = game;\r\n\r\n document.addEventListener('mousemove', this.onMouseMove, true);\r\n document.addEventListener('mousedown', this.onMouseDown, true);\r\n document.addEventListener('mouseup', this.onMouseUp, true);\r\n document.addEventListener('keydown', this.onKeyDown, true);\r\n document.addEventListener('keyup', this.onKeyUp, true);\r\n document.addEventListener('contextmenu', this.onMenu, true);\r\n\r\n document.addEventListener('touchstart', this.onTouchStart, {passive: false, capture: true});\r\n document.addEventListener('touchmove', this.onTouchMove, {passive: false, capture: true});\r\n document.addEventListener('touchend', this.onTouchEnd, {passive: false, capture: true});\r\n\r\n document.addEventListener('pointerlockchange', this.onPointerLockChange);\r\n document.addEventListener('fullscreenchange', this.onFullscreenChange);\r\n window.addEventListener('resize', this.onResize);\r\n\r\n this.setState({started: true});\r\n }, e => this.onError(e.message));\r\n }\r\n\r\n pointerLocked() {\r\n return document.pointerLockElement === this.canvas || document.mozPointerLockElement === this.canvas;\r\n }\r\n\r\n mousePos(e) {\r\n const rect = this.canvas.getBoundingClientRect();\r\n if (this.pointerLocked()) {\r\n this.cursorPos.x = Math.max(rect.left, Math.min(rect.right, this.cursorPos.x + e.movementX));\r\n this.cursorPos.y = Math.max(rect.top, Math.min(rect.bottom, this.cursorPos.y + e.movementY));\r\n } else {\r\n this.cursorPos = {x: e.clientX, y: e.clientY};\r\n }\r\n return {\r\n x: Math.max(0, Math.min(Math.round((this.cursorPos.x - rect.left) / (rect.right - rect.left) * 640), 639)),\r\n y: Math.max(0, Math.min(Math.round((this.cursorPos.y - rect.top) / (rect.bottom - rect.top) * 480), 479)),\r\n };\r\n }\r\n\r\n mouseButton(e) {\r\n switch (e.button) {\r\n case 0: return 1;\r\n case 1: return 4;\r\n case 2: return 2;\r\n case 3: return 5;\r\n case 4: return 6;\r\n default: return 1;\r\n }\r\n }\r\n eventMods(e) {\r\n return ((e.shiftKey || this.touchMods[TOUCH_SHIFT]) ? 1 : 0) + (e.ctrlKey ? 2 : 0) + (e.altKey ? 4 : 0) + (e.touches ? 8 : 0);\r\n }\r\n\r\n onResize = () => {\r\n document.exitPointerLock();\r\n }\r\n\r\n onPointerLockChange = () => {\r\n if (window.screen && window.innerHeight === window.screen.height && !this.pointerLocked()) {\r\n // assume that the user pressed escape\r\n this.game(\"DApi_Key\", 0, 0, 27);\r\n this.game(\"DApi_Key\", 1, 0, 27);\r\n }\r\n }\r\n\r\n onMouseMove = e => {\r\n if (!this.canvas) return;\r\n const {x, y} = this.mousePos(e);\r\n this.game(\"DApi_Mouse\", 0, 0, this.eventMods(e), x, y);\r\n e.preventDefault();\r\n }\r\n\r\n onMouseDown = e => {\r\n if (!this.canvas) return;\r\n const {x, y} = this.mousePos(e);\r\n if (window.screen && window.innerHeight === window.screen.height) {\r\n // we're in fullscreen, let's get pointer lock!\r\n if (!this.pointerLocked()) {\r\n this.canvas.requestPointerLock();\r\n }\r\n }\r\n this.game(\"DApi_Mouse\", 1, this.mouseButton(e), this.eventMods(e), x, y);\r\n e.preventDefault();\r\n }\r\n\r\n onMouseUp = e => {\r\n if (!this.canvas) return;\r\n const {x, y} = this.mousePos(e);\r\n this.game(\"DApi_Mouse\", 2, this.mouseButton(e), this.eventMods(e), x, y);\r\n e.preventDefault();\r\n }\r\n\r\n onKeyDown = e => {\r\n if (!this.canvas) return;\r\n this.game(\"DApi_Key\", 0, this.eventMods(e), e.keyCode);\r\n if (e.keyCode >= 32 && e.key.length === 1 && !this.showKeyboard) {\r\n this.game(\"DApi_Char\", e.key.charCodeAt(0));\r\n }\r\n this.clearKeySel();\r\n if (!this.showKeyboard) {\r\n if (e.keyCode === 8 || e.keyCode === 116 || e.keyCode === 112) {\r\n e.preventDefault();\r\n }\r\n }\r\n }\r\n\r\n onMenu = e => {\r\n e.preventDefault();\r\n }\r\n\r\n onKeyUp = e => {\r\n if (!this.canvas) return;\r\n this.game(\"DApi_Key\", 1, this.eventMods(e), e.keyCode);\r\n this.clearKeySel();\r\n }\r\n\r\n clearKeySel() {\r\n if (this.showKeyboard) {\r\n const len = this.keyboard.value.length;\r\n this.keyboard.setSelectionRange(len, len);\r\n }\r\n }\r\n\r\n onKeyboard = () => {\r\n if (this.showKeyboard) {\r\n const text = this.keyboard.value;\r\n const valid = (text.match(/[\\x20-\\x7E]/g) || []).join(\"\").substring(0, 15);\r\n if (text !== valid) {\r\n this.keyboard.value = valid;\r\n }\r\n this.clearKeySel();\r\n const values = [...Array(15)].map((_, i) => i < valid.length ? valid.charCodeAt(i) : 0);\r\n this.game(\"DApi_SyncText\", ...values);\r\n }\r\n }\r\n\r\n parseFile = e => {\r\n const files = e.target.files;\r\n if (files.length > 0) {\r\n this.start(files[0]);\r\n }\r\n }\r\n\r\n touchButton = null;\r\n touchCanvas = null;\r\n\r\n onFullscreenChange = () => {\r\n this.setState({touch: (document.fullscreenElement === this.element)});\r\n }\r\n\r\n setTouchMod(index, value, use) {\r\n if (index < 3) {\r\n this.touchMods[index] = value;\r\n if (this.touchButtons[index]) {\r\n this.touchButtons[index].classList.toggle(\"active\", value);\r\n }\r\n } else if (use && this.touchBelt[index] >= 0) {\r\n const now = performance.now();\r\n if (!this.beltTime || now - this.beltTime > 750) {\r\n this.game(\"DApi_Char\", 49 + this.touchBelt[index]);\r\n this.beltTime = now;\r\n }\r\n }\r\n }\r\n\r\n updateTouchButton(touches, release) {\r\n let touchOther = null;\r\n const btn = this.touchButton;\r\n for (let {target, identifier, clientX, clientY} of touches) {\r\n if (btn && btn.id === identifier && this.touchButtons[btn.index] === target) {\r\n if (touches.length > 1) {\r\n btn.stick = false;\r\n }\r\n btn.clientX = clientX;\r\n btn.clientY = clientY;\r\n this.touchCanvas = [...touches].find(t => t.identifier !== identifier);\r\n if (this.touchCanvas) {\r\n this.touchCanvas = {clientX: this.touchCanvas.clientX, clientY: this.touchCanvas.clientY};\r\n }\r\n delete this.panPos;\r\n return this.touchCanvas != null;\r\n }\r\n const idx = this.touchButtons.indexOf(target);\r\n if (idx >= 0 && !touchOther) {\r\n touchOther = {id: identifier, index: idx, stick: true, original: this.touchMods[idx], clientX, clientY};\r\n }\r\n }\r\n if (btn && !touchOther && release && btn.stick) {\r\n const rect = this.touchButtons[btn.index].getBoundingClientRect();\r\n const {clientX, clientY} = btn;\r\n if (clientX >= rect.left && clientX < rect.right && clientY >= rect.top && clientY < rect.bottom) {\r\n this.setTouchMod(btn.index, !btn.original, true);\r\n } else {\r\n this.setTouchMod(btn.index, btn.original);\r\n }\r\n } else if (btn) {\r\n this.setTouchMod(btn.index, false);\r\n }\r\n this.touchButton = touchOther;\r\n if (touchOther) {\r\n this.setTouchMod(touchOther.index, true);\r\n if (touchOther.index === TOUCH_MOVE) {\r\n this.setTouchMod(TOUCH_RMB, false);\r\n } else if (touchOther.index === TOUCH_RMB) {\r\n this.setTouchMod(TOUCH_MOVE, false);\r\n }\r\n delete this.panPos;\r\n } else if (touches.length === 2) {\r\n const x = (touches[1].clientX + touches[0].clientX) / 2, y = (touches[1].clientY + touches[0].clientY) / 2;\r\n if (this.panPos) {\r\n const dx = x - this.panPos.x, dy = y - this.panPos.y;\r\n const step = this.canvas.offsetHeight / 12;\r\n if (Math.max(Math.abs(dx), Math.abs(dy)) > step) {\r\n let key;\r\n if (Math.abs(dx) > Math.abs(dy)) {\r\n key = (dx > 0 ? 0x25 : 0x27);\r\n } else {\r\n key = (dy > 0 ? 0x26 : 0x28);\r\n }\r\n this.game(\"DApi_Key\", 0, 0, key);\r\n // key up is ignored anyway\r\n this.panPos = {x, y};\r\n }\r\n } else {\r\n this.game(\"DApi_Mouse\", 0, 0, 24, 320, 180);\r\n this.game(\"DApi_Mouse\", 2, 1, 24, 320, 180);\r\n this.panPos = {x, y};\r\n }\r\n this.touchCanvas = null;\r\n return false;\r\n } else {\r\n delete this.panPos;\r\n }\r\n this.touchCanvas = [...touches].find(t => !touchOther || t.identifier !== touchOther.id);\r\n if (this.touchCanvas) {\r\n this.touchCanvas = {clientX: this.touchCanvas.clientX, clientY: this.touchCanvas.clientY};\r\n }\r\n return this.touchCanvas != null;\r\n }\r\n\r\n onTouchStart = e => {\r\n if (!this.canvas) return;\r\n e.preventDefault();\r\n if (this.updateTouchButton(e.touches, false)) {\r\n const {x, y} = this.mousePos(this.touchCanvas);\r\n this.game(\"DApi_Mouse\", 0, 0, this.eventMods(e), x, y);\r\n if (!this.touchMods[TOUCH_MOVE]) {\r\n this.game(\"DApi_Mouse\", 1, this.touchMods[TOUCH_RMB] ? 2 : 1, this.eventMods(e), x, y);\r\n }\r\n }\r\n }\r\n onTouchMove = e => {\r\n if (!this.canvas) return;\r\n e.preventDefault();\r\n if (this.updateTouchButton(e.touches, false)) {\r\n const {x, y} = this.mousePos(this.touchCanvas);\r\n this.game(\"DApi_Mouse\", 0, 0, this.eventMods(e), x, y);\r\n }\r\n }\r\n onTouchEnd = e => {\r\n if (!this.canvas) return;\r\n e.preventDefault();\r\n const prevTc = this.touchCanvas;\r\n this.updateTouchButton(e.touches, true);\r\n if (prevTc && !this.touchCanvas) {\r\n const {x, y} = this.mousePos(prevTc);\r\n this.game(\"DApi_Mouse\", 2, 1, this.eventMods(e), x, y);\r\n this.game(\"DApi_Mouse\", 2, 2, this.eventMods(e), x, y);\r\n\r\n if (this.touchMods[TOUCH_RMB] && (!this.touchButton || this.touchButton.index !== TOUCH_RMB)) {\r\n this.setTouchButton(TOUCH_RMB, false);\r\n }\r\n }\r\n if (!document.fullscreenElement) {\r\n this.element.requestFullscreen();\r\n }\r\n }\r\n\r\n setCanvas = e => this.canvas = e;\r\n setElement = e => this.element = e;\r\n setKeyboard = e => this.keyboard = e;\r\n setTouch_(i, e) {\r\n this.touchButtons[i] = e;\r\n }\r\n setTouchBelt_(i, e) {\r\n this.touchButtons[i] = e;\r\n if (e) {\r\n const canvas = document.createElement(\"canvas\");\r\n canvas.width = 28;\r\n canvas.height = 28;\r\n e.appendChild(canvas);\r\n this.touchCtx[i] = canvas.getContext(\"2d\");\r\n } else {\r\n this.touchCtx[i] = null;\r\n }\r\n }\r\n\r\n render() {\r\n const {started, loading, error, progress, dropping, touch, has_spawn} = this.state;\r\n return (\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n {!error && }\r\n \r\n
\r\n
\r\n {!!error && (\r\n \r\n

The following error has occurred:

\r\n

{error}

\r\n

Click to go to GitHub issues

\r\n \r\n )}\r\n {!!loading && !started && !error && (\r\n
\r\n {(progress && progress.text) || 'Loading...'}\r\n {progress != null && !!progress.total && (\r\n \r\n )}\r\n
\r\n )}\r\n {!started && !loading && !error && (\r\n
\r\n

\r\n This is a web port of the original Diablo game, based on source code reconstructed by\r\n GalaXyHaXz and devilution team: https://github.com/diasurgical/devilution\r\n

\r\n

\r\n If you own the original game, you can drop the original DIABDAT.MPQ onto this page or click the button below to start playing.\r\n The game can be purchased from GoG.\r\n

\r\n {!has_spawn && (\r\n

\r\n Or you can play the shareware version for free (50MB download).\r\n

\r\n )}\r\n
\r\n \r\n \r\n
\r\n this.start()}>Play Shareware\r\n
\r\n )}\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default App;\r\n","import React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport './reset.css';\r\nimport * as serviceWorker from './serviceWorker';\r\n\r\nimport App from './App';\r\n\r\nReactDOM.render(, document.getElementById('root'));\r\n\r\nserviceWorker.register();\r\n","import IdbKvStore from 'idb-kv-store';\r\n\r\nconst importStorage = () => new Promise((resolve, reject) => {\r\n let done = false;\r\n const frame = document.createElement('iframe');\r\n window.addEventListener('message', ({data}) => {\r\n if (data.method === 'storage' && !done) {\r\n done = true;\r\n resolve(data.files);\r\n frame.contentWindow.postMessage({method: 'clear'}, '*');\r\n }\r\n });\r\n frame.addEventListener('load', () => {\r\n frame.contentWindow.postMessage({method: 'transfer'}, '*');\r\n });\r\n frame.addEventListener('error', () => {\r\n if (!done) {\r\n done = true;\r\n resolve(null);\r\n }\r\n });\r\n frame.src = \"https://diablo.rivsoft.net/storage.html\";\r\n frame.style.display = \"none\";\r\n document.body.appendChild(frame);\r\n setTimeout(() => {\r\n if (!done) {\r\n done = true;\r\n resolve(null);\r\n }\r\n }, 10000);\r\n});\r\n\r\nasync function downloadFile(store, name) {\r\n const file = await store.get(name.toLowerCase());\r\n if (file) {\r\n const blob = new Blob([file], {type: 'binary/octet-stream'});\r\n const url = URL.createObjectURL(blob);\r\n const lnk = document.createElement('a');\r\n lnk.setAttribute('href', url);\r\n lnk.setAttribute('download', name);\r\n document.body.appendChild(lnk);\r\n lnk.click();\r\n document.body.removeChild(lnk);\r\n URL.revokeObjectURL(url);\r\n } else {\r\n console.error(`File ${name} does not exist`);\r\n }\r\n}\r\n\r\nexport default async function create_fs(load) {\r\n try {\r\n const store = new IdbKvStore('diablo_fs');\r\n const files = new Map();\r\n for (let [name, data] of Object.entries(await store.json())) {\r\n files.set(name, data);\r\n }\r\n if (load) {\r\n const files = await importStorage();\r\n if (files) {\r\n for (let [name, data] of files) {\r\n files.set(name, data);\r\n store.set(name, data);\r\n }\r\n }\r\n }\r\n window.DownloadFile = name => downloadFile(store, name);\r\n return {\r\n files,\r\n update: (name, data) => store.set(name, data),\r\n delete: name => store.remove(name),\r\n clear: () => store.clear(),\r\n };\r\n } catch (e) {\r\n window.DownloadFile = () => console.error('IndexedDB is not supported');\r\n return {\r\n files: new Map(),\r\n update: () => Promise.resolve(),\r\n delete: () => Promise.resolve(),\r\n clear: () => Promise.resolve(),\r\n };\r\n } \r\n}\r\n"],"sourceRoot":""} \ No newline at end of file diff --git a/static/js/main.21ca9033.chunk.js b/static/js/main.d7e3eea7.chunk.js similarity index 99% rename from static/js/main.21ca9033.chunk.js rename to static/js/main.d7e3eea7.chunk.js index 553945f..3c25cd7 100644 --- a/static/js/main.21ca9033.chunk.js +++ b/static/js/main.d7e3eea7.chunk.js @@ -1,2 +1,2 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{23:function(e,t,n){e.exports=function(){return new Worker(n.p+"54277a9e96a084857713.worker.js")}},28:function(e,t,n){e.exports=n(58)},34:function(e,t,n){},35:function(e,t,n){},58:function(e,t,n){"use strict";n.r(t);var a=n(0),o=n.n(a),r=n(19),s=n.n(r),i=(n(34),Boolean("localhost"===window.location.hostname||"[::1]"===window.location.hostname||window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)));function c(e,t){navigator.serviceWorker.register(e).then(function(e){e.onupdatefound=function(){var n=e.installing;null!=n&&(n.onstatechange=function(){"installed"===n.state&&(navigator.serviceWorker.controller?(console.log("New content is available and will be used when all tabs for this page are closed. See https://bit.ly/CRA-PWA."),t&&t.onUpdate&&t.onUpdate(e)):(console.log("Content is cached for offline use."),t&&t.onSuccess&&t.onSuccess(e)))})}}).catch(function(e){console.error("Error during service worker registration:",e)})}var u=n(5),l=n(20),d=n(21),h=n(25),f=n(22),p=n(4),v=n(26),m=n(27),g=(n(35),n(7)),b=n.n(g),y=n(8),w=n(1),k=n.n(w),x=n(6),M=n(3),E=n(23),T=n.n(E);var C=n(24),D=n.n(C),B=50274091;function L(e,t){return P.apply(this,arguments)}function P(){return(P=Object(M.a)(k.a.mark(function e(t,n){var a,o,r;return k.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(!(a=n.files.get("spawn.mpq"))||a.byteLength===B){e.next=6;break}return n.files.delete("spawn.mpq"),e.next=5,n.delete("spawn.mpq");case 5:a=null;case 6:if(a){e.next=15;break}return e.next=9,D.a.request({url:"/diabloweb/spawn.mpq",responseType:"arraybuffer",onDownloadProgress:function(e){t.onProgress&&t.onProgress({text:"Downloading...",loaded:e.loaded,total:e.total||B})},headers:{"Cache-Control":"max-age=31536000"}});case 9:if((o=e.sent).data.byteLength===B){e.next=12;break}throw Error("Invalid spawn.mpq size. Try clearing cache and refreshing the page.");case 12:r=new Uint8Array(o.data),n.files.set("spawn.mpq",r),n.update("spawn.mpq",r.slice());case 15:return e.abrupt("return",n);case 16:case"end":return e.stop()}},e)}))).apply(this,arguments)}function _(e,t,n){var a=n.bitmap,o=n.images,r=n.text,s=n.clip,i=n.belt;if(a)t.transferFromImageBitmap(a);else{var c=!0,u=!1,l=void 0;try{for(var d,h=o[Symbol.iterator]();!(c=(d=h.next()).done);c=!0){var f=d.value,p=f.x,v=f.y,m=f.w,g=f.h,b=f.data,y=t.createImageData(m,g);y.data.set(b),t.putImageData(y,p,v)}}catch(N){u=!0,l=N}finally{try{c||null==h.return||h.return()}finally{if(u)throw l}}if(r.length){if(t.save(),t.font="bold 13px Times New Roman",s){var w=s.x0,k=s.y0,x=s.x1,M=s.y1;t.beginPath(),t.rect(w,k,x-w,M-k),t.clip()}var E=!0,T=!1,C=void 0;try{for(var D,B=r[Symbol.iterator]();!(E=(D=B.next()).done);E=!0){var L=D.value,P=L.x,_=L.y,j=L.text,A=L.color,O=A>>16&255,S=A>>8&255,K=255&A;t.fillStyle="rgb(".concat(O,", ").concat(S,", ").concat(K,")"),t.fillText(j,P,_+22)}}catch(N){T=!0,C=N}finally{try{E||null==B.return||B.return()}finally{if(T)throw C}}t.restore()}}e.updateBelt(i)}function j(){return(j=Object(M.a)(k.a.mark(function e(t,n,a){var o,r,s,i;return k.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t.fs;case 2:if(o=e.sent,r=!0,!a){e.next=8;break}a.name.match(/^spawn\.mpq$/i)||(r=!1,o.files.delete("spawn.mpq")),e.next=10;break;case 8:return e.next=10,L(t,o);case 10:return s=null,i=!1,s=t.canvas.getContext("2d",{alpha:!1}),e.next=14,new Promise(function(e,c){try{var l=new T.a;l.addEventListener("message",function(a){var r=a.data;switch(r.action){case"loaded":e(function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),a=1;a=32&&1===e.key.length&&!n.showKeyboard&&n.game("DApi_Char",e.key.charCodeAt(0)),n.clearKeySel(),n.showKeyboard||8!==e.keyCode&&116!==e.keyCode&&112!==e.keyCode||e.preventDefault())},n.onMenu=function(e){e.preventDefault()},n.onKeyUp=function(e){n.canvas&&(n.game("DApi_Key",1,n.eventMods(e),e.keyCode),n.clearKeySel())},n.onKeyboard=function(){if(n.showKeyboard){var e,t=n.keyboard.value,a=(t.match(/[\x20-\x7E]/g)||[]).join("").substring(0,15);t!==a&&(n.keyboard.value=a),n.clearKeySel();var o=Object(u.a)(Array(15)).map(function(e,t){return t0&&n.start(t[0])},n.touchButton=null,n.touchCanvas=null,n.onFullscreenChange=function(){n.setState({touch:document.fullscreenElement===n.element})},n.onTouchStart=function(e){if(n.canvas&&(e.preventDefault(),n.updateTouchButton(e.touches,!1))){var t=n.mousePos(n.touchCanvas),a=t.x,o=t.y;n.game("DApi_Mouse",0,0,n.eventMods(e),a,o),n.touchMods[O]||n.game("DApi_Mouse",1,n.touchMods[S]?2:1,n.eventMods(e),a,o)}},n.onTouchMove=function(e){if(n.canvas&&(e.preventDefault(),n.updateTouchButton(e.touches,!1))){var t=n.mousePos(n.touchCanvas),a=t.x,o=t.y;n.game("DApi_Mouse",0,0,n.eventMods(e),a,o)}},n.onTouchEnd=function(e){if(n.canvas){e.preventDefault();var t=n.touchCanvas;if(n.updateTouchButton(e.touches,!0),t&&!n.touchCanvas){var a=n.mousePos(t),o=a.x,r=a.y;n.game("DApi_Mouse",2,1,n.eventMods(e),o,r),n.game("DApi_Mouse",2,2,n.eventMods(e),o,r),!n.touchMods[S]||n.touchButton&&n.touchButton.index===S||n.setTouchButton(S,!1)}document.fullscreenElement||n.element.requestFullscreen()}},n.setCanvas=function(e){return n.canvas=e},n.setElement=function(e){return n.element=e},n.setKeyboard=function(e){return n.keyboard=e},n.setTouch0=n.setTouch_.bind(Object(p.a)(n),0),n.setTouch1=n.setTouch_.bind(Object(p.a)(n),1),n.setTouch2=n.setTouch_.bind(Object(p.a)(n),2),n.setTouch3=n.setTouchBelt_.bind(Object(p.a)(n),3),n.setTouch4=n.setTouchBelt_.bind(Object(p.a)(n),4),n.setTouch5=n.setTouchBelt_.bind(Object(p.a)(n),5),n}return Object(v.a)(t,e),Object(d.a)(t,[{key:"componentDidMount",value:function(){var e=this;document.addEventListener("drop",this.onDrop,!0),document.addEventListener("dragover",this.onDragOver,!0),document.addEventListener("dragenter",this.onDragEnter,!0),document.addEventListener("dragleave",this.onDragLeave,!0),this.fs.then(function(t){var n=t.files.get("spawn.mpq");n&&n.byteLength===B&&e.setState({has_spawn:!0})})}},{key:"setDropping",value:function(e){this.setState(function(t){var n=t.dropping;return{dropping:Math.max(n+e,0)}})}},{key:"onError",value:function(e){this.setState({error:e})}},{key:"openKeyboard",value:function(e){e?(this.showKeyboard=!0,this.element.classList.add("keyboard"),this.keyboard.focus()):(this.showKeyboard=!1,this.element.classList.remove("keyboard"),this.keyboard.blur())}},{key:"setCursorPos",value:function(e,t){var n=this,a=this.canvas.getBoundingClientRect();this.cursorPos={x:a.left+(a.right-a.left)*e/640,y:a.top+(a.bottom-a.top)*t/480},setTimeout(function(){n.game("DApi_Mouse",0,0,0,e,t)})}},{key:"onProgress",value:function(e){this.setState({progress:e})}},{key:"drawBelt",value:function(e,t){this.touchButtons[e]&&(this.touchBelt[e]=t,t>=0?(this.touchButtons[e].style.display="block",this.touchCtx[e].drawImage(this.canvas,205+29*t,357,28,28,0,0,28,28)):this.touchButtons[e].style.display="none")}},{key:"updateBelt",value:function(e){if(e){for(var t=new Set,n=3,a=0;a=0&&!t.has(e[a])&&(this.drawBelt(n++,a),t.add(e[a]));for(;n<6;++n)this.drawBelt(n,-1)}else this.drawBelt(3,-1),this.drawBelt(4,-1),this.drawBelt(5,-1)}},{key:"start",value:function(e){var t=this;document.removeEventListener("drop",this.onDrop,!0),document.removeEventListener("dragover",this.onDragOver,!0),document.removeEventListener("dragenter",this.onDragEnter,!0),document.removeEventListener("dragleave",this.onDragLeave,!0),this.setState({dropping:0}),this.setState({loading:!0}),A(this,e).then(function(e){t.game=e,document.addEventListener("mousemove",t.onMouseMove,!0),document.addEventListener("mousedown",t.onMouseDown,!0),document.addEventListener("mouseup",t.onMouseUp,!0),document.addEventListener("keydown",t.onKeyDown,!0),document.addEventListener("keyup",t.onKeyUp,!0),document.addEventListener("contextmenu",t.onMenu,!0),document.addEventListener("touchstart",t.onTouchStart,{passive:!1,capture:!0}),document.addEventListener("touchmove",t.onTouchMove,{passive:!1,capture:!0}),document.addEventListener("touchend",t.onTouchEnd,{passive:!1,capture:!0}),document.addEventListener("pointerlockchange",t.onPointerLockChange),document.addEventListener("fullscreenchange",t.onFullscreenChange),window.addEventListener("resize",t.onResize),t.setState({started:!0})},function(e){return t.onError(e.message)})}},{key:"pointerLocked",value:function(){return document.pointerLockElement===this.canvas||document.mozPointerLockElement===this.canvas}},{key:"mousePos",value:function(e){var t=this.canvas.getBoundingClientRect();return this.pointerLocked()?(this.cursorPos.x=Math.max(t.left,Math.min(t.right,this.cursorPos.x+e.movementX)),this.cursorPos.y=Math.max(t.top,Math.min(t.bottom,this.cursorPos.y+e.movementY))):this.cursorPos={x:e.clientX,y:e.clientY},{x:Math.max(0,Math.min(Math.round((this.cursorPos.x-t.left)/(t.right-t.left)*640),639)),y:Math.max(0,Math.min(Math.round((this.cursorPos.y-t.top)/(t.bottom-t.top)*480),479))}}},{key:"mouseButton",value:function(e){switch(e.button){case 0:return 1;case 1:return 4;case 2:return 2;case 3:return 5;case 4:return 6;default:return 1}}},{key:"eventMods",value:function(e){return(e.shiftKey||this.touchMods[2]?1:0)+(e.ctrlKey?2:0)+(e.altKey?4:0)+(e.touches?8:0)}},{key:"clearKeySel",value:function(){if(this.showKeyboard){var e=this.keyboard.value.length;this.keyboard.setSelectionRange(e,e)}}},{key:"setTouchMod",value:function(e,t,n){if(e<3)this.touchMods[e]=t,this.touchButtons[e]&&this.touchButtons[e].classList.toggle("active",t);else if(n&&this.touchBelt[e]>=0){var a=performance.now();(!this.beltTime||a-this.beltTime>750)&&(this.game("DApi_Char",49+this.touchBelt[e]),this.beltTime=a)}}},{key:"updateTouchButton",value:function(e,t){var n=this,a=null,o=this.touchButton,r=!0,s=!1,i=void 0;try{for(var c,l=function(){var t=c.value,r=t.target,s=t.identifier,i=t.clientX,l=t.clientY;if(o&&o.id===s&&n.touchButtons[o.index]===r)return e.length>1&&(o.stick=!1),o.clientX=i,o.clientY=l,n.touchCanvas=Object(u.a)(e).find(function(e){return e.identifier!==s}),n.touchCanvas&&(n.touchCanvas={clientX:n.touchCanvas.clientX,clientY:n.touchCanvas.clientY}),delete n.panPos,{v:null!=n.touchCanvas};var d=n.touchButtons.indexOf(r);d>=0&&!a&&(a={id:s,index:d,stick:!0,original:n.touchMods[d],clientX:i,clientY:l})},d=e[Symbol.iterator]();!(r=(c=d.next()).done);r=!0){var h=l();if("object"===typeof h)return h.v}}catch(x){s=!0,i=x}finally{try{r||null==d.return||d.return()}finally{if(s)throw i}}if(o&&!a&&t&&o.stick){var f=this.touchButtons[o.index].getBoundingClientRect(),p=o.clientX,v=o.clientY;p>=f.left&&p=f.top&&vk)b=Math.abs(y)>Math.abs(w)?y>0?37:39:w>0?38:40,this.game("DApi_Key",0,0,b),this.panPos={x:m,y:g}}else this.game("DApi_Mouse",0,0,24,320,180),this.game("DApi_Mouse",2,1,24,320,180),this.panPos={x:m,y:g};return this.touchCanvas=null,!1}delete this.panPos}return this.touchCanvas=Object(u.a)(e).find(function(e){return!a||e.identifier!==a.id}),this.touchCanvas&&(this.touchCanvas={clientX:this.touchCanvas.clientX,clientY:this.touchCanvas.clientY}),null!=this.touchCanvas}},{key:"setTouch_",value:function(e,t){this.touchButtons[e]=t}},{key:"setTouchBelt_",value:function(e,t){if(this.touchButtons[e]=t,t){var n=document.createElement("canvas");n.width=28,n.height=28,t.appendChild(n),this.touchCtx[e]=n.getContext("2d")}else this.touchCtx[e]=null}},{key:"render",value:function(){var e=this,t=this.state,n=t.started,a=t.loading,r=t.error,s=t.progress,i=t.dropping,c=t.touch,u=t.has_spawn;return o.a.createElement("div",{className:b()("App",{touch:c,started:n,dropping:i,keyboard:this.showKeyboard}),ref:this.setElement},o.a.createElement("div",{className:"touch-ui touch-mods"},o.a.createElement("div",{className:b()("touch-button","touch-button-0",{active:this.touchMods[0]}),ref:this.setTouch0}),o.a.createElement("div",{className:b()("touch-button","touch-button-1",{active:this.touchMods[1]}),ref:this.setTouch1}),o.a.createElement("div",{className:b()("touch-button","touch-button-2",{active:this.touchMods[2]}),ref:this.setTouch2})),o.a.createElement("div",{className:"touch-ui touch-belt"},o.a.createElement("div",{className:b()("touch-button","touch-button-0"),ref:this.setTouch3}),o.a.createElement("div",{className:b()("touch-button","touch-button-1"),ref:this.setTouch4}),o.a.createElement("div",{className:b()("touch-button","touch-button-2"),ref:this.setTouch5})),o.a.createElement("div",{className:"Body"},!r&&o.a.createElement("canvas",{ref:this.setCanvas,width:640,height:480}),o.a.createElement("input",{type:"text",className:"keyboard",onChange:this.onKeyboard,ref:this.setKeyboard,spellCheck:!1})),o.a.createElement("div",{className:"BodyV"},!!r&&o.a.createElement(K,{className:"error",href:"https://github.com/d07RiV/diabloweb/issues"},o.a.createElement("p",{className:"header"},"The following error has occurred:"),o.a.createElement("p",{className:"body"},r),o.a.createElement("p",{className:"footer"},"Click to go to GitHub issues")),!!a&&!n&&!r&&o.a.createElement("div",{className:"loading"},s&&s.text||"Loading...",null!=s&&!!s.total&&o.a.createElement("span",{className:"progressBar"},o.a.createElement("span",null,o.a.createElement("span",{style:{width:"".concat(Math.round(100*s.loaded/s.total),"%")}})))),!n&&!a&&!r&&o.a.createElement("div",{className:"start"},o.a.createElement("p",null,"This is a web port of the original Diablo game, based on source code reconstructed by GalaXyHaXz and devilution team: ",o.a.createElement(K,{href:"https://github.com/diasurgical/devilution"},"https://github.com/diasurgical/devilution")),o.a.createElement("p",null,"If you own the original game, you can drop the original DIABDAT.MPQ onto this page or click the button below to start playing. The game can be purchased from ",o.a.createElement(K,{href:"https://www.gog.com/game/diablo"},"GoG"),"."),!u&&o.a.createElement("p",null,"Or you can play the shareware version for free (50MB download)."),o.a.createElement("form",null,o.a.createElement("label",{htmlFor:"loadFile",className:"startButton"},"Select MPQ"),o.a.createElement("input",{accept:".mpq",type:"file",id:"loadFile",style:{display:"none"},onChange:this.parseFile})),o.a.createElement("span",{className:"startButton",onClick:function(){return e.start()}},"Play Shareware"))))}}]),t}(o.a.Component);s.a.render(o.a.createElement(N,null),document.getElementById("root")),function(e){if("serviceWorker"in navigator){if(new URL("/diabloweb",window.location.href).origin!==window.location.origin)return;window.addEventListener("load",function(){var t="".concat("/diabloweb","/service-worker.js");i?(function(e,t){fetch(e).then(function(n){var a=n.headers.get("content-type");404===n.status||null!=a&&-1===a.indexOf("javascript")?navigator.serviceWorker.ready.then(function(e){e.unregister().then(function(){window.location.reload()})}):c(e,t)}).catch(function(){console.log("No internet connection found. App is running in offline mode.")})}(t,e),navigator.serviceWorker.ready.then(function(){console.log("This web app is being served cache-first by a service worker. To learn more, visit https://bit.ly/CRA-PWA")})):c(t,e)})}}()},8:function(e,t,n){"use strict";n.d(t,"a",function(){return h});var a=n(6),o=n(1),r=n.n(o),s=n(3),i=n(9),c=n.n(i),u=function(){return new Promise(function(e,t){var n=!1,a=document.createElement("iframe");window.addEventListener("message",function(t){var o=t.data;"storage"!==o.method||n||(n=!0,e(o.files),a.contentWindow.postMessage({method:"clear"},"*"))}),a.addEventListener("load",function(){a.contentWindow.postMessage({method:"transfer"},"*")}),a.addEventListener("error",function(){n||(n=!0,e(null))}),a.src="https://diablo.rivsoft.net/storage.html",a.style.display="none",document.body.appendChild(a),setTimeout(function(){n||(n=!0,e(null))},1e4)})};function l(e,t){return d.apply(this,arguments)}function d(){return(d=Object(s.a)(r.a.mark(function e(t,n){var a,o,s,i;return r.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t.get(n.toLowerCase());case 2:(a=e.sent)?(o=new Blob([a],{type:"binary/octet-stream"}),s=URL.createObjectURL(o),(i=document.createElement("a")).setAttribute("href",s),i.setAttribute("download",n),document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(s)):console.error("File ".concat(n," does not exist"));case 4:case"end":return e.stop()}},e)}))).apply(this,arguments)}function h(e){return f.apply(this,arguments)}function f(){return(f=Object(s.a)(r.a.mark(function e(t){var n,o,s,i,d,h,f,p,v,m,g,b,y,w,k,x,M,E;return r.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.prev=0,n=new c.a("diablo_fs"),o=new Map,s=0,e.t0=Object,e.next=7,n.json();case 7:e.t1=e.sent,i=e.t0.entries.call(e.t0,e.t1);case 9:if(!(s>16&255,S=A>>8&255,K=255&A;t.fillStyle="rgb(".concat(O,", ").concat(S,", ").concat(K,")"),t.fillText(j,P,_+22)}}catch(N){T=!0,C=N}finally{try{E||null==B.return||B.return()}finally{if(T)throw C}}t.restore()}}e.updateBelt(i)}function j(){return(j=Object(M.a)(k.a.mark(function e(t,n,a){var o,r,s,i;return k.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t.fs;case 2:if(o=e.sent,r=!0,!a){e.next=8;break}a.name.match(/^spawn\.mpq$/i)||(r=!1,o.files.delete("spawn.mpq")),e.next=10;break;case 8:return e.next=10,L(t,o);case 10:return s=null,i=!1,s=t.canvas.getContext("2d",{alpha:!1}),e.next=14,new Promise(function(e,c){try{var l=new T.a;l.addEventListener("message",function(a){var r=a.data;switch(r.action){case"loaded":e(function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),a=1;a=32&&1===e.key.length&&!n.showKeyboard&&n.game("DApi_Char",e.key.charCodeAt(0)),n.clearKeySel(),n.showKeyboard||(8===e.keyCode||e.keyCode>=112&&e.keyCode<=119)&&e.preventDefault())},n.onMenu=function(e){e.preventDefault()},n.onKeyUp=function(e){n.canvas&&(n.game("DApi_Key",1,n.eventMods(e),e.keyCode),n.clearKeySel())},n.onKeyboard=function(){if(n.showKeyboard){var e,t=n.keyboard.value,a=(t.match(/[\x20-\x7E]/g)||[]).join("").substring(0,15);t!==a&&(n.keyboard.value=a),n.clearKeySel();var o=Object(u.a)(Array(15)).map(function(e,t){return t0&&n.start(t[0])},n.touchButton=null,n.touchCanvas=null,n.onFullscreenChange=function(){n.setState({touch:document.fullscreenElement===n.element})},n.onTouchStart=function(e){if(n.canvas&&(e.preventDefault(),n.updateTouchButton(e.touches,!1))){var t=n.mousePos(n.touchCanvas),a=t.x,o=t.y;n.game("DApi_Mouse",0,0,n.eventMods(e),a,o),n.touchMods[O]||n.game("DApi_Mouse",1,n.touchMods[S]?2:1,n.eventMods(e),a,o)}},n.onTouchMove=function(e){if(n.canvas&&(e.preventDefault(),n.updateTouchButton(e.touches,!1))){var t=n.mousePos(n.touchCanvas),a=t.x,o=t.y;n.game("DApi_Mouse",0,0,n.eventMods(e),a,o)}},n.onTouchEnd=function(e){if(n.canvas){e.preventDefault();var t=n.touchCanvas;if(n.updateTouchButton(e.touches,!0),t&&!n.touchCanvas){var a=n.mousePos(t),o=a.x,r=a.y;n.game("DApi_Mouse",2,1,n.eventMods(e),o,r),n.game("DApi_Mouse",2,2,n.eventMods(e),o,r),!n.touchMods[S]||n.touchButton&&n.touchButton.index===S||n.setTouchButton(S,!1)}document.fullscreenElement||n.element.requestFullscreen()}},n.setCanvas=function(e){return n.canvas=e},n.setElement=function(e){return n.element=e},n.setKeyboard=function(e){return n.keyboard=e},n.setTouch0=n.setTouch_.bind(Object(p.a)(n),0),n.setTouch1=n.setTouch_.bind(Object(p.a)(n),1),n.setTouch2=n.setTouch_.bind(Object(p.a)(n),2),n.setTouch3=n.setTouchBelt_.bind(Object(p.a)(n),3),n.setTouch4=n.setTouchBelt_.bind(Object(p.a)(n),4),n.setTouch5=n.setTouchBelt_.bind(Object(p.a)(n),5),n}return Object(v.a)(t,e),Object(d.a)(t,[{key:"componentDidMount",value:function(){var e=this;document.addEventListener("drop",this.onDrop,!0),document.addEventListener("dragover",this.onDragOver,!0),document.addEventListener("dragenter",this.onDragEnter,!0),document.addEventListener("dragleave",this.onDragLeave,!0),this.fs.then(function(t){var n=t.files.get("spawn.mpq");n&&n.byteLength===B&&e.setState({has_spawn:!0})})}},{key:"setDropping",value:function(e){this.setState(function(t){var n=t.dropping;return{dropping:Math.max(n+e,0)}})}},{key:"onError",value:function(e){this.setState({error:e})}},{key:"openKeyboard",value:function(e){e?(this.showKeyboard=!0,this.element.classList.add("keyboard"),this.keyboard.focus()):(this.showKeyboard=!1,this.element.classList.remove("keyboard"),this.keyboard.blur())}},{key:"setCursorPos",value:function(e,t){var n=this,a=this.canvas.getBoundingClientRect();this.cursorPos={x:a.left+(a.right-a.left)*e/640,y:a.top+(a.bottom-a.top)*t/480},setTimeout(function(){n.game("DApi_Mouse",0,0,0,e,t)})}},{key:"onProgress",value:function(e){this.setState({progress:e})}},{key:"drawBelt",value:function(e,t){this.touchButtons[e]&&(this.touchBelt[e]=t,t>=0?(this.touchButtons[e].style.display="block",this.touchCtx[e].drawImage(this.canvas,205+29*t,357,28,28,0,0,28,28)):this.touchButtons[e].style.display="none")}},{key:"updateBelt",value:function(e){if(e){for(var t=new Set,n=3,a=0;a=0&&!t.has(e[a])&&(this.drawBelt(n++,a),t.add(e[a]));for(;n<6;++n)this.drawBelt(n,-1)}else this.drawBelt(3,-1),this.drawBelt(4,-1),this.drawBelt(5,-1)}},{key:"start",value:function(e){var t=this;document.removeEventListener("drop",this.onDrop,!0),document.removeEventListener("dragover",this.onDragOver,!0),document.removeEventListener("dragenter",this.onDragEnter,!0),document.removeEventListener("dragleave",this.onDragLeave,!0),this.setState({dropping:0}),this.setState({loading:!0}),A(this,e).then(function(e){t.game=e,document.addEventListener("mousemove",t.onMouseMove,!0),document.addEventListener("mousedown",t.onMouseDown,!0),document.addEventListener("mouseup",t.onMouseUp,!0),document.addEventListener("keydown",t.onKeyDown,!0),document.addEventListener("keyup",t.onKeyUp,!0),document.addEventListener("contextmenu",t.onMenu,!0),document.addEventListener("touchstart",t.onTouchStart,{passive:!1,capture:!0}),document.addEventListener("touchmove",t.onTouchMove,{passive:!1,capture:!0}),document.addEventListener("touchend",t.onTouchEnd,{passive:!1,capture:!0}),document.addEventListener("pointerlockchange",t.onPointerLockChange),document.addEventListener("fullscreenchange",t.onFullscreenChange),window.addEventListener("resize",t.onResize),t.setState({started:!0})},function(e){return t.onError(e.message)})}},{key:"pointerLocked",value:function(){return document.pointerLockElement===this.canvas||document.mozPointerLockElement===this.canvas}},{key:"mousePos",value:function(e){var t=this.canvas.getBoundingClientRect();return this.pointerLocked()?(this.cursorPos.x=Math.max(t.left,Math.min(t.right,this.cursorPos.x+e.movementX)),this.cursorPos.y=Math.max(t.top,Math.min(t.bottom,this.cursorPos.y+e.movementY))):this.cursorPos={x:e.clientX,y:e.clientY},{x:Math.max(0,Math.min(Math.round((this.cursorPos.x-t.left)/(t.right-t.left)*640),639)),y:Math.max(0,Math.min(Math.round((this.cursorPos.y-t.top)/(t.bottom-t.top)*480),479))}}},{key:"mouseButton",value:function(e){switch(e.button){case 0:return 1;case 1:return 4;case 2:return 2;case 3:return 5;case 4:return 6;default:return 1}}},{key:"eventMods",value:function(e){return(e.shiftKey||this.touchMods[2]?1:0)+(e.ctrlKey?2:0)+(e.altKey?4:0)+(e.touches?8:0)}},{key:"clearKeySel",value:function(){if(this.showKeyboard){var e=this.keyboard.value.length;this.keyboard.setSelectionRange(e,e)}}},{key:"setTouchMod",value:function(e,t,n){if(e<3)this.touchMods[e]=t,this.touchButtons[e]&&this.touchButtons[e].classList.toggle("active",t);else if(n&&this.touchBelt[e]>=0){var a=performance.now();(!this.beltTime||a-this.beltTime>750)&&(this.game("DApi_Char",49+this.touchBelt[e]),this.beltTime=a)}}},{key:"updateTouchButton",value:function(e,t){var n=this,a=null,o=this.touchButton,r=!0,s=!1,i=void 0;try{for(var c,l=function(){var t=c.value,r=t.target,s=t.identifier,i=t.clientX,l=t.clientY;if(o&&o.id===s&&n.touchButtons[o.index]===r)return e.length>1&&(o.stick=!1),o.clientX=i,o.clientY=l,n.touchCanvas=Object(u.a)(e).find(function(e){return e.identifier!==s}),n.touchCanvas&&(n.touchCanvas={clientX:n.touchCanvas.clientX,clientY:n.touchCanvas.clientY}),delete n.panPos,{v:null!=n.touchCanvas};var d=n.touchButtons.indexOf(r);d>=0&&!a&&(a={id:s,index:d,stick:!0,original:n.touchMods[d],clientX:i,clientY:l})},d=e[Symbol.iterator]();!(r=(c=d.next()).done);r=!0){var h=l();if("object"===typeof h)return h.v}}catch(x){s=!0,i=x}finally{try{r||null==d.return||d.return()}finally{if(s)throw i}}if(o&&!a&&t&&o.stick){var f=this.touchButtons[o.index].getBoundingClientRect(),p=o.clientX,v=o.clientY;p>=f.left&&p=f.top&&vk)b=Math.abs(y)>Math.abs(w)?y>0?37:39:w>0?38:40,this.game("DApi_Key",0,0,b),this.panPos={x:m,y:g}}else this.game("DApi_Mouse",0,0,24,320,180),this.game("DApi_Mouse",2,1,24,320,180),this.panPos={x:m,y:g};return this.touchCanvas=null,!1}delete this.panPos}return this.touchCanvas=Object(u.a)(e).find(function(e){return!a||e.identifier!==a.id}),this.touchCanvas&&(this.touchCanvas={clientX:this.touchCanvas.clientX,clientY:this.touchCanvas.clientY}),null!=this.touchCanvas}},{key:"setTouch_",value:function(e,t){this.touchButtons[e]=t}},{key:"setTouchBelt_",value:function(e,t){if(this.touchButtons[e]=t,t){var n=document.createElement("canvas");n.width=28,n.height=28,t.appendChild(n),this.touchCtx[e]=n.getContext("2d")}else this.touchCtx[e]=null}},{key:"render",value:function(){var e=this,t=this.state,n=t.started,a=t.loading,r=t.error,s=t.progress,i=t.dropping,c=t.touch,u=t.has_spawn;return o.a.createElement("div",{className:b()("App",{touch:c,started:n,dropping:i,keyboard:this.showKeyboard}),ref:this.setElement},o.a.createElement("div",{className:"touch-ui touch-mods"},o.a.createElement("div",{className:b()("touch-button","touch-button-0",{active:this.touchMods[0]}),ref:this.setTouch0}),o.a.createElement("div",{className:b()("touch-button","touch-button-1",{active:this.touchMods[1]}),ref:this.setTouch1}),o.a.createElement("div",{className:b()("touch-button","touch-button-2",{active:this.touchMods[2]}),ref:this.setTouch2})),o.a.createElement("div",{className:"touch-ui touch-belt"},o.a.createElement("div",{className:b()("touch-button","touch-button-0"),ref:this.setTouch3}),o.a.createElement("div",{className:b()("touch-button","touch-button-1"),ref:this.setTouch4}),o.a.createElement("div",{className:b()("touch-button","touch-button-2"),ref:this.setTouch5})),o.a.createElement("div",{className:"Body"},!r&&o.a.createElement("canvas",{ref:this.setCanvas,width:640,height:480}),o.a.createElement("input",{type:"text",className:"keyboard",onChange:this.onKeyboard,ref:this.setKeyboard,spellCheck:!1})),o.a.createElement("div",{className:"BodyV"},!!r&&o.a.createElement(K,{className:"error",href:"https://github.com/d07RiV/diabloweb/issues"},o.a.createElement("p",{className:"header"},"The following error has occurred:"),o.a.createElement("p",{className:"body"},r),o.a.createElement("p",{className:"footer"},"Click to go to GitHub issues")),!!a&&!n&&!r&&o.a.createElement("div",{className:"loading"},s&&s.text||"Loading...",null!=s&&!!s.total&&o.a.createElement("span",{className:"progressBar"},o.a.createElement("span",null,o.a.createElement("span",{style:{width:"".concat(Math.round(100*s.loaded/s.total),"%")}})))),!n&&!a&&!r&&o.a.createElement("div",{className:"start"},o.a.createElement("p",null,"This is a web port of the original Diablo game, based on source code reconstructed by GalaXyHaXz and devilution team: ",o.a.createElement(K,{href:"https://github.com/diasurgical/devilution"},"https://github.com/diasurgical/devilution")),o.a.createElement("p",null,"If you own the original game, you can drop the original DIABDAT.MPQ onto this page or click the button below to start playing. The game can be purchased from ",o.a.createElement(K,{href:"https://www.gog.com/game/diablo"},"GoG"),"."),!u&&o.a.createElement("p",null,"Or you can play the shareware version for free (50MB download)."),o.a.createElement("form",null,o.a.createElement("label",{htmlFor:"loadFile",className:"startButton"},"Select MPQ"),o.a.createElement("input",{accept:".mpq",type:"file",id:"loadFile",style:{display:"none"},onChange:this.parseFile})),o.a.createElement("span",{className:"startButton",onClick:function(){return e.start()}},"Play Shareware"))))}}]),t}(o.a.Component);s.a.render(o.a.createElement(N,null),document.getElementById("root")),function(e){if("serviceWorker"in navigator){if(new URL("/diabloweb",window.location.href).origin!==window.location.origin)return;window.addEventListener("load",function(){var t="".concat("/diabloweb","/service-worker.js");i?(function(e,t){fetch(e).then(function(n){var a=n.headers.get("content-type");404===n.status||null!=a&&-1===a.indexOf("javascript")?navigator.serviceWorker.ready.then(function(e){e.unregister().then(function(){window.location.reload()})}):c(e,t)}).catch(function(){console.log("No internet connection found. App is running in offline mode.")})}(t,e),navigator.serviceWorker.ready.then(function(){console.log("This web app is being served cache-first by a service worker. To learn more, visit https://bit.ly/CRA-PWA")})):c(t,e)})}}()},8:function(e,t,n){"use strict";n.d(t,"a",function(){return h});var a=n(6),o=n(1),r=n.n(o),s=n(3),i=n(9),c=n.n(i),u=function(){return new Promise(function(e,t){var n=!1,a=document.createElement("iframe");window.addEventListener("message",function(t){var o=t.data;"storage"!==o.method||n||(n=!0,e(o.files),a.contentWindow.postMessage({method:"clear"},"*"))}),a.addEventListener("load",function(){a.contentWindow.postMessage({method:"transfer"},"*")}),a.addEventListener("error",function(){n||(n=!0,e(null))}),a.src="https://diablo.rivsoft.net/storage.html",a.style.display="none",document.body.appendChild(a),setTimeout(function(){n||(n=!0,e(null))},1e4)})};function l(e,t){return d.apply(this,arguments)}function d(){return(d=Object(s.a)(r.a.mark(function e(t,n){var a,o,s,i;return r.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t.get(n.toLowerCase());case 2:(a=e.sent)?(o=new Blob([a],{type:"binary/octet-stream"}),s=URL.createObjectURL(o),(i=document.createElement("a")).setAttribute("href",s),i.setAttribute("download",n),document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(s)):console.error("File ".concat(n," does not exist"));case 4:case"end":return e.stop()}},e)}))).apply(this,arguments)}function h(e){return f.apply(this,arguments)}function f(){return(f=Object(s.a)(r.a.mark(function e(t){var n,o,s,i,d,h,f,p,v,m,g,b,y,w,k,x,M,E;return r.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.prev=0,n=new c.a("diablo_fs"),o=new Map,s=0,e.t0=Object,e.next=7,n.json();case 7:e.t1=e.sent,i=e.t0.entries.call(e.t0,e.t1);case 9:if(!(s {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Let's check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, config);\r\n\r\n // Add some additional logging to localhost, pointing developers to the\r\n // service worker/PWA documentation.\r\n navigator.serviceWorker.ready.then(() => {\r\n console.log(\r\n 'This web app is being served cache-first by a service ' +\r\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\r\n );\r\n });\r\n } else {\r\n // Is not localhost. Just register service worker\r\n registerValidSW(swUrl, config);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl, config) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n if (installingWorker == null) {\r\n return;\r\n }\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the updated precached content has been fetched,\r\n // but the previous service worker will still serve the older\r\n // content until all client tabs are closed.\r\n console.log(\r\n 'New content is available and will be used when all ' +\r\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\r\n );\r\n\r\n // Execute callback\r\n if (config && config.onUpdate) {\r\n config.onUpdate(registration);\r\n }\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n\r\n // Execute callback\r\n if (config && config.onSuccess) {\r\n config.onSuccess(registration);\r\n }\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl, config) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl)\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n const contentType = response.headers.get('content-type');\r\n if (\r\n response.status === 404 ||\r\n (contentType != null && contentType.indexOf('javascript') === -1)\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, config);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister();\r\n });\r\n }\r\n}\r\n","import axios from 'axios';\r\n\r\nconst SpawnSize = 50274091;\r\n\r\nexport { SpawnSize };\r\n\r\nexport default async function load_spawn(api, fs) {\r\n let file = fs.files.get('spawn.mpq');\r\n if (file && file.byteLength !== SpawnSize) {\r\n fs.files.delete('spawn.mpq');\r\n await fs.delete('spawn.mpq');\r\n file = null;\r\n }\r\n if (!file) {\r\n const spawn = await axios.request({\r\n url: process.env.PUBLIC_URL + '/spawn.mpq',\r\n responseType: 'arraybuffer',\r\n onDownloadProgress: e => {\r\n if (api.onProgress) {\r\n api.onProgress({text: 'Downloading...', loaded: e.loaded, total: e.total || SpawnSize});\r\n }\r\n },\r\n headers: {\r\n 'Cache-Control': 'max-age=31536000'\r\n }\r\n });\r\n if (spawn.data.byteLength !== SpawnSize) {\r\n throw Error(\"Invalid spawn.mpq size. Try clearing cache and refreshing the page.\");\r\n }\r\n const data = new Uint8Array(spawn.data);\r\n fs.files.set('spawn.mpq', data);\r\n fs.update('spawn.mpq', data.slice());\r\n }\r\n return fs;\r\n}\r\n","import Worker from './game.worker.js';\r\nimport init_sound from './sound';\r\nimport load_spawn from './load_spawn';\r\n\r\nfunction onRender(api, ctx, {bitmap, images, text, clip, belt}) {\r\n if (bitmap) {\r\n ctx.transferFromImageBitmap(bitmap);\r\n } else {\r\n for (let {x, y, w, h, data} of images) {\r\n const image = ctx.createImageData(w, h);\r\n image.data.set(data);\r\n ctx.putImageData(image, x, y);\r\n }\r\n if (text.length) {\r\n ctx.save();\r\n ctx.font = 'bold 13px Times New Roman';\r\n if (clip) {\r\n const {x0, y0, x1, y1} = clip;\r\n ctx.beginPath();\r\n ctx.rect(x0, y0, x1 - x0, y1 - y0);\r\n ctx.clip();\r\n }\r\n for (let {x, y, text: str, color} of text) {\r\n const r = ((color >> 16) & 0xFF);\r\n const g = ((color >> 8) & 0xFF);\r\n const b = (color & 0xFF);\r\n ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;\r\n ctx.fillText(str, x, y + 22);\r\n }\r\n ctx.restore();\r\n }\r\n }\r\n\r\n api.updateBelt(belt);\r\n}\r\n\r\nfunction testOffscreen() {\r\n return false;\r\n /*try {\r\n const canvas = document.createElement(\"canvas\");\r\n const offscreen = canvas.transferControlToOffscreen();\r\n const context = offscreen.getContext(\"2d\");\r\n return context != null;\r\n } catch (e) {\r\n return false;\r\n }*/\r\n}\r\n\r\nasync function do_load_game(api, audio, mpq) {\r\n const fs = await api.fs;\r\n let spawn = true;\r\n if (mpq) {\r\n if (!mpq.name.match(/^spawn\\.mpq$/i)) {\r\n spawn = false;\r\n fs.files.delete('spawn.mpq');\r\n }\r\n } else {\r\n await load_spawn(api, fs);\r\n }\r\n\r\n let context = null, offscreen = false;\r\n if (testOffscreen()) {\r\n context = api.canvas.getContext(\"bitmaprenderer\");\r\n offscreen = true;\r\n } else {\r\n context = api.canvas.getContext(\"2d\", {alpha: false});\r\n }\r\n return await new Promise((resolve, reject) => {\r\n try {\r\n const worker = new Worker();\r\n worker.addEventListener(\"message\", ({data}) => {\r\n switch (data.action) {\r\n case \"loaded\":\r\n resolve((func, ...params) => worker.postMessage({action: \"event\", func, params}));\r\n break;\r\n case \"render\":\r\n onRender(api, context, data.batch);\r\n break;\r\n case \"audio\":\r\n audio[data.func](...data.params);\r\n break;\r\n case \"audioBatch\":\r\n for (let {func, params} of data.batch) {\r\n audio[func](...params);\r\n }\r\n break;\r\n case \"fs\":\r\n fs[data.func](...data.params);\r\n break;\r\n case \"cursor\":\r\n api.setCursorPos(data.x, data.y);\r\n break;\r\n case \"keyboard\":\r\n api.openKeyboard(data.open);\r\n break;\r\n case \"error\":\r\n api.onError(data.error);\r\n break;\r\n case \"failed\":\r\n reject(Error(data.error));\r\n break;\r\n case \"progress\":\r\n api.onProgress({text: data.text, loaded: data.loaded, total: data.total});\r\n break;\r\n default:\r\n }\r\n });\r\n const transfer= [];\r\n for (let [, file] of fs.files) {\r\n transfer.push(file.buffer);\r\n }\r\n worker.postMessage({action: \"init\", files: fs.files, mpq, spawn, offscreen}, transfer);\r\n delete fs.files;\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n}\r\n\r\nexport default function load_game(api, mpq) {\r\n const audio = init_sound();\r\n return do_load_game(api, audio, mpq);\r\n}\r\n","function no_sound() {\r\n return {\r\n create_sound: () => 0,\r\n duplicate_sound: () => 0,\r\n play_sound: () => undefined,\r\n set_volume: () => undefined,\r\n stop_sound: () => undefined,\r\n delete_sound: () => undefined,\r\n };\r\n}\r\n\r\nexport default function init_sound() {\r\n const AudioContext = window.AudioContext || window.webkitAudioContext;\r\n if (!AudioContext) {\r\n return no_sound();\r\n }\r\n\r\n const context = new AudioContext();\r\n const sounds = new Map();\r\n\r\n return {\r\n create_sound(id, data, length, channels, rate) {\r\n const buffer = context.createBuffer(channels, length, rate);\r\n for (let i = 0; i < channels; ++i) {\r\n buffer.copyToChannel(data.subarray(i * length, i * length + length), i);\r\n }\r\n sounds.set(id, {\r\n buffer,\r\n gain: context.createGain(),\r\n panner: new StereoPannerNode(context, {pan: 0}),\r\n });\r\n },\r\n duplicate_sound(id, srcId) {\r\n const src = sounds.get(srcId);\r\n if (!src) {\r\n return;\r\n }\r\n sounds.set(id, {\r\n buffer: src.buffer,\r\n gain: context.createGain(),\r\n panner: new StereoPannerNode(context, {pan: 0}),\r\n });\r\n },\r\n play_sound(id, volume, pan, loop) {\r\n const src = sounds.get(id);\r\n if (src) {\r\n if (src.source) {\r\n src.source.stop();\r\n }\r\n src.gain.gain.value = Math.pow(2.0, volume / 1000.0);\r\n const relVolume = Math.pow(2.0, pan / 1000.0);\r\n src.panner.pan.value = 1.0 - 2.0 / (1.0 + relVolume);\r\n src.source = context.createBufferSource();\r\n src.source.buffer = src.buffer;\r\n src.source.loop = !!loop;\r\n src.source.connect(src.gain).connect(src.panner).connect(context.destination);\r\n src.source.start();\r\n }\r\n },\r\n set_volume(id, volume) {\r\n const src = sounds.get(id);\r\n if (src) {\r\n src.gain.gain.value = Math.pow(2.0, volume / 1000.0);\r\n }\r\n },\r\n stop_sound(id) {\r\n const src = sounds.get(id);\r\n if (src && src.source) {\r\n src.source.stop();\r\n delete src.source;\r\n }\r\n },\r\n delete_sound(id) {\r\n const src = sounds.get(id);\r\n if (src && src.source) {\r\n src.source.stop();\r\n }\r\n sounds.delete(id);\r\n },\r\n };\r\n}\r\n","import React from 'react';\r\nimport './App.scss';\r\nimport classNames from 'classnames';\r\n\r\nimport create_fs from './fs';\r\nimport load_game from './api/loader';\r\nimport { SpawnSize } from './api/load_spawn';\r\n\r\nfunction isDropFile(e) {\r\n if (e.dataTransfer.items) {\r\n for (let i = 0; i < e.dataTransfer.items.length; ++i) {\r\n if (e.dataTransfer.items[i].kind === \"file\") {\r\n return true;\r\n }\r\n }\r\n } if (e.dataTransfer.files.length) {\r\n return true;\r\n }\r\n return false;\r\n}\r\nfunction getDropFile(e) {\r\n if (e.dataTransfer.items) {\r\n for (let i = 0; i < e.dataTransfer.items.length; ++i) {\r\n if (e.dataTransfer.items[i].kind === \"file\") {\r\n return e.dataTransfer.items[i].getAsFile();\r\n }\r\n }\r\n } if (e.dataTransfer.files.length) {\r\n return e.dataTransfer.files[0];\r\n }\r\n}\r\n\r\nconst TOUCH_MOVE = 0;\r\nconst TOUCH_RMB = 1;\r\nconst TOUCH_SHIFT = 2;\r\n\r\nconst Link = ({children, ...props}) => {children};\r\n\r\nclass App extends React.Component {\r\n files = new Map();\r\n state = {started: false, loading: false, touch: false, dropping: 0, has_spawn: false};\r\n cursorPos = {x: 0, y: 0};\r\n\r\n touchButtons = [null, null, null, null, null, null];\r\n touchCtx = [null, null, null, null, null, null];\r\n touchMods = [false, false, false, false, false, false];\r\n touchBelt = [-1, -1, -1, -1, -1, -1];\r\n\r\n fs = create_fs(true);\r\n\r\n constructor(props) {\r\n super(props);\r\n\r\n this.setTouch0 = this.setTouch_.bind(this, 0);\r\n this.setTouch1 = this.setTouch_.bind(this, 1);\r\n this.setTouch2 = this.setTouch_.bind(this, 2);\r\n this.setTouch3 = this.setTouchBelt_.bind(this, 3);\r\n this.setTouch4 = this.setTouchBelt_.bind(this, 4);\r\n this.setTouch5 = this.setTouchBelt_.bind(this, 5);\r\n }\r\n\r\n componentDidMount() {\r\n document.addEventListener(\"drop\", this.onDrop, true);\r\n document.addEventListener(\"dragover\", this.onDragOver, true);\r\n document.addEventListener(\"dragenter\", this.onDragEnter, true);\r\n document.addEventListener(\"dragleave\", this.onDragLeave, true);\r\n\r\n this.fs.then(fs => {\r\n const spawn = fs.files.get('spawn.mpq');\r\n if (spawn && spawn.byteLength === SpawnSize) {\r\n this.setState({has_spawn: true});\r\n }\r\n });\r\n }\r\n\r\n onDrop = e => {\r\n const file = getDropFile(e);\r\n if (file) {\r\n e.preventDefault();\r\n this.start(file);\r\n }\r\n this.setState({dropping: 0});\r\n }\r\n onDragEnter = e => {\r\n e.preventDefault();\r\n this.setDropping(1);\r\n }\r\n onDragOver = e => {\r\n if (isDropFile(e)) {\r\n e.preventDefault();\r\n }\r\n }\r\n onDragLeave = e => {\r\n this.setDropping(-1);\r\n }\r\n setDropping(inc) {\r\n this.setState(({dropping}) => ({dropping: Math.max(dropping + inc, 0)}));\r\n }\r\n\r\n onError(text) {\r\n this.setState({error: text});\r\n }\r\n\r\n openKeyboard(open) {\r\n if (open) {\r\n this.showKeyboard = true;\r\n this.element.classList.add(\"keyboard\");\r\n this.keyboard.focus();\r\n } else {\r\n this.showKeyboard = false;\r\n this.element.classList.remove(\"keyboard\");\r\n this.keyboard.blur();\r\n }\r\n }\r\n\r\n setCursorPos(x, y) {\r\n const rect = this.canvas.getBoundingClientRect();\r\n this.cursorPos = {\r\n x: rect.left + (rect.right - rect.left) * x / 640,\r\n y: rect.top + (rect.bottom - rect.top) * y / 480,\r\n };\r\n setTimeout(() => {\r\n this.game(\"DApi_Mouse\", 0, 0, 0, x, y);\r\n });\r\n }\r\n\r\n onProgress(progress) {\r\n this.setState({progress});\r\n }\r\n\r\n drawBelt(idx, slot) {\r\n if (!this.touchButtons[idx]) {\r\n return;\r\n }\r\n this.touchBelt[idx] = slot;\r\n if (slot >= 0) {\r\n this.touchButtons[idx].style.display = \"block\";\r\n this.touchCtx[idx].drawImage(this.canvas, 205 + 29 * slot, 357, 28, 28, 0, 0, 28, 28);\r\n } else {\r\n this.touchButtons[idx].style.display = \"none\";\r\n }\r\n }\r\n\r\n updateBelt(belt) {\r\n if (belt) {\r\n const used = new Set();\r\n let pos = 3;\r\n for (let i = 0; i < belt.length && pos < 6; ++i) {\r\n if (belt[i] >= 0 && !used.has(belt[i])) {\r\n this.drawBelt(pos++, i);\r\n used.add(belt[i]);\r\n }\r\n }\r\n for (; pos < 6; ++pos) {\r\n this.drawBelt(pos, -1);\r\n }\r\n } else {\r\n this.drawBelt(3, -1);\r\n this.drawBelt(4, -1);\r\n this.drawBelt(5, -1);\r\n }\r\n }\r\n\r\n start(file) {\r\n document.removeEventListener(\"drop\", this.onDrop, true);\r\n document.removeEventListener(\"dragover\", this.onDragOver, true);\r\n document.removeEventListener(\"dragenter\", this.onDragEnter, true);\r\n document.removeEventListener(\"dragleave\", this.onDragLeave, true);\r\n this.setState({dropping: 0});\r\n\r\n this.setState({loading: true});\r\n\r\n load_game(this, file).then(game => {\r\n this.game = game;\r\n\r\n document.addEventListener('mousemove', this.onMouseMove, true);\r\n document.addEventListener('mousedown', this.onMouseDown, true);\r\n document.addEventListener('mouseup', this.onMouseUp, true);\r\n document.addEventListener('keydown', this.onKeyDown, true);\r\n document.addEventListener('keyup', this.onKeyUp, true);\r\n document.addEventListener('contextmenu', this.onMenu, true);\r\n\r\n document.addEventListener('touchstart', this.onTouchStart, {passive: false, capture: true});\r\n document.addEventListener('touchmove', this.onTouchMove, {passive: false, capture: true});\r\n document.addEventListener('touchend', this.onTouchEnd, {passive: false, capture: true});\r\n\r\n document.addEventListener('pointerlockchange', this.onPointerLockChange);\r\n document.addEventListener('fullscreenchange', this.onFullscreenChange);\r\n window.addEventListener('resize', this.onResize);\r\n\r\n this.setState({started: true});\r\n }, e => this.onError(e.message));\r\n }\r\n\r\n pointerLocked() {\r\n return document.pointerLockElement === this.canvas || document.mozPointerLockElement === this.canvas;\r\n }\r\n\r\n mousePos(e) {\r\n const rect = this.canvas.getBoundingClientRect();\r\n if (this.pointerLocked()) {\r\n this.cursorPos.x = Math.max(rect.left, Math.min(rect.right, this.cursorPos.x + e.movementX));\r\n this.cursorPos.y = Math.max(rect.top, Math.min(rect.bottom, this.cursorPos.y + e.movementY));\r\n } else {\r\n this.cursorPos = {x: e.clientX, y: e.clientY};\r\n }\r\n return {\r\n x: Math.max(0, Math.min(Math.round((this.cursorPos.x - rect.left) / (rect.right - rect.left) * 640), 639)),\r\n y: Math.max(0, Math.min(Math.round((this.cursorPos.y - rect.top) / (rect.bottom - rect.top) * 480), 479)),\r\n };\r\n }\r\n\r\n mouseButton(e) {\r\n switch (e.button) {\r\n case 0: return 1;\r\n case 1: return 4;\r\n case 2: return 2;\r\n case 3: return 5;\r\n case 4: return 6;\r\n default: return 1;\r\n }\r\n }\r\n eventMods(e) {\r\n return ((e.shiftKey || this.touchMods[TOUCH_SHIFT]) ? 1 : 0) + (e.ctrlKey ? 2 : 0) + (e.altKey ? 4 : 0) + (e.touches ? 8 : 0);\r\n }\r\n\r\n onResize = () => {\r\n document.exitPointerLock();\r\n }\r\n\r\n onPointerLockChange = () => {\r\n if (window.screen && window.innerHeight === window.screen.height && !this.pointerLocked()) {\r\n // assume that the user pressed escape\r\n this.game(\"DApi_Key\", 0, 0, 27);\r\n this.game(\"DApi_Key\", 1, 0, 27);\r\n }\r\n }\r\n\r\n onMouseMove = e => {\r\n if (!this.canvas) return;\r\n const {x, y} = this.mousePos(e);\r\n this.game(\"DApi_Mouse\", 0, 0, this.eventMods(e), x, y);\r\n e.preventDefault();\r\n }\r\n\r\n onMouseDown = e => {\r\n if (!this.canvas) return;\r\n const {x, y} = this.mousePos(e);\r\n if (window.screen && window.innerHeight === window.screen.height) {\r\n // we're in fullscreen, let's get pointer lock!\r\n if (!this.pointerLocked()) {\r\n this.canvas.requestPointerLock();\r\n }\r\n }\r\n this.game(\"DApi_Mouse\", 1, this.mouseButton(e), this.eventMods(e), x, y);\r\n e.preventDefault();\r\n }\r\n\r\n onMouseUp = e => {\r\n if (!this.canvas) return;\r\n const {x, y} = this.mousePos(e);\r\n this.game(\"DApi_Mouse\", 2, this.mouseButton(e), this.eventMods(e), x, y);\r\n e.preventDefault();\r\n }\r\n\r\n onKeyDown = e => {\r\n if (!this.canvas) return;\r\n this.game(\"DApi_Key\", 0, this.eventMods(e), e.keyCode);\r\n if (e.keyCode >= 32 && e.key.length === 1 && !this.showKeyboard) {\r\n this.game(\"DApi_Char\", e.key.charCodeAt(0));\r\n }\r\n this.clearKeySel();\r\n if (!this.showKeyboard) {\r\n if (e.keyCode === 8 || (e.keyCode >= 112 && e.keyCode <= 119)) {\r\n e.preventDefault();\r\n }\r\n }\r\n }\r\n\r\n onMenu = e => {\r\n e.preventDefault();\r\n }\r\n\r\n onKeyUp = e => {\r\n if (!this.canvas) return;\r\n this.game(\"DApi_Key\", 1, this.eventMods(e), e.keyCode);\r\n this.clearKeySel();\r\n }\r\n\r\n clearKeySel() {\r\n if (this.showKeyboard) {\r\n const len = this.keyboard.value.length;\r\n this.keyboard.setSelectionRange(len, len);\r\n }\r\n }\r\n\r\n onKeyboard = () => {\r\n if (this.showKeyboard) {\r\n const text = this.keyboard.value;\r\n const valid = (text.match(/[\\x20-\\x7E]/g) || []).join(\"\").substring(0, 15);\r\n if (text !== valid) {\r\n this.keyboard.value = valid;\r\n }\r\n this.clearKeySel();\r\n const values = [...Array(15)].map((_, i) => i < valid.length ? valid.charCodeAt(i) : 0);\r\n this.game(\"DApi_SyncText\", ...values);\r\n }\r\n }\r\n\r\n parseFile = e => {\r\n const files = e.target.files;\r\n if (files.length > 0) {\r\n this.start(files[0]);\r\n }\r\n }\r\n\r\n touchButton = null;\r\n touchCanvas = null;\r\n\r\n onFullscreenChange = () => {\r\n this.setState({touch: (document.fullscreenElement === this.element)});\r\n }\r\n\r\n setTouchMod(index, value, use) {\r\n if (index < 3) {\r\n this.touchMods[index] = value;\r\n if (this.touchButtons[index]) {\r\n this.touchButtons[index].classList.toggle(\"active\", value);\r\n }\r\n } else if (use && this.touchBelt[index] >= 0) {\r\n const now = performance.now();\r\n if (!this.beltTime || now - this.beltTime > 750) {\r\n this.game(\"DApi_Char\", 49 + this.touchBelt[index]);\r\n this.beltTime = now;\r\n }\r\n }\r\n }\r\n\r\n updateTouchButton(touches, release) {\r\n let touchOther = null;\r\n const btn = this.touchButton;\r\n for (let {target, identifier, clientX, clientY} of touches) {\r\n if (btn && btn.id === identifier && this.touchButtons[btn.index] === target) {\r\n if (touches.length > 1) {\r\n btn.stick = false;\r\n }\r\n btn.clientX = clientX;\r\n btn.clientY = clientY;\r\n this.touchCanvas = [...touches].find(t => t.identifier !== identifier);\r\n if (this.touchCanvas) {\r\n this.touchCanvas = {clientX: this.touchCanvas.clientX, clientY: this.touchCanvas.clientY};\r\n }\r\n delete this.panPos;\r\n return this.touchCanvas != null;\r\n }\r\n const idx = this.touchButtons.indexOf(target);\r\n if (idx >= 0 && !touchOther) {\r\n touchOther = {id: identifier, index: idx, stick: true, original: this.touchMods[idx], clientX, clientY};\r\n }\r\n }\r\n if (btn && !touchOther && release && btn.stick) {\r\n const rect = this.touchButtons[btn.index].getBoundingClientRect();\r\n const {clientX, clientY} = btn;\r\n if (clientX >= rect.left && clientX < rect.right && clientY >= rect.top && clientY < rect.bottom) {\r\n this.setTouchMod(btn.index, !btn.original, true);\r\n } else {\r\n this.setTouchMod(btn.index, btn.original);\r\n }\r\n } else if (btn) {\r\n this.setTouchMod(btn.index, false);\r\n }\r\n this.touchButton = touchOther;\r\n if (touchOther) {\r\n this.setTouchMod(touchOther.index, true);\r\n if (touchOther.index === TOUCH_MOVE) {\r\n this.setTouchMod(TOUCH_RMB, false);\r\n } else if (touchOther.index === TOUCH_RMB) {\r\n this.setTouchMod(TOUCH_MOVE, false);\r\n }\r\n delete this.panPos;\r\n } else if (touches.length === 2) {\r\n const x = (touches[1].clientX + touches[0].clientX) / 2, y = (touches[1].clientY + touches[0].clientY) / 2;\r\n if (this.panPos) {\r\n const dx = x - this.panPos.x, dy = y - this.panPos.y;\r\n const step = this.canvas.offsetHeight / 12;\r\n if (Math.max(Math.abs(dx), Math.abs(dy)) > step) {\r\n let key;\r\n if (Math.abs(dx) > Math.abs(dy)) {\r\n key = (dx > 0 ? 0x25 : 0x27);\r\n } else {\r\n key = (dy > 0 ? 0x26 : 0x28);\r\n }\r\n this.game(\"DApi_Key\", 0, 0, key);\r\n // key up is ignored anyway\r\n this.panPos = {x, y};\r\n }\r\n } else {\r\n this.game(\"DApi_Mouse\", 0, 0, 24, 320, 180);\r\n this.game(\"DApi_Mouse\", 2, 1, 24, 320, 180);\r\n this.panPos = {x, y};\r\n }\r\n this.touchCanvas = null;\r\n return false;\r\n } else {\r\n delete this.panPos;\r\n }\r\n this.touchCanvas = [...touches].find(t => !touchOther || t.identifier !== touchOther.id);\r\n if (this.touchCanvas) {\r\n this.touchCanvas = {clientX: this.touchCanvas.clientX, clientY: this.touchCanvas.clientY};\r\n }\r\n return this.touchCanvas != null;\r\n }\r\n\r\n onTouchStart = e => {\r\n if (!this.canvas) return;\r\n e.preventDefault();\r\n if (this.updateTouchButton(e.touches, false)) {\r\n const {x, y} = this.mousePos(this.touchCanvas);\r\n this.game(\"DApi_Mouse\", 0, 0, this.eventMods(e), x, y);\r\n if (!this.touchMods[TOUCH_MOVE]) {\r\n this.game(\"DApi_Mouse\", 1, this.touchMods[TOUCH_RMB] ? 2 : 1, this.eventMods(e), x, y);\r\n }\r\n }\r\n }\r\n onTouchMove = e => {\r\n if (!this.canvas) return;\r\n e.preventDefault();\r\n if (this.updateTouchButton(e.touches, false)) {\r\n const {x, y} = this.mousePos(this.touchCanvas);\r\n this.game(\"DApi_Mouse\", 0, 0, this.eventMods(e), x, y);\r\n }\r\n }\r\n onTouchEnd = e => {\r\n if (!this.canvas) return;\r\n e.preventDefault();\r\n const prevTc = this.touchCanvas;\r\n this.updateTouchButton(e.touches, true);\r\n if (prevTc && !this.touchCanvas) {\r\n const {x, y} = this.mousePos(prevTc);\r\n this.game(\"DApi_Mouse\", 2, 1, this.eventMods(e), x, y);\r\n this.game(\"DApi_Mouse\", 2, 2, this.eventMods(e), x, y);\r\n\r\n if (this.touchMods[TOUCH_RMB] && (!this.touchButton || this.touchButton.index !== TOUCH_RMB)) {\r\n this.setTouchButton(TOUCH_RMB, false);\r\n }\r\n }\r\n if (!document.fullscreenElement) {\r\n this.element.requestFullscreen();\r\n }\r\n }\r\n\r\n setCanvas = e => this.canvas = e;\r\n setElement = e => this.element = e;\r\n setKeyboard = e => this.keyboard = e;\r\n setTouch_(i, e) {\r\n this.touchButtons[i] = e;\r\n }\r\n setTouchBelt_(i, e) {\r\n this.touchButtons[i] = e;\r\n if (e) {\r\n const canvas = document.createElement(\"canvas\");\r\n canvas.width = 28;\r\n canvas.height = 28;\r\n e.appendChild(canvas);\r\n this.touchCtx[i] = canvas.getContext(\"2d\");\r\n } else {\r\n this.touchCtx[i] = null;\r\n }\r\n }\r\n\r\n render() {\r\n const {started, loading, error, progress, dropping, touch, has_spawn} = this.state;\r\n return (\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n {!error && }\r\n \r\n
\r\n
\r\n {!!error && (\r\n \r\n

The following error has occurred:

\r\n

{error}

\r\n

Click to go to GitHub issues

\r\n \r\n )}\r\n {!!loading && !started && !error && (\r\n
\r\n {(progress && progress.text) || 'Loading...'}\r\n {progress != null && !!progress.total && (\r\n \r\n )}\r\n
\r\n )}\r\n {!started && !loading && !error && (\r\n
\r\n

\r\n This is a web port of the original Diablo game, based on source code reconstructed by\r\n GalaXyHaXz and devilution team: https://github.com/diasurgical/devilution\r\n

\r\n

\r\n If you own the original game, you can drop the original DIABDAT.MPQ onto this page or click the button below to start playing.\r\n The game can be purchased from GoG.\r\n

\r\n {!has_spawn && (\r\n

\r\n Or you can play the shareware version for free (50MB download).\r\n

\r\n )}\r\n
\r\n \r\n \r\n
\r\n this.start()}>Play Shareware\r\n
\r\n )}\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default App;\r\n","import React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport './reset.css';\r\nimport * as serviceWorker from './serviceWorker';\r\n\r\nimport App from './App';\r\n\r\nReactDOM.render(, document.getElementById('root'));\r\n\r\nserviceWorker.register();\r\n","import IdbKvStore from 'idb-kv-store';\r\n\r\nconst importStorage = () => new Promise((resolve, reject) => {\r\n let done = false;\r\n const frame = document.createElement('iframe');\r\n window.addEventListener('message', ({data}) => {\r\n if (data.method === 'storage' && !done) {\r\n done = true;\r\n resolve(data.files);\r\n frame.contentWindow.postMessage({method: 'clear'}, '*');\r\n }\r\n });\r\n frame.addEventListener('load', () => {\r\n frame.contentWindow.postMessage({method: 'transfer'}, '*');\r\n });\r\n frame.addEventListener('error', () => {\r\n if (!done) {\r\n done = true;\r\n resolve(null);\r\n }\r\n });\r\n frame.src = \"https://diablo.rivsoft.net/storage.html\";\r\n frame.style.display = \"none\";\r\n document.body.appendChild(frame);\r\n setTimeout(() => {\r\n if (!done) {\r\n done = true;\r\n resolve(null);\r\n }\r\n }, 10000);\r\n});\r\n\r\nasync function downloadFile(store, name) {\r\n const file = await store.get(name.toLowerCase());\r\n if (file) {\r\n const blob = new Blob([file], {type: 'binary/octet-stream'});\r\n const url = URL.createObjectURL(blob);\r\n const lnk = document.createElement('a');\r\n lnk.setAttribute('href', url);\r\n lnk.setAttribute('download', name);\r\n document.body.appendChild(lnk);\r\n lnk.click();\r\n document.body.removeChild(lnk);\r\n URL.revokeObjectURL(url);\r\n } else {\r\n console.error(`File ${name} does not exist`);\r\n }\r\n}\r\n\r\nexport default async function create_fs(load) {\r\n try {\r\n const store = new IdbKvStore('diablo_fs');\r\n const files = new Map();\r\n for (let [name, data] of Object.entries(await store.json())) {\r\n files.set(name, data);\r\n }\r\n if (load) {\r\n const files = await importStorage();\r\n if (files) {\r\n for (let [name, data] of files) {\r\n files.set(name, data);\r\n store.set(name, data);\r\n }\r\n }\r\n }\r\n window.DownloadFile = name => downloadFile(store, name);\r\n return {\r\n files,\r\n update: (name, data) => store.set(name, data),\r\n delete: name => store.remove(name),\r\n clear: () => store.clear(),\r\n };\r\n } catch (e) {\r\n window.DownloadFile = () => console.error('IndexedDB is not supported');\r\n return {\r\n files: new Map(),\r\n update: () => Promise.resolve(),\r\n delete: () => Promise.resolve(),\r\n clear: () => Promise.resolve(),\r\n };\r\n } \r\n}\r\n"],"sourceRoot":""} \ No newline at end of file