diff --git a/.github/500stars/README.md b/.github/500stars/README.md
new file mode 100644
index 00000000..9ad3d6d1
--- /dev/null
+++ b/.github/500stars/README.md
@@ -0,0 +1,16 @@
+# Techmino - 500-star Banner
+Created by NOT_A_ROBOT
+13 September, 2024
+
+**Don't forget to attribute me when using this.**
+The image already includes sufficient attribution, so if you just don't crop that out, you shouldn't need to explicitly mention them.
+
+## Attribution
+Created by NOT_A_ROBOT
+GitHub logo (on Z-character's screen) by GitHub
+Background (space stars) originally by MrZ, ported to JS by NOT_A_ROBOT for rendering
+Block skin (featured in the background) by Scf, slightly modified to make it darker
+Z-character drawn by 葉枭, designed by MrZ
+Techmino by MrZ and many contributors
+
+Techmino is fun! https://github.com/26F-Studio/Techmino
diff --git a/.github/500stars/exported.png b/.github/500stars/exported.png
new file mode 100644
index 00000000..e3751e68
Binary files /dev/null and b/.github/500stars/exported.png differ
diff --git a/.github/actions/get-cc/action.yml b/.github/actions/get-cc/action.yml
deleted file mode 100644
index ea348ee9..00000000
--- a/.github/actions/get-cc/action.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: 'get cc'
-description: 'download cc into specific dir'
-inputs:
- tag:
- required: false
- default: "11.4.2"
- platform:
- required: true
- dir:
- required: false
- default: '.'
- repo:
- required: false
- default: 26F-Studio/cold_clear_ai_love2d_wrapper
- temp-file:
- required: false
- default: temp.zip
-runs:
- using: "composite"
- steps:
- - run: |
- echo "tag="$(if [ -z "${{ inputs.tag }}" ]
- then curl -w '%{url_effective}' -I -L -s -S https://github.com/${{ inputs.repo }}/releases/latest -o /dev/null | grep -o '\<[^/]*$'
- else echo ${{ inputs.tag }}
- fi) >> $GITHUB_OUTPUT
- id: get-tag
- shell: bash
- - uses: ./.github/actions/get-unzip
- with:
- url: https://github.com/${{ inputs.repo }}/releases/download/${{ steps.get-tag.outputs.tag }}/${{ inputs.platform }}.zip
- dir: ${{ inputs.dir }}
- temp-file: ${{ inputs.temp-file }}
diff --git a/.github/build/extraLibs/Windows_x64/discord-rpc.dll b/.github/build/extraLibs/Windows_x64/discord-rpc.dll
new file mode 100644
index 00000000..8493c549
Binary files /dev/null and b/.github/build/extraLibs/Windows_x64/discord-rpc.dll differ
diff --git a/.github/build/extraLibs/Windows_x86/discord-rpc.dll b/.github/build/extraLibs/Windows_x86/discord-rpc.dll
new file mode 100644
index 00000000..8493c549
Binary files /dev/null and b/.github/build/extraLibs/Windows_x86/discord-rpc.dll differ
diff --git a/.github/build/web/dev/favicon.ico b/.github/build/web/dev/favicon.ico
new file mode 100644
index 00000000..deabb9cc
Binary files /dev/null and b/.github/build/web/dev/favicon.ico differ
diff --git a/.github/build/web/dev/index.html b/.github/build/web/dev/index.html
new file mode 100644
index 00000000..bf2cf577
--- /dev/null
+++ b/.github/build/web/dev/index.html
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+ Techmino Development
+
+
+
+
+
+
+
+
+
Techmino
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/build/web/game.js b/.github/build/web/game.js
deleted file mode 100644
index f0755e5f..00000000
--- a/.github/build/web/game.js
+++ /dev/null
@@ -1,288 +0,0 @@
-
-var Module;
-
-if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
-
-if (!Module.expectedDataFileDownloads) {
- Module.expectedDataFileDownloads = 0;
- Module.finishedDataFileDownloads = 0;
-}
-Module.expectedDataFileDownloads++;
-(function() {
- var loadPackage = function(metadata) {
-
- var PACKAGE_PATH;
- if (typeof window === 'object') {
- PACKAGE_PATH = window['encodeURIComponent'](window.location.pathname.toString().substring(0, window.location.pathname.toString().lastIndexOf('/')) + '/');
- } else if (typeof location !== 'undefined') {
- // worker
- PACKAGE_PATH = encodeURIComponent(location.pathname.toString().substring(0, location.pathname.toString().lastIndexOf('/')) + '/');
- } else {
- throw 'using preloaded data can only be done on a web page or in a web worker';
- }
- var PACKAGE_NAME = 'game.data';
- var REMOTE_PACKAGE_BASE = 'game.data';
- if (typeof Module['locateFilePackage'] === 'function' && !Module['locateFile']) {
- Module['locateFile'] = Module['locateFilePackage'];
- Module.printErr('warning: you defined Module.locateFilePackage, that has been renamed to Module.locateFile (using your locateFilePackage for now)');
- }
- var REMOTE_PACKAGE_NAME = typeof Module['locateFile'] === 'function' ?
- Module['locateFile'](REMOTE_PACKAGE_BASE) :
- ((Module['filePackagePrefixURL'] || '') + REMOTE_PACKAGE_BASE);
-
- var REMOTE_PACKAGE_SIZE = metadata.remote_package_size;
- var PACKAGE_UUID = metadata.package_uuid;
-
- function fetchRemotePackage(packageName, packageSize, callback, errback) {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', packageName, true);
- xhr.responseType = 'arraybuffer';
- xhr.onprogress = function(event) {
- var url = packageName;
- var size = packageSize;
- if (event.total) size = event.total;
- if (event.loaded) {
- if (!xhr.addedTotal) {
- xhr.addedTotal = true;
- if (!Module.dataFileDownloads) Module.dataFileDownloads = {};
- Module.dataFileDownloads[url] = {
- loaded: event.loaded,
- total: size
- };
- } else {
- Module.dataFileDownloads[url].loaded = event.loaded;
- }
- var total = 0;
- var loaded = 0;
- var num = 0;
- for (var download in Module.dataFileDownloads) {
- var data = Module.dataFileDownloads[download];
- total += data.total;
- loaded += data.loaded;
- num++;
- }
- total = Math.ceil(total * Module.expectedDataFileDownloads/num);
- if (Module['setStatus']) Module['setStatus']('Downloading data... (' + loaded + '/' + total + ')');
- } else if (!Module.dataFileDownloads) {
- if (Module['setStatus']) Module['setStatus']('Downloading data...');
- }
- };
- xhr.onerror = function(event) {
- throw new Error("NetworkError for: " + packageName);
- }
- xhr.onload = function(event) {
- if (xhr.status == 200 || xhr.status == 304 || xhr.status == 206 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
- var packageData = xhr.response;
- callback(packageData);
- } else {
- throw new Error(xhr.statusText + " : " + xhr.responseURL);
- }
- };
- xhr.send(null);
- };
-
- function handleError(error) {
- console.error('package error:', error);
- };
-
- function runWithFS() {
-
- function assert(check, msg) {
- if (!check) throw msg + new Error().stack;
- }
-
- function DataRequest(start, end, crunched, audio) {
- this.start = start;
- this.end = end;
- this.crunched = crunched;
- this.audio = audio;
- }
- DataRequest.prototype = {
- requests: {},
- open: function(mode, name) {
- this.name = name;
- this.requests[name] = this;
- Module['addRunDependency']('fp ' + this.name);
- },
- send: function() {},
- onload: function() {
- var byteArray = this.byteArray.subarray(this.start, this.end);
-
- this.finish(byteArray);
-
- },
- finish: function(byteArray) {
- var that = this;
-
- Module['FS_createDataFile'](this.name, null, byteArray, true, true, true); // canOwn this data in the filesystem, it is a slide into the heap that will never change
- Module['removeRunDependency']('fp ' + that.name);
-
- this.requests[this.name] = null;
- }
- };
-
- var files = metadata.files;
- for (i = 0; i < files.length; ++i) {
- new DataRequest(files[i].start, files[i].end, files[i].crunched, files[i].audio).open('GET', files[i].filename);
- }
-
-
- var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
- var IDB_RO = "readonly";
- var IDB_RW = "readwrite";
- var DB_NAME = "EM_PRELOAD_CACHE";
- var DB_VERSION = 1;
- var METADATA_STORE_NAME = 'METADATA';
- var PACKAGE_STORE_NAME = 'PACKAGES';
- function openDatabase(callback, errback) {
- try {
- var openRequest = indexedDB.open(DB_NAME, DB_VERSION);
- } catch (e) {
- return errback(e);
- }
- openRequest.onupgradeneeded = function(event) {
- var db = event.target.result;
-
- if(db.objectStoreNames.contains(PACKAGE_STORE_NAME)) {
- db.deleteObjectStore(PACKAGE_STORE_NAME);
- }
- var packages = db.createObjectStore(PACKAGE_STORE_NAME);
-
- if(db.objectStoreNames.contains(METADATA_STORE_NAME)) {
- db.deleteObjectStore(METADATA_STORE_NAME);
- }
- var metadata = db.createObjectStore(METADATA_STORE_NAME);
- };
- openRequest.onsuccess = function(event) {
- var db = event.target.result;
- callback(db);
- };
- openRequest.onerror = function(error) {
- errback(error);
- };
- };
-
- /* Check if there's a cached package, and if so whether it's the latest available */
- function checkCachedPackage(db, packageName, callback, errback) {
- var transaction = db.transaction([METADATA_STORE_NAME], IDB_RO);
- var metadata = transaction.objectStore(METADATA_STORE_NAME);
-
- var getRequest = metadata.get("metadata/" + packageName);
- getRequest.onsuccess = function(event) {
- var result = event.target.result;
- if (!result) {
- return callback(false);
- } else {
- return callback(PACKAGE_UUID === result.uuid);
- }
- };
- getRequest.onerror = function(error) {
- errback(error);
- };
- };
-
- function fetchCachedPackage(db, packageName, callback, errback) {
- var transaction = db.transaction([PACKAGE_STORE_NAME], IDB_RO);
- var packages = transaction.objectStore(PACKAGE_STORE_NAME);
-
- var getRequest = packages.get("package/" + packageName);
- getRequest.onsuccess = function(event) {
- var result = event.target.result;
- callback(result);
- };
- getRequest.onerror = function(error) {
- errback(error);
- };
- };
-
- function cacheRemotePackage(db, packageName, packageData, packageMeta, callback, errback) {
- var transaction_packages = db.transaction([PACKAGE_STORE_NAME], IDB_RW);
- var packages = transaction_packages.objectStore(PACKAGE_STORE_NAME);
-
- var putPackageRequest = packages.put(packageData, "package/" + packageName);
- putPackageRequest.onsuccess = function(event) {
- var transaction_metadata = db.transaction([METADATA_STORE_NAME], IDB_RW);
- var metadata = transaction_metadata.objectStore(METADATA_STORE_NAME);
- var putMetadataRequest = metadata.put(packageMeta, "metadata/" + packageName);
- putMetadataRequest.onsuccess = function(event) {
- callback(packageData);
- };
- putMetadataRequest.onerror = function(error) {
- errback(error);
- };
- };
- putPackageRequest.onerror = function(error) {
- errback(error);
- };
- };
-
- function processPackageData(arrayBuffer) {
- Module.finishedDataFileDownloads++;
- assert(arrayBuffer, 'Loading data file failed.');
- assert(arrayBuffer instanceof ArrayBuffer, 'bad input to processPackageData');
- var byteArray = new Uint8Array(arrayBuffer);
- var curr;
-
- // copy the entire loaded file into a spot in the heap. Files will refer to slices in that. They cannot be freed though
- // (we may be allocating before malloc is ready, during startup).
- if (Module['SPLIT_MEMORY']) Module.printErr('warning: you should run the file packager with --no-heap-copy when SPLIT_MEMORY is used, otherwise copying into the heap may fail due to the splitting');
- var ptr = Module['getMemory'](byteArray.length);
- Module['HEAPU8'].set(byteArray, ptr);
- DataRequest.prototype.byteArray = Module['HEAPU8'].subarray(ptr, ptr+byteArray.length);
-
- var files = metadata.files;
- for (i = 0; i < files.length; ++i) {
- DataRequest.prototype.requests[files[i].filename].onload();
- }
- Module['removeRunDependency']('datafile_game.data');
-
- };
- Module['addRunDependency']('datafile_game.data');
-
- if (!Module.preloadResults) Module.preloadResults = {};
-
- function preloadFallback(error) {
- console.error(error);
- console.error('falling back to default preload behavior');
- fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE, processPackageData, handleError);
- };
-
- openDatabase(
- function(db) {
- checkCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME,
- function(useCached) {
- Module.preloadResults[PACKAGE_NAME] = {fromCache: useCached};
- if (useCached) {
- console.info('loading ' + PACKAGE_NAME + ' from cache');
- fetchCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME, processPackageData, preloadFallback);
- } else {
- console.info('loading ' + PACKAGE_NAME + ' from remote');
- fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE,
- function(packageData) {
- cacheRemotePackage(db, PACKAGE_PATH + PACKAGE_NAME, packageData, {uuid:PACKAGE_UUID}, processPackageData,
- function(error) {
- console.error(error);
- processPackageData(packageData);
- });
- }
- , preloadFallback);
- }
- }
- , preloadFallback);
- }
- , preloadFallback);
-
- if (Module['setStatus']) Module['setStatus']('Downloading...');
-
- }
- if (Module['calledRun']) {
- runWithFS();
- } else {
- if (!Module['preRun']) Module['preRun'] = [];
- Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it
- }
-
- }
- loadPackage({"package_uuid":"80826f15-f924-4428-a8c4-e984743417c6","remote_package_size":62246034,"files":[{"filename":"/game.love","crunched":0,"start":0,"end":62246034,"audio":false}]});
-
-})();
diff --git a/.github/build/web/love.js b/.github/build/web/love.js
deleted file mode 100644
index 22e07ac9..00000000
--- a/.github/build/web/love.js
+++ /dev/null
@@ -1,22 +0,0 @@
-
-var Love = (function() {
- var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
- if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
- return (
-function(Love) {
- Love = Love || {};
-
-var Module=typeof Love!=="undefined"?Love:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise(function(resolve,reject){readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){return read(f)}}readBinary=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var STACK_ALIGN=16;function dynamicAlloc(size){var ret=HEAP32[DYNAMICTOP_PTR>>2];var end=ret+size+15&-16;HEAP32[DYNAMICTOP_PTR>>2]=end;return ret}function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;return Math.ceil(size/factor)*factor}function getNativeTypeSize(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return 4}else if(type[0]==="i"){var bits=Number(type.substr(1));assert(bits%8===0,"getNativeTypeSize invalid bits "+bits+", type "+type);return bits/8}else{return 0}}}}function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;err(text)}}function convertJsFunctionToWasm(func,sig){if(typeof WebAssembly.Function==="function"){var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":5397,"maximum":5397,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string")return UTF8ToString(ret);if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>2]=0}stop=ret+size;while(ptr>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function allocateUTF8(str){var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8Array(str,HEAP8,ret,size);return ret}function allocateUTF8OnStack(str){var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8Array(str,HEAP8,ret,size);return ret}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var STACK_BASE=7161696,DYNAMIC_BASE=7161696,DYNAMICTOP_PTR=1918800;var INITIAL_INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_INITIAL_MEMORY/WASM_PAGE_SIZE,"maximum":2147483648/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_INITIAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();TTY.init();SOCKFS.root=FS.mount(SOCKFS,{},null);callRuntimeCallbacks(__ATINIT__)}function preMain(){FS.ignorePermissions=false;callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}function hasPrefix(str,prefix){return String.prototype.startsWith?str.startsWith(prefix):str.indexOf(prefix)===0}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return hasPrefix(filename,dataURIPrefix)}var fileURIPrefix="file://";function isFileURI(filename){return hasPrefix(filename,fileURIPrefix)}var wasmBinaryFile="love.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return Promise.resolve().then(getBinary)}function createWasm(){var info={"env":asmLibraryArg,"wasi_snapshot_preview1":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;var ASM_CONSTS={354316:function($0){window.open(UTF8ToString($0));return 0},1016846:function($0,$1){alert(UTF8ToString($0)+"\n\n"+UTF8ToString($1))},1019084:function($0,$1,$2){var w=$0;var h=$1;var pixels=$2;if(!Module["SDL2"])Module["SDL2"]={};var SDL2=Module["SDL2"];if(SDL2.ctxCanvas!==Module["canvas"]){SDL2.ctx=Module["createContext"](Module["canvas"],false,true);SDL2.ctxCanvas=Module["canvas"]}if(SDL2.w!==w||SDL2.h!==h||SDL2.imageCtx!==SDL2.ctx){SDL2.image=SDL2.ctx.createImageData(w,h);SDL2.w=w;SDL2.h=h;SDL2.imageCtx=SDL2.ctx}var data=SDL2.image.data;var src=pixels>>2;var dst=0;var num;if(typeof CanvasPixelArray!=="undefined"&&data instanceof CanvasPixelArray){num=data.length;while(dst>8&255;data[dst+2]=val>>16&255;data[dst+3]=255;src++;dst+=4}}else{if(SDL2.data32Data!==data){SDL2.data32=new Int32Array(data.buffer);SDL2.data8=new Uint8Array(data.buffer)}var data32=SDL2.data32;num=data32.length;data32.set(HEAP32.subarray(src,src+num));var data8=SDL2.data8;var i=3;var j=i+4*num;if(num%8==0){while(i>2;var dst=0;var num;if(typeof CanvasPixelArray!=="undefined"&&data instanceof CanvasPixelArray){num=data.length;while(dst>8&255;data[dst+2]=val>>16&255;data[dst+3]=val>>24&255;src++;dst+=4}}else{var data32=new Int32Array(data.buffer);num=data32.length;data32.set(HEAP32.subarray(src,src+num))}ctx.putImageData(image,0,0);var url=hot_x===0&&hot_y===0?"url("+canvas.toDataURL()+"), auto":"url("+canvas.toDataURL()+") "+hot_x+" "+hot_y+", auto";var urlBuf=_malloc(url.length+1);stringToUTF8(url,urlBuf,url.length+1);return urlBuf},1021552:function($0){if(Module["canvas"]){Module["canvas"].style["cursor"]=UTF8ToString($0)}return 0},1021645:function(){if(Module["canvas"]){Module["canvas"].style["cursor"]="none"}},1022870:function(){return screen.width},1022897:function(){return screen.height},1022925:function(){return window.innerWidth},1022957:function(){return window.innerHeight},1023035:function($0){if(typeof setWindowTitle!=="undefined"){setWindowTitle(UTF8ToString($0))}return 0},1023169:function(){if(typeof AudioContext!=="undefined"){return 1}else if(typeof webkitAudioContext!=="undefined"){return 1}return 0},1023335:function(){if(typeof navigator.mediaDevices!=="undefined"&&typeof navigator.mediaDevices.getUserMedia!=="undefined"){return 1}else if(typeof navigator.webkitGetUserMedia!=="undefined"){return 1}return 0},1023561:function($0){if(typeof Module["SDL2"]==="undefined"){Module["SDL2"]={}}var SDL2=Module["SDL2"];if(!$0){SDL2.audio={}}else{SDL2.capture={}}if(!SDL2.audioContext){if(typeof AudioContext!=="undefined"){SDL2.audioContext=new AudioContext}else if(typeof webkitAudioContext!=="undefined"){SDL2.audioContext=new webkitAudioContext}if(SDL2.audioContext){autoResumeAudioContext(SDL2.audioContext)}}return SDL2.audioContext===undefined?-1:0},1024114:function(){var SDL2=Module["SDL2"];return SDL2.audioContext.sampleRate},1024184:function($0,$1,$2,$3){var SDL2=Module["SDL2"];var have_microphone=function(stream){if(SDL2.capture.silenceTimer!==undefined){clearTimeout(SDL2.capture.silenceTimer);SDL2.capture.silenceTimer=undefined}SDL2.capture.mediaStreamNode=SDL2.audioContext.createMediaStreamSource(stream);SDL2.capture.scriptProcessorNode=SDL2.audioContext.createScriptProcessor($1,$0,1);SDL2.capture.scriptProcessorNode.onaudioprocess=function(audioProcessingEvent){if(SDL2===undefined||SDL2.capture===undefined){return}audioProcessingEvent.outputBuffer.getChannelData(0).fill(0);SDL2.capture.currentCaptureBuffer=audioProcessingEvent.inputBuffer;dynCall("vi",$2,[$3])};SDL2.capture.mediaStreamNode.connect(SDL2.capture.scriptProcessorNode);SDL2.capture.scriptProcessorNode.connect(SDL2.audioContext.destination);SDL2.capture.stream=stream};var no_microphone=function(error){};SDL2.capture.silenceBuffer=SDL2.audioContext.createBuffer($0,$1,SDL2.audioContext.sampleRate);SDL2.capture.silenceBuffer.getChannelData(0).fill(0);var silence_callback=function(){SDL2.capture.currentCaptureBuffer=SDL2.capture.silenceBuffer;dynCall("vi",$2,[$3])};SDL2.capture.silenceTimer=setTimeout(silence_callback,$1/SDL2.audioContext.sampleRate*1e3);if(navigator.mediaDevices!==undefined&&navigator.mediaDevices.getUserMedia!==undefined){navigator.mediaDevices.getUserMedia({audio:true,video:false}).then(have_microphone).catch(no_microphone)}else if(navigator.webkitGetUserMedia!==undefined){navigator.webkitGetUserMedia({audio:true,video:false},have_microphone,no_microphone)}},1025836:function($0,$1,$2,$3){var SDL2=Module["SDL2"];SDL2.audio.scriptProcessorNode=SDL2.audioContext["createScriptProcessor"]($1,0,$0);SDL2.audio.scriptProcessorNode["onaudioprocess"]=function(e){if(SDL2===undefined||SDL2.audio===undefined){return}SDL2.audio.currentOutputBuffer=e["outputBuffer"];dynCall("vi",$2,[$3])};SDL2.audio.scriptProcessorNode["connect"](SDL2.audioContext["destination"])},1026246:function($0,$1){var SDL2=Module["SDL2"];var numChannels=SDL2.capture.currentCaptureBuffer.numberOfChannels;for(var c=0;c>2]}}},1027331:function($0){var SDL2=Module["SDL2"];if($0){if(SDL2.capture.silenceTimer!==undefined){clearTimeout(SDL2.capture.silenceTimer)}if(SDL2.capture.stream!==undefined){var tracks=SDL2.capture.stream.getAudioTracks();for(var i=0;i0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){wasmTable.get(func)()}else{wasmTable.get(func)(callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}function demangle(func){return func}function demangleAll(text){var regex=/\b_Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function dynCallLegacy(sig,ptr,args){if(args&&args.length){return Module["dynCall_"+sig].apply(null,[ptr].concat(args))}return Module["dynCall_"+sig].call(null,ptr)}function dynCall(sig,ptr,args){if(sig.indexOf("j")!=-1){return dynCallLegacy(sig,ptr,args)}return wasmTable.get(ptr).apply(null,args)}function jsStackTrace(){var error=new Error;if(!error.stack){try{throw new Error}catch(e){error=e}if(!error.stack){return"(no stack trace available)"}}return error.stack.toString()}function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return demangleAll(js)}var _emscripten_get_now;if(ENVIRONMENT_IS_NODE){_emscripten_get_now=function(){var t=process["hrtime"]();return t[0]*1e3+t[1]/1e6}}else if(typeof dateNow!=="undefined"){_emscripten_get_now=dateNow}else _emscripten_get_now=function(){return performance.now()};var _emscripten_get_now_is_monotonic=true;function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}function _clock_gettime(clk_id,tp){var now;if(clk_id===0){now=Date.now()}else if((clk_id===1||clk_id===4)&&_emscripten_get_now_is_monotonic){now=_emscripten_get_now()}else{setErrNo(28);return-1}HEAP32[tp>>2]=now/1e3|0;HEAP32[tp+4>>2]=now%1e3*1e3*1e3|0;return 0}function ___clock_gettime(a0,a1){return _clock_gettime(a0,a1)}var ExceptionInfoAttrs={DESTRUCTOR_OFFSET:0,REFCOUNT_OFFSET:4,TYPE_OFFSET:8,CAUGHT_OFFSET:12,RETHROWN_OFFSET:13,SIZE:16};function ___cxa_allocate_exception(size){return _malloc(size+ExceptionInfoAttrs.SIZE)+ExceptionInfoAttrs.SIZE}function _atexit(func,arg){}function ___cxa_atexit(a0,a1){return _atexit(a0,a1)}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-ExceptionInfoAttrs.SIZE;this.set_type=function(type){HEAP32[this.ptr+ExceptionInfoAttrs.TYPE_OFFSET>>2]=type};this.get_type=function(){return HEAP32[this.ptr+ExceptionInfoAttrs.TYPE_OFFSET>>2]};this.set_destructor=function(destructor){HEAP32[this.ptr+ExceptionInfoAttrs.DESTRUCTOR_OFFSET>>2]=destructor};this.get_destructor=function(){return HEAP32[this.ptr+ExceptionInfoAttrs.DESTRUCTOR_OFFSET>>2]};this.set_refcount=function(refcount){HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2]=refcount};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+ExceptionInfoAttrs.CAUGHT_OFFSET>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+ExceptionInfoAttrs.CAUGHT_OFFSET>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+ExceptionInfoAttrs.RETHROWN_OFFSET>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+ExceptionInfoAttrs.RETHROWN_OFFSET>>0]!=0};this.init=function(type,destructor){this.set_type(type);this.set_destructor(destructor);this.set_refcount(0);this.set_caught(false);this.set_rethrown(false)};this.add_ref=function(){var value=HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2];HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2]=value+1};this.release_ref=function(){var prev=HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2];HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2]=prev-1;return prev===1}}function CatchInfo(ptr){this.free=function(){_free(this.ptr);this.ptr=0};this.set_base_ptr=function(basePtr){HEAP32[this.ptr>>2]=basePtr};this.get_base_ptr=function(){return HEAP32[this.ptr>>2]};this.set_adjusted_ptr=function(adjustedPtr){var ptrSize=4;HEAP32[this.ptr+ptrSize>>2]=adjustedPtr};this.get_adjusted_ptr=function(){var ptrSize=4;return HEAP32[this.ptr+ptrSize>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_exception_info().get_type());if(isPointer){return HEAP32[this.get_base_ptr()>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.get_base_ptr()};this.get_exception_info=function(){return new ExceptionInfo(this.get_base_ptr())};if(ptr===undefined){this.ptr=_malloc(8);this.set_adjusted_ptr(0)}else{this.ptr=ptr}}var exceptionCaught=[];function exception_addRef(info){info.add_ref()}function __ZSt18uncaught_exceptionv(){return __ZSt18uncaught_exceptionv.uncaught_exceptions>0}function ___cxa_begin_catch(ptr){var catchInfo=new CatchInfo(ptr);var info=catchInfo.get_exception_info();if(!info.get_caught()){info.set_caught(true);__ZSt18uncaught_exceptionv.uncaught_exceptions--}info.set_rethrown(false);exceptionCaught.push(catchInfo);exception_addRef(info);return catchInfo.get_exception_ptr()}var exceptionLast=0;function ___cxa_free_exception(ptr){return _free(new ExceptionInfo(ptr).ptr)}function exception_decRef(info){if(info.release_ref()&&!info.get_rethrown()){var destructor=info.get_destructor();if(destructor){wasmTable.get(destructor)(info.excPtr)}___cxa_free_exception(info.excPtr)}}function ___cxa_end_catch(){_setThrew(0);var catchInfo=exceptionCaught.pop();exception_decRef(catchInfo.get_exception_info());catchInfo.free();exceptionLast=0}function ___resumeException(catchInfoPtr){var catchInfo=new CatchInfo(catchInfoPtr);var ptr=catchInfo.get_base_ptr();if(!exceptionLast){exceptionLast=ptr}catchInfo.free();throw ptr}var exceptionThrowBuf=0;function ___cxa_find_matching_catch_2(){var thrown=exceptionLast;if(!thrown){return(setTempRet0(0),0)|0}var info=new ExceptionInfo(thrown);var thrownType=info.get_type();var catchInfo=new CatchInfo;catchInfo.set_base_ptr(thrown);if(!thrownType){return(setTempRet0(0),catchInfo.ptr)|0}var typeArray=Array.prototype.slice.call(arguments);if(!exceptionThrowBuf){exceptionThrowBuf=_malloc(4)}HEAP32[exceptionThrowBuf>>2]=thrown;for(var i=0;i>2];if(thrown!==adjusted){catchInfo.set_adjusted_ptr(adjusted)}return(setTempRet0(caughtType),catchInfo.ptr)|0}}return(setTempRet0(thrownType),catchInfo.ptr)|0}function ___cxa_find_matching_catch_3(){var thrown=exceptionLast;if(!thrown){return(setTempRet0(0),0)|0}var info=new ExceptionInfo(thrown);var thrownType=info.get_type();var catchInfo=new CatchInfo;catchInfo.set_base_ptr(thrown);if(!thrownType){return(setTempRet0(0),catchInfo.ptr)|0}var typeArray=Array.prototype.slice.call(arguments);if(!exceptionThrowBuf){exceptionThrowBuf=_malloc(4)}HEAP32[exceptionThrowBuf>>2]=thrown;for(var i=0;i>2];if(thrown!==adjusted){catchInfo.set_adjusted_ptr(adjusted)}return(setTempRet0(caughtType),catchInfo.ptr)|0}}return(setTempRet0(thrownType),catchInfo.ptr)|0}function ___cxa_rethrow(){var catchInfo=exceptionCaught.pop();var info=catchInfo.get_exception_info();var ptr=catchInfo.get_base_ptr();if(!info.get_rethrown()){exceptionCaught.push(catchInfo);info.set_rethrown(true)}else{catchInfo.free()}exceptionLast=ptr;throw ptr}function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exceptions=1}else{__ZSt18uncaught_exceptionv.uncaught_exceptions++}throw ptr}function ___cxa_uncaught_exceptions(){return __ZSt18uncaught_exceptionv.uncaught_exceptions}function _gmtime_r(time,tmPtr){var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();HEAP32[tmPtr+36>>2]=0;HEAP32[tmPtr+32>>2]=0;var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;if(!_gmtime_r.GMTString)_gmtime_r.GMTString=allocateUTF8("GMT");HEAP32[tmPtr+40>>2]=_gmtime_r.GMTString;return tmPtr}function ___gmtime_r(a0,a1){return _gmtime_r(a0,a1)}function _tzset(){if(_tzset.called)return;_tzset.called=true;HEAP32[__get_timezone()>>2]=(new Date).getTimezoneOffset()*60;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);HEAP32[__get_daylight()>>2]=Number(winter.getTimezoneOffset()!=summer.getTimezoneOffset());function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=allocateUTF8(winterName);var summerNamePtr=allocateUTF8(summerName);if(summer.getTimezoneOffset()>2]=winterNamePtr;HEAP32[__get_tzname()+4>>2]=summerNamePtr}else{HEAP32[__get_tzname()>>2]=summerNamePtr;HEAP32[__get_tzname()+4>>2]=winterNamePtr}}function _localtime_r(time,tmPtr){_tzset();var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var start=new Date(date.getFullYear(),0,1);var yday=(date.getTime()-start.getTime())/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst;var zonePtr=HEAP32[__get_tzname()+(dst?4:0)>>2];HEAP32[tmPtr+40>>2]=zonePtr;return tmPtr}function ___localtime_r(a0,a1){return _localtime_r(a0,a1)}function ___map_file(pathname,size){setErrNo(63);return-1}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!=="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=path.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(from,to){from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node}return node},getFileDataAsRegularArray:function(node){if(node.contents&&node.contents.subarray){var arr=[];for(var i=0;i=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);return},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;return}if(!node.contents||node.contents.subarray){var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize;return}if(!node.contents)node.contents=[];if(node.contents.length>newSize)node.contents.length=newSize;else while(node.contents.length=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+lengthe2["timestamp"]){create.push(key);total++}});var remove=[];Object.keys(dst.entries).forEach(function(key){var e=dst.entries[key];var e2=src.entries[key];if(!e2){remove.push(key);total++}});if(!total){return callback(null)}var errored=false;var db=src.type==="remote"?src.db:dst.db;var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readwrite");var store=transaction.objectStore(IDBFS.DB_STORE_NAME);function done(err){if(err&&!errored){errored=true;return callback(err)}}transaction.onerror=function(e){done(this.error);e.preventDefault()};transaction.oncomplete=function(e){if(!errored){callback(null)}};create.sort().forEach(function(path){if(dst.type==="local"){IDBFS.loadRemoteEntry(store,path,function(err,entry){if(err)return done(err);IDBFS.storeLocalEntry(path,entry,done)})}else{IDBFS.loadLocalEntry(path,function(err,entry){if(err)return done(err);IDBFS.storeRemoteEntry(store,path,entry,done)})}});remove.sort().reverse().forEach(function(path){if(dst.type==="local"){IDBFS.removeLocalEntry(path,done)}else{IDBFS.removeRemoteEntry(store,path,done)}})}};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,trackingDelegate:{},tracking:{openFlags:{READ:1,WRITE:2}},ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,handleFSError:function(e){if(!(e instanceof FS.ErrnoError))throw e+" : "+stackTrace();return setErrNo(e.errno)},lookupPath:function(path,opts){path=PATH_FS.resolve(FS.cwd(),path);opts=opts||{};if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};for(var key in defaults){if(opts[key]===undefined){opts[key]=defaults[key]}}if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),false);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:function(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?mount+"/"+path:mount+path}path=path?node.name+"/"+path:node.name;node=node.parent}},hashName:function(parentid,name){var hash=0;name=name.toLowerCase();for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:function(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:function(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:function(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);name=name.toLowerCase();for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;nodeName=nodeName.toLowerCase();if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:function(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:function(node){FS.hashRemoveNode(node)},isRoot:function(node){return node===node.parent},isMountpoint:function(node){return!!node.mounted},isFile:function(mode){return(mode&61440)===32768},isDir:function(mode){return(mode&61440)===16384},isLink:function(mode){return(mode&61440)===40960},isChrdev:function(mode){return(mode&61440)===8192},isBlkdev:function(mode){return(mode&61440)===24576},isFIFO:function(mode){return(mode&61440)===4096},isSocket:function(mode){return(mode&49152)===49152},flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(str){var flags=FS.flagModes[str];if(typeof flags==="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:function(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:function(node,perms){if(FS.ignorePermissions){return 0}if(perms.indexOf("r")!==-1&&!(node.mode&292)){return 2}else if(perms.indexOf("w")!==-1&&!(node.mode&146)){return 2}else if(perms.indexOf("x")!==-1&&!(node.mode&73)){return 2}return 0},mayLookup:function(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:function(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:function(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:function(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:function(fd_start,fd_end){fd_start=fd_start||0;fd_end=fd_end||FS.MAX_OPEN_FDS;for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:function(fd){return FS.streams[fd]},createStream:function(stream,fd_start,fd_end){if(!FS.FSStream){FS.FSStream=function(){};FS.FSStream.prototype={object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}}}}var newStream=new FS.FSStream;for(var p in stream){newStream[p]=stream[p]}stream=newStream;var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:function(fd){FS.streams[fd]=null},chrdev_stream_ops:{open:function(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:function(){throw new FS.ErrnoError(70)}},major:function(dev){return dev>>8},minor:function(dev){return dev&255},makedev:function(ma,mi){return ma<<8|mi},registerDevice:function(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:function(dev){return FS.devices[dev]},getMounts:function(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:function(populate,callback){if(typeof populate==="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err("warning: "+FS.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work")}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(function(mount){if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:function(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:function(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(function(hash){var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.indexOf(current.mount)!==-1){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:function(parent,name){return parent.node_ops.lookup(parent,name)},mknod:function(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:function(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:function(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:function(path,mode){var dirs=path.split("/");var d="";for(var i=0;i"})},staticInit:function(){FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS,"IDBFS":IDBFS}},init:function(input,output,error){FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit:function(){FS.init.initialized=false;var fflush=Module["_fflush"];if(fflush)fflush(0);for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=function(from,to){if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);if(typeof Uint8Array!="undefined")xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(function(chunkNum){var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]==="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]==="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!=="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(function(key){var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}return fn.apply(null,arguments)}});stream_ops.read=function stream_ops_read(stream,buffer,offset,length,position){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i>2]=stat.dev;HEAP32[buf+4>>2]=0;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;HEAP32[buf+32>>2]=0;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0},doMknod:function(path,mode,dev){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var node;var lookup=FS.lookupPath(path,{follow:true});node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0},doDup:function(path,flags,suggestFD){var suggest=FS.getStream(suggestFD);if(suggest)FS.close(suggest);return FS.open(path,flags,0,suggestFD,suggestFD).fd},doReadv:function(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(low,high){return low}};function ___sys__newselect(nfds,readfds,writefds,exceptfds,timeout){try{var total=0;var srcReadLow=readfds?HEAP32[readfds>>2]:0,srcReadHigh=readfds?HEAP32[readfds+4>>2]:0;var srcWriteLow=writefds?HEAP32[writefds>>2]:0,srcWriteHigh=writefds?HEAP32[writefds+4>>2]:0;var srcExceptLow=exceptfds?HEAP32[exceptfds>>2]:0,srcExceptHigh=exceptfds?HEAP32[exceptfds+4>>2]:0;var dstReadLow=0,dstReadHigh=0;var dstWriteLow=0,dstWriteHigh=0;var dstExceptLow=0,dstExceptHigh=0;var allLow=(readfds?HEAP32[readfds>>2]:0)|(writefds?HEAP32[writefds>>2]:0)|(exceptfds?HEAP32[exceptfds>>2]:0);var allHigh=(readfds?HEAP32[readfds+4>>2]:0)|(writefds?HEAP32[writefds+4>>2]:0)|(exceptfds?HEAP32[exceptfds+4>>2]:0);var check=function(fd,low,high,val){return fd<32?low&val:high&val};for(var fd=0;fd>2]=dstReadLow;HEAP32[readfds+4>>2]=dstReadHigh}if(writefds){HEAP32[writefds>>2]=dstWriteLow;HEAP32[writefds+4>>2]=dstWriteHigh}if(exceptfds){HEAP32[exceptfds>>2]=dstExceptLow;HEAP32[exceptfds+4>>2]=dstExceptHigh}return total}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_access(path,amode){try{path=SYSCALLS.getStr(path);return SYSCALLS.doAccess(path,amode)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_dup2(oldfd,suggestFD){try{var old=SYSCALLS.getStreamFromFD(oldfd);if(old.fd===suggestFD)return suggestFD;return SYSCALLS.doDup(old.path,old.flags,suggestFD)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_dup3(fd,suggestFD,flags){try{var old=SYSCALLS.getStreamFromFD(fd);if(old.fd===suggestFD)return-28;return SYSCALLS.doDup(old.path,old.flags,suggestFD)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.open(stream.path,stream.flags,0,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 12:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_getcwd(buf,size){try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd);if(size>>0,(tempDouble=id,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos>>2]=tempI64[0],HEAP32[dirp+pos+4>>2]=tempI64[1];tempI64=[(idx+1)*struct_size>>>0,(tempDouble=(idx+1)*struct_size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos+8>>2]=tempI64[0],HEAP32[dirp+pos+12>>2]=tempI64[1];HEAP16[dirp+pos+16>>1]=280;HEAP8[dirp+pos+18>>0]=type;stringToUTF8(name,dirp+pos+19,256);pos+=struct_size;idx+=1}FS.llseek(stream,idx*struct_size,0);return pos}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_getpid(){return 42}function ___sys_getegid32(){return 0}function ___sys_getuid32(){return ___sys_getegid32()}function ___sys_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:abort("bad ioctl syscall "+op)}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_lstat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_mkdir(path,mode){try{path=SYSCALLS.getStr(path);return SYSCALLS.doMkdir(path,mode)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function syscallMunmap(addr,len){if((addr|0)===-1||len===0){return-28}var info=SYSCALLS.mappings[addr];if(!info)return 0;if(len===info.len){var stream=FS.getStream(info.fd);if(info.prot&2){SYSCALLS.doMsync(addr,stream,len,info.flags,info.offset)}FS.munmap(stream);SYSCALLS.mappings[addr]=null;if(info.allocated){_free(info.malloc)}}return 0}function ___sys_munmap(addr,len){try{return syscallMunmap(addr,len)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_open(path,flags,varargs){SYSCALLS.varargs=varargs;try{var pathname=SYSCALLS.getStr(path);var mode=SYSCALLS.get();var stream=FS.open(pathname,flags,mode);return stream.fd}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_poll(fds,nfds,timeout){try{var nonzero=0;for(var i=0;i>2];var events=HEAP16[pollfd+4>>1];var mask=32;var stream=FS.getStream(fd);if(stream){mask=SYSCALLS.DEFAULT_POLLMASK;if(stream.stream_ops.poll){mask=stream.stream_ops.poll(stream)}}mask&=events|8|16;if(mask)nonzero++;HEAP16[pollfd+6>>1]=mask}return nonzero}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_read(fd,buf,count){try{var stream=SYSCALLS.getStreamFromFD(fd);return FS.read(stream,HEAP8,buf,count)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_readlink(path,buf,bufsize){try{path=SYSCALLS.getStr(path);return SYSCALLS.doReadlink(path,buf,bufsize)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_rename(old_path,new_path){try{old_path=SYSCALLS.getStr(old_path);new_path=SYSCALLS.getStr(new_path);FS.rename(old_path,new_path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_rmdir(path){try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}var ERRNO_CODES={EPERM:63,ENOENT:44,ESRCH:71,EINTR:27,EIO:29,ENXIO:60,E2BIG:1,ENOEXEC:45,EBADF:8,ECHILD:12,EAGAIN:6,EWOULDBLOCK:6,ENOMEM:48,EACCES:2,EFAULT:21,ENOTBLK:105,EBUSY:10,EEXIST:20,EXDEV:75,ENODEV:43,ENOTDIR:54,EISDIR:31,EINVAL:28,ENFILE:41,EMFILE:33,ENOTTY:59,ETXTBSY:74,EFBIG:22,ENOSPC:51,ESPIPE:70,EROFS:69,EMLINK:34,EPIPE:64,EDOM:18,ERANGE:68,ENOMSG:49,EIDRM:24,ECHRNG:106,EL2NSYNC:156,EL3HLT:107,EL3RST:108,ELNRNG:109,EUNATCH:110,ENOCSI:111,EL2HLT:112,EDEADLK:16,ENOLCK:46,EBADE:113,EBADR:114,EXFULL:115,ENOANO:104,EBADRQC:103,EBADSLT:102,EDEADLOCK:16,EBFONT:101,ENOSTR:100,ENODATA:116,ETIME:117,ENOSR:118,ENONET:119,ENOPKG:120,EREMOTE:121,ENOLINK:47,EADV:122,ESRMNT:123,ECOMM:124,EPROTO:65,EMULTIHOP:36,EDOTDOT:125,EBADMSG:9,ENOTUNIQ:126,EBADFD:127,EREMCHG:128,ELIBACC:129,ELIBBAD:130,ELIBSCN:131,ELIBMAX:132,ELIBEXEC:133,ENOSYS:52,ENOTEMPTY:55,ENAMETOOLONG:37,ELOOP:32,EOPNOTSUPP:138,EPFNOSUPPORT:139,ECONNRESET:15,ENOBUFS:42,EAFNOSUPPORT:5,EPROTOTYPE:67,ENOTSOCK:57,ENOPROTOOPT:50,ESHUTDOWN:140,ECONNREFUSED:14,EADDRINUSE:3,ECONNABORTED:13,ENETUNREACH:40,ENETDOWN:38,ETIMEDOUT:73,EHOSTDOWN:142,EHOSTUNREACH:23,EINPROGRESS:26,EALREADY:7,EDESTADDRREQ:17,EMSGSIZE:35,EPROTONOSUPPORT:66,ESOCKTNOSUPPORT:137,EADDRNOTAVAIL:4,ENETRESET:39,EISCONN:30,ENOTCONN:53,ETOOMANYREFS:141,EUSERS:136,EDQUOT:19,ESTALE:72,ENOTSUP:138,ENOMEDIUM:148,EILSEQ:25,EOVERFLOW:61,ECANCELED:11,ENOTRECOVERABLE:56,EOWNERDEAD:62,ESTRPIPE:135};var SOCKFS={mount:function(mount){Module["websocket"]=Module["websocket"]&&"object"===typeof Module["websocket"]?Module["websocket"]:{};Module["websocket"]._callbacks={};Module["websocket"]["on"]=function(event,callback){if("function"===typeof callback){this._callbacks[event]=callback}return this};Module["websocket"].emit=function(event,param){if("function"===typeof this._callbacks[event]){this._callbacks[event].call(this,param)}};return FS.createNode(null,"/",16384|511,0)},createSocket:function(family,type,protocol){type&=~526336;var streaming=type==1;if(protocol){assert(streaming==(protocol==6))}var sock={family:family,type:type,protocol:protocol,server:null,error:null,peers:{},pending:[],recv_queue:[],sock_ops:SOCKFS.websocket_sock_ops};var name=SOCKFS.nextname();var node=FS.createNode(SOCKFS.root,name,49152,0);node.sock=sock;var stream=FS.createStream({path:name,node:node,flags:FS.modeStringToFlags("r+"),seekable:false,stream_ops:SOCKFS.stream_ops});sock.stream=stream;return sock},getSocket:function(fd){var stream=FS.getStream(fd);if(!stream||!FS.isSocket(stream.node.mode)){return null}return stream.node.sock},stream_ops:{poll:function(stream){var sock=stream.node.sock;return sock.sock_ops.poll(sock)},ioctl:function(stream,request,varargs){var sock=stream.node.sock;return sock.sock_ops.ioctl(sock,request,varargs)},read:function(stream,buffer,offset,length,position){var sock=stream.node.sock;var msg=sock.sock_ops.recvmsg(sock,length);if(!msg){return 0}buffer.set(msg.buffer,offset);return msg.buffer.length},write:function(stream,buffer,offset,length,position){var sock=stream.node.sock;return sock.sock_ops.sendmsg(sock,buffer,offset,length)},close:function(stream){var sock=stream.node.sock;sock.sock_ops.close(sock)}},nextname:function(){if(!SOCKFS.nextname.current){SOCKFS.nextname.current=0}return"socket["+SOCKFS.nextname.current+++"]"},websocket_sock_ops:{createPeer:function(sock,addr,port){var ws;if(typeof addr==="object"){ws=addr;addr=null;port=null}if(ws){if(ws._socket){addr=ws._socket.remoteAddress;port=ws._socket.remotePort}else{var result=/ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);if(!result){throw new Error("WebSocket URL must be in the format ws(s)://address:port")}addr=result[1];port=parseInt(result[2],10)}}else{try{var runtimeConfig=Module["websocket"]&&"object"===typeof Module["websocket"];var url="ws:#".replace("#","//");if(runtimeConfig){if("string"===typeof Module["websocket"]["url"]){url=Module["websocket"]["url"]}}if(url==="ws://"||url==="wss://"){var parts=addr.split("/");url=url+parts[0]+":"+port+"/"+parts.slice(1).join("/")}var subProtocols="binary";if(runtimeConfig){if("string"===typeof Module["websocket"]["subprotocol"]){subProtocols=Module["websocket"]["subprotocol"]}}var opts=undefined;if(subProtocols!=="null"){subProtocols=subProtocols.replace(/^ +| +$/g,"").split(/ *, */);opts=ENVIRONMENT_IS_NODE?{"protocol":subProtocols.toString()}:subProtocols}if(runtimeConfig&&null===Module["websocket"]["subprotocol"]){subProtocols="null";opts=undefined}var WebSocketConstructor;if(ENVIRONMENT_IS_NODE){WebSocketConstructor=require("ws")}else{WebSocketConstructor=WebSocket}ws=new WebSocketConstructor(url,opts);ws.binaryType="arraybuffer"}catch(e){throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH)}}var peer={addr:addr,port:port,socket:ws,dgram_send_queue:[]};SOCKFS.websocket_sock_ops.addPeer(sock,peer);SOCKFS.websocket_sock_ops.handlePeerEvents(sock,peer);if(sock.type===2&&typeof sock.sport!=="undefined"){peer.dgram_send_queue.push(new Uint8Array([255,255,255,255,"p".charCodeAt(0),"o".charCodeAt(0),"r".charCodeAt(0),"t".charCodeAt(0),(sock.sport&65280)>>8,sock.sport&255]))}return peer},getPeer:function(sock,addr,port){return sock.peers[addr+":"+port]},addPeer:function(sock,peer){sock.peers[peer.addr+":"+peer.port]=peer},removePeer:function(sock,peer){delete sock.peers[peer.addr+":"+peer.port]},handlePeerEvents:function(sock,peer){var first=true;var handleOpen=function(){Module["websocket"].emit("open",sock.stream.fd);try{var queued=peer.dgram_send_queue.shift();while(queued){peer.socket.send(queued);queued=peer.dgram_send_queue.shift()}}catch(e){peer.socket.close()}};function handleMessage(data){if(typeof data==="string"){var encoder=new TextEncoder;data=encoder.encode(data)}else{assert(data.byteLength!==undefined);if(data.byteLength==0){return}else{data=new Uint8Array(data)}}var wasfirst=first;first=false;if(wasfirst&&data.length===10&&data[0]===255&&data[1]===255&&data[2]===255&&data[3]===255&&data[4]==="p".charCodeAt(0)&&data[5]==="o".charCodeAt(0)&&data[6]==="r".charCodeAt(0)&&data[7]==="t".charCodeAt(0)){var newport=data[8]<<8|data[9];SOCKFS.websocket_sock_ops.removePeer(sock,peer);peer.port=newport;SOCKFS.websocket_sock_ops.addPeer(sock,peer);return}sock.recv_queue.push({addr:peer.addr,port:peer.port,data:data});Module["websocket"].emit("message",sock.stream.fd)}if(ENVIRONMENT_IS_NODE){peer.socket.on("open",handleOpen);peer.socket.on("message",function(data,flags){if(!flags.binary){return}handleMessage(new Uint8Array(data).buffer)});peer.socket.on("close",function(){Module["websocket"].emit("close",sock.stream.fd)});peer.socket.on("error",function(error){sock.error=ERRNO_CODES.ECONNREFUSED;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])})}else{peer.socket.onopen=handleOpen;peer.socket.onclose=function(){Module["websocket"].emit("close",sock.stream.fd)};peer.socket.onmessage=function peer_socket_onmessage(event){handleMessage(event.data)};peer.socket.onerror=function(error){sock.error=ERRNO_CODES.ECONNREFUSED;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])}}},poll:function(sock){if(sock.type===1&&sock.server){return sock.pending.length?64|1:0}var mask=0;var dest=sock.type===1?SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport):null;if(sock.recv_queue.length||!dest||dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=64|1}if(!dest||dest&&dest.socket.readyState===dest.socket.OPEN){mask|=4}if(dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=16}return mask},ioctl:function(sock,request,arg){switch(request){case 21531:var bytes=0;if(sock.recv_queue.length){bytes=sock.recv_queue[0].data.length}HEAP32[arg>>2]=bytes;return 0;default:return ERRNO_CODES.EINVAL}},close:function(sock){if(sock.server){try{sock.server.close()}catch(e){}sock.server=null}var peers=Object.keys(sock.peers);for(var i=0;i>>0}function jstoi_q(str){return parseInt(str)}function __inet_pton6_raw(str){var words;var w,offset,z;var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;var parts=[];if(!valid6regx.test(str)){return null}if(str==="::"){return[0,0,0,0,0,0,0,0]}if(str.indexOf("::")===0){str=str.replace("::","Z:")}else{str=str.replace("::",":Z:")}if(str.indexOf(".")>0){str=str.replace(new RegExp("[.]","g"),":");words=str.split(":");words[words.length-4]=jstoi_q(words[words.length-4])+jstoi_q(words[words.length-3])*256;words[words.length-3]=jstoi_q(words[words.length-2])+jstoi_q(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w>8&255)+"."+(addr>>16&255)+"."+(addr>>24&255)}function __inet_ntop6_raw(ints){var str="";var word=0;var longest=0;var lastzero=0;var zstart=0;var len=0;var i=0;var parts=[ints[0]&65535,ints[0]>>16,ints[1]&65535,ints[1]>>16,ints[2]&65535,ints[2]>>16,ints[3]&65535,ints[3]>>16];var hasipv4=true;var v4part="";for(i=0;i<5;i++){if(parts[i]!==0){hasipv4=false;break}}if(hasipv4){v4part=__inet_ntop4_raw(parts[6]|parts[7]<<16);if(parts[5]===-1){str="::ffff:";str+=v4part;return str}if(parts[5]===0){str="::";if(v4part==="0.0.0.0")v4part="";if(v4part==="0.0.0.1")v4part="1";str+=v4part;return str}}for(word=0;word<8;word++){if(parts[word]===0){if(word-lastzero>1){len=0}lastzero=word;len++}if(len>longest){longest=len;zstart=word-longest+1}}for(word=0;word<8;word++){if(longest>1){if(parts[word]===0&&word>=zstart&&word>1];var port=_ntohs(HEAPU16[sa+2>>1]);var addr;switch(family){case 2:if(salen!==16){return{errno:28}}addr=HEAP32[sa+4>>2];addr=__inet_ntop4_raw(addr);break;case 10:if(salen!==28){return{errno:28}}addr=[HEAP32[sa+8>>2],HEAP32[sa+12>>2],HEAP32[sa+16>>2],HEAP32[sa+20>>2]];addr=__inet_ntop6_raw(addr);break;default:return{errno:5}}return{family:family,addr:addr,port:port}}function __write_sockaddr(sa,family,addr,port){switch(family){case 2:addr=__inet_pton4_raw(addr);HEAP16[sa>>1]=family;HEAP32[sa+4>>2]=addr;HEAP16[sa+2>>1]=_htons(port);break;case 10:addr=__inet_pton6_raw(addr);HEAP32[sa>>2]=family;HEAP32[sa+8>>2]=addr[0];HEAP32[sa+12>>2]=addr[1];HEAP32[sa+16>>2]=addr[2];HEAP32[sa+20>>2]=addr[3];HEAP16[sa+2>>1]=_htons(port);HEAP32[sa+4>>2]=0;HEAP32[sa+24>>2]=0;break;default:return{errno:5}}return{}}function ___sys_socketcall(call,socketvararg){try{SYSCALLS.varargs=socketvararg;var getSocketFromFD=function(){var socket=SOCKFS.getSocket(SYSCALLS.get());if(!socket)throw new FS.ErrnoError(8);return socket};var getSocketAddress=function(allowNull){var addrp=SYSCALLS.get(),addrlen=SYSCALLS.get();if(allowNull&&addrp===0)return null;var info=__read_sockaddr(addrp,addrlen);if(info.errno)throw new FS.ErrnoError(info.errno);info.addr=DNS.lookup_addr(info.addr)||info.addr;return info};switch(call){case 1:{var domain=SYSCALLS.get(),type=SYSCALLS.get(),protocol=SYSCALLS.get();var sock=SOCKFS.createSocket(domain,type,protocol);return sock.stream.fd}case 2:{var sock=getSocketFromFD(),info=getSocketAddress();sock.sock_ops.bind(sock,info.addr,info.port);return 0}case 3:{var sock=getSocketFromFD(),info=getSocketAddress();sock.sock_ops.connect(sock,info.addr,info.port);return 0}case 4:{var sock=getSocketFromFD(),backlog=SYSCALLS.get();sock.sock_ops.listen(sock,backlog);return 0}case 5:{var sock=getSocketFromFD(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();var newsock=sock.sock_ops.accept(sock);if(addr){var res=__write_sockaddr(addr,newsock.family,DNS.lookup_name(newsock.daddr),newsock.dport)}return newsock.stream.fd}case 6:{var sock=getSocketFromFD(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();var res=__write_sockaddr(addr,sock.family,DNS.lookup_name(sock.saddr||"0.0.0.0"),sock.sport);return 0}case 7:{var sock=getSocketFromFD(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();if(!sock.daddr){return-53}var res=__write_sockaddr(addr,sock.family,DNS.lookup_name(sock.daddr),sock.dport);return 0}case 11:{var sock=getSocketFromFD(),message=SYSCALLS.get(),length=SYSCALLS.get(),flags=SYSCALLS.get(),dest=getSocketAddress(true);if(!dest){return FS.write(sock.stream,HEAP8,message,length)}else{return sock.sock_ops.sendmsg(sock,HEAP8,message,length,dest.addr,dest.port)}}case 12:{var sock=getSocketFromFD(),buf=SYSCALLS.get(),len=SYSCALLS.get(),flags=SYSCALLS.get(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();var msg=sock.sock_ops.recvmsg(sock,len);if(!msg)return 0;if(addr){var res=__write_sockaddr(addr,sock.family,DNS.lookup_name(msg.addr),msg.port)}HEAPU8.set(msg.buffer,buf);return msg.buffer.byteLength}case 14:{return-50}case 15:{var sock=getSocketFromFD(),level=SYSCALLS.get(),optname=SYSCALLS.get(),optval=SYSCALLS.get(),optlen=SYSCALLS.get();if(level===1){if(optname===4){HEAP32[optval>>2]=sock.error;HEAP32[optlen>>2]=4;sock.error=null;return 0}}return-50}case 16:{var sock=getSocketFromFD(),message=SYSCALLS.get(),flags=SYSCALLS.get();var iov=HEAP32[message+8>>2];var num=HEAP32[message+12>>2];var addr,port;var name=HEAP32[message>>2];var namelen=HEAP32[message+4>>2];if(name){var info=__read_sockaddr(name,namelen);if(info.errno)return-info.errno;port=info.port;addr=DNS.lookup_addr(info.addr)||info.addr}var total=0;for(var i=0;i>2]}var view=new Uint8Array(total);var offset=0;for(var i=0;i>2];var iovlen=HEAP32[iov+(8*i+4)>>2];for(var j=0;j>0]}}return sock.sock_ops.sendmsg(sock,view,0,total,addr,port)}case 17:{var sock=getSocketFromFD(),message=SYSCALLS.get(),flags=SYSCALLS.get();var iov=HEAP32[message+8>>2];var num=HEAP32[message+12>>2];var total=0;for(var i=0;i>2]}var msg=sock.sock_ops.recvmsg(sock,total);if(!msg)return 0;var name=HEAP32[message>>2];if(name){var res=__write_sockaddr(name,sock.family,DNS.lookup_name(msg.addr),msg.port)}var bytesRead=0;var bytesRemaining=msg.buffer.byteLength;for(var i=0;bytesRemaining>0&&i>2];var iovlen=HEAP32[iov+(8*i+4)>>2];if(!iovlen){continue}var length=Math.min(iovlen,bytesRemaining);var buf=msg.buffer.subarray(bytesRead,bytesRead+length);HEAPU8.set(buf,iovbase+bytesRead);bytesRead+=length;bytesRemaining-=length}return bytesRead}default:{return-52}}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_uname(buf){try{if(!buf)return-21;var layout={"__size__":390,"sysname":0,"nodename":65,"release":130,"version":195,"machine":260,"domainname":325};var copyString=function(element,value){var offset=layout[element];writeAsciiToMemory(value,buf+offset)};copyString("sysname","Emscripten");copyString("nodename","emscripten");copyString("release","1.0");copyString("version","#1");copyString("machine","x86-JS");return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_unlink(path){try{path=SYSCALLS.getStr(path);FS.unlink(path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function _abort(){abort()}function _emscripten_set_main_loop_timing(mode,value){Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){return 1}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof setImmediate==="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=function(event){if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0}function setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop,arg,noSetTiming){noExitRuntime=true;assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=browserIterationFunc;Browser.mainLoop.arg=arg;var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;Browser.mainLoop.runner=function Browser_mainLoop_runner(){if(ABORT)return;if(Browser.mainLoop.queue.length>0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}console.log('main loop blocker "'+blocker.name+'" took '+(Date.now()-start)+" ms");Browser.mainLoop.updateStatus();if(thisMainLoopId1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}GL.newRenderingFrameStarted();Browser.mainLoop.runIter(browserIterationFunc);if(thisMainLoopId0)_emscripten_set_main_loop_timing(0,1e3/fps);else _emscripten_set_main_loop_timing(1,1);Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}}var Browser={mainLoop:{scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;setMainLoop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus:function(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;Browser.safeSetTimeout(function(){finish(audio)},1e4)}else{return fail()}};Module["preloadPlugins"].push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||function(){};canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||function(){};canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",function(ev){if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext:function(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!=="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){if(!useWebGL)assert(typeof GLctx==="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});Browser.init()}return ctx},destroyContext:function(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen:function(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer==="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas==="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}if(Module["onFullScreen"])Module["onFullScreen"](Browser.isFullscreen);if(Module["onFullscreen"])Module["onFullscreen"](Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?function(){canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null)||(canvasContainer["webkitRequestFullScreen"]?function(){canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null);canvasContainer.requestFullscreen()},exitFullscreen:function(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||function(){};CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame:function(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame:function(func){if(typeof requestAnimationFrame==="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeCallback:function(func){return function(){if(!ABORT)return func.apply(null,arguments)}},allowAsyncCallbacks:true,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=false},resumeAsyncCallbacks:function(){Browser.allowAsyncCallbacks=true;if(Browser.queuedAsyncCallbacks.length>0){var callbacks=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[];callbacks.forEach(function(func){func()})}},safeRequestAnimationFrame:function(func){return Browser.requestAnimationFrame(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}else{Browser.queuedAsyncCallbacks.push(func)}})},safeSetTimeout:function(func,timeout){noExitRuntime=true;return setTimeout(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}else{Browser.queuedAsyncCallbacks.push(func)}},timeout)},safeSetInterval:function(func,timeout){noExitRuntime=true;return setInterval(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}},timeout)},getMimetype:function(name){return{"jpg":"image/jpeg","jpeg":"image/jpeg","png":"image/png","bmp":"image/bmp","ogg":"audio/ogg","wav":"audio/wav","mp3":"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia:function(func){if(!window.getUserMedia){window.getUserMedia=navigator["getUserMedia"]||navigator["mozGetUserMedia"]}window.getUserMedia(func)},getMovementX:function(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY:function(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta:function(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}if(typeof SDL!="undefined"){Browser.mouseX=SDL.mouseX+Browser.mouseMovementX;Browser.mouseY=SDL.mouseY+Browser.mouseMovementY}else{Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}}else{var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!=="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!=="undefined"?window.scrollY:window.pageYOffset;if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var adjustedX=touch.pageX-(scrollX+rect.left);var adjustedY=touch.pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);var coords={x:adjustedX,y:adjustedY};if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];if(!last)last=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}var x=event.pageX-(scrollX+rect.left);var y=event.pageY-(scrollY+rect.top);x=x*(cw/rect.width);y=y*(ch/rect.height);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y}},asyncLoad:function(url,onload,onerror,noRunDep){var dep=!noRunDep?getUniqueRunDependency("al "+url):"";readAsync(url,function(arrayBuffer){assert(arrayBuffer,'Loading data file "'+url+'" failed (no arrayBuffer).');onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},function(event){if(onerror){onerror()}else{throw'Loading data file "'+url+'" failed.'}});if(dep)addRunDependency(dep)},resizeListeners:[],updateResizeListeners:function(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(function(listener){listener(canvas.width,canvas.height)})},setCanvasSize:function(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags|8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags&~8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions:function(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h0?AL.freeIds.pop():AL._nextId++},freeIds:[],scheduleContextAudio:function(ctx){if(Browser.mainLoop.timingMode===1&&document["visibilityState"]!="visible"){return}for(var i in ctx.sources){AL.scheduleSourceAudio(ctx.sources[i])}},scheduleSourceAudio:function(src,lookahead){if(Browser.mainLoop.timingMode===1&&document["visibilityState"]!="visible"){return}if(src.state!==4114){return}var currentTime=AL.updateSourceTime(src);var startTime=src.bufStartTime;var startOffset=src.bufOffset;var bufCursor=src.bufsProcessed;for(var i=0;i=src.bufQueue.length){if(src.looping){bufCursor%=src.bufQueue.length}else{break}}var buf=src.bufQueue[bufCursor%src.bufQueue.length];if(buf.length===0){skipCount++;if(skipCount===src.bufQueue.length){break}}else{var audioSrc=src.context.audioCtx.createBufferSource();audioSrc.buffer=buf.audioBuf;audioSrc.playbackRate.value=src.playbackRate;if(buf.audioBuf._loopStart||buf.audioBuf._loopEnd){audioSrc.loopStart=buf.audioBuf._loopStart;audioSrc.loopEnd=buf.audioBuf._loopEnd}var duration=0;if(src.type===4136&&src.looping){duration=Number.POSITIVE_INFINITY;audioSrc.loop=true;if(buf.audioBuf._loopStart){audioSrc.loopStart=buf.audioBuf._loopStart}if(buf.audioBuf._loopEnd){audioSrc.loopEnd=buf.audioBuf._loopEnd}}else{duration=(buf.audioBuf.duration-startOffset)/src.playbackRate}audioSrc._startOffset=startOffset;audioSrc._duration=duration;audioSrc._skipCount=skipCount;skipCount=0;audioSrc.connect(src.gain);if(typeof audioSrc.start!=="undefined"){startTime=Math.max(startTime,src.context.audioCtx.currentTime);audioSrc.start(startTime,startOffset)}else if(typeof audioSrc.noteOn!=="undefined"){startTime=Math.max(startTime,src.context.audioCtx.currentTime);audioSrc.noteOn(startTime)}audioSrc._startTime=startTime;src.audioQueue.push(audioSrc);startTime+=duration}startOffset=0;bufCursor++}},updateSourceTime:function(src){var currentTime=src.context.audioCtx.currentTime;if(src.state!==4114){return currentTime}if(!isFinite(src.bufStartTime)){src.bufStartTime=currentTime-src.bufOffset/src.playbackRate;src.bufOffset=0}var nextStartTime=0;while(src.audioQueue.length){var audioSrc=src.audioQueue[0];src.bufsProcessed+=audioSrc._skipCount;nextStartTime=audioSrc._startTime+audioSrc._duration;if(currentTime=src.bufQueue.length&&!src.looping){AL.setSourceState(src,4116)}else if(src.type===4136&&src.looping){var buf=src.bufQueue[0];if(buf.length===0){src.bufOffset=0}else{var delta=(currentTime-src.bufStartTime)*src.playbackRate;var loopStart=buf.audioBuf._loopStart||0;var loopEnd=buf.audioBuf._loopEnd||buf.audioBuf.duration;if(loopEnd<=loopStart){loopEnd=buf.audioBuf.duration}if(delta0){src.bufStartTime+=Math.floor((currentTime-src.bufStartTime)/srcDuration)*srcDuration}}for(var i=0;i=src.bufQueue.length){if(src.looping){src.bufsProcessed%=src.bufQueue.length}else{AL.setSourceState(src,4116);break}}var buf=src.bufQueue[src.bufsProcessed];if(buf.length>0){nextStartTime=src.bufStartTime+buf.audioBuf.duration/src.playbackRate;if(currentTime1){src.audioQueue.length=1}},stopSourceAudio:function(src){for(var i=0;isrc.bufQueue[src.bufsProcessed].audioBuf.duration){offset-=src.bufQueue[src.bufsProcessed].audiobuf.duration;src.bufsProcessed++}src.bufOffset=offset}if(playing){AL.setSourceState(src,4114)}},getGlobalParam:function(funcname,param){if(!AL.currentCtx){return null}switch(param){case 49152:return AL.currentCtx.dopplerFactor;case 49155:return AL.currentCtx.speedOfSound;case 53248:return AL.currentCtx.distanceModel;default:AL.currentCtx.err=40962;return null}},setGlobalParam:function(funcname,param,value){if(!AL.currentCtx){return}switch(param){case 49152:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}AL.currentCtx.dopplerFactor=value;AL.updateListenerSpace(AL.currentCtx);break;case 49155:if(!Number.isFinite(value)||value<=0){AL.currentCtx.err=40963;return}AL.currentCtx.speedOfSound=value;AL.updateListenerSpace(AL.currentCtx);break;case 53248:switch(value){case 0:case 53249:case 53250:case 53251:case 53252:case 53253:case 53254:AL.currentCtx.distanceModel=value;AL.updateContextGlobal(AL.currentCtx);break;default:AL.currentCtx.err=40963;return}break;default:AL.currentCtx.err=40962;return}},getListenerParam:function(funcname,param){if(!AL.currentCtx){return null}switch(param){case 4100:return AL.currentCtx.listener.position;case 4102:return AL.currentCtx.listener.velocity;case 4111:return AL.currentCtx.listener.direction.concat(AL.currentCtx.listener.up);case 4106:return AL.currentCtx.gain.gain.value;default:AL.currentCtx.err=40962;return null}},setListenerParam:function(funcname,param,value){if(!AL.currentCtx){return}if(value===null){AL.currentCtx.err=40962;return}var listener=AL.currentCtx.listener;switch(param){case 4100:if(!Number.isFinite(value[0])||!Number.isFinite(value[1])||!Number.isFinite(value[2])){AL.currentCtx.err=40963;return}listener.position[0]=value[0];listener.position[1]=value[1];listener.position[2]=value[2];AL.updateListenerSpace(AL.currentCtx);break;case 4102:if(!Number.isFinite(value[0])||!Number.isFinite(value[1])||!Number.isFinite(value[2])){AL.currentCtx.err=40963;return}listener.velocity[0]=value[0];listener.velocity[1]=value[1];listener.velocity[2]=value[2];AL.updateListenerSpace(AL.currentCtx);break;case 4106:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}AL.currentCtx.gain.gain.value=value;break;case 4111:if(!Number.isFinite(value[0])||!Number.isFinite(value[1])||!Number.isFinite(value[2])||!Number.isFinite(value[3])||!Number.isFinite(value[4])||!Number.isFinite(value[5])){AL.currentCtx.err=40963;return}listener.direction[0]=value[0];listener.direction[1]=value[1];listener.direction[2]=value[2];listener.up[0]=value[3];listener.up[1]=value[4];listener.up[2]=value[5];AL.updateListenerSpace(AL.currentCtx);break;default:AL.currentCtx.err=40962;return}},getBufferParam:function(funcname,bufferId,param){if(!AL.currentCtx){return}var buf=AL.buffers[bufferId];if(!buf||bufferId===0){AL.currentCtx.err=40961;return}switch(param){case 8193:return buf.frequency;case 8194:return buf.bytesPerSample*8;case 8195:return buf.channels;case 8196:return buf.length*buf.bytesPerSample*buf.channels;case 8213:if(buf.length===0){return[0,0]}else{return[(buf.audioBuf._loopStart||0)*buf.frequency,(buf.audioBuf._loopEnd||buf.length)*buf.frequency]}default:AL.currentCtx.err=40962;return null}},setBufferParam:function(funcname,bufferId,param,value){if(!AL.currentCtx){return}var buf=AL.buffers[bufferId];if(!buf||bufferId===0){AL.currentCtx.err=40961;return}if(value===null){AL.currentCtx.err=40962;return}switch(param){case 8196:if(value!==0){AL.currentCtx.err=40963;return}break;case 8213:if(value[0]<0||value[0]>buf.length||value[1]<0||value[1]>buf.Length||value[0]>=value[1]){AL.currentCtx.err=40963;return}if(buf.refCount>0){AL.currentCtx.err=40964;return}if(buf.audioBuf){buf.audioBuf._loopStart=value[0]/buf.frequency;buf.audioBuf._loopEnd=value[1]/buf.frequency}break;default:AL.currentCtx.err=40962;return}},getSourceParam:function(funcname,sourceId,param){if(!AL.currentCtx){return null}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return null}switch(param){case 514:return src.relative;case 4097:return src.coneInnerAngle;case 4098:return src.coneOuterAngle;case 4099:return src.pitch;case 4100:return src.position;case 4101:return src.direction;case 4102:return src.velocity;case 4103:return src.looping;case 4105:if(src.type===4136){return src.bufQueue[0].id}else{return 0}case 4106:return src.gain.gain.value;case 4109:return src.minGain;case 4110:return src.maxGain;case 4112:return src.state;case 4117:if(src.bufQueue.length===1&&src.bufQueue[0].id===0){return 0}else{return src.bufQueue.length}case 4118:if(src.bufQueue.length===1&&src.bufQueue[0].id===0||src.looping){return 0}else{return src.bufsProcessed}case 4128:return src.refDistance;case 4129:return src.rolloffFactor;case 4130:return src.coneOuterGain;case 4131:return src.maxDistance;case 4132:return AL.sourceTell(src);case 4133:var offset=AL.sourceTell(src);if(offset>0){offset*=src.bufQueue[0].frequency}return offset;case 4134:var offset=AL.sourceTell(src);if(offset>0){offset*=src.bufQueue[0].frequency*src.bufQueue[0].bytesPerSample}return offset;case 4135:return src.type;case 4628:return src.spatialize;case 8201:var length=0;var bytesPerFrame=0;for(var i=0;i0){var audioSrc=src.audioQueue[0];audioSrc.loop=true;audioSrc._duration=Number.POSITIVE_INFINITY}}else if(value===0){src.looping=false;var currentTime=AL.updateSourceTime(src);if(src.type===4136&&src.audioQueue.length>0){var audioSrc=src.audioQueue[0];audioSrc.loop=false;audioSrc._duration=src.bufQueue[0].audioBuf.duration/src.playbackRate;audioSrc._startTime=currentTime-src.bufOffset/src.playbackRate}}else{AL.currentCtx.err=40963;return}break;case 4105:if(src.state===4114||src.state===4115){AL.currentCtx.err=40964;return}if(value===0){for(var i in src.bufQueue){src.bufQueue[i].refCount--}src.bufQueue.length=1;src.bufQueue[0]=AL.buffers[0];src.bufsProcessed=0;src.type=4144}else{var buf=AL.buffers[value];if(!buf){AL.currentCtx.err=40963;return}for(var i in src.bufQueue){src.bufQueue[i].refCount--}src.bufQueue.length=0;buf.refCount++;src.bufQueue=[buf];src.bufsProcessed=0;src.type=4136}AL.initSourcePanner(src);AL.scheduleSourceAudio(src);break;case 4106:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}src.gain.gain.value=value;break;case 4109:if(!Number.isFinite(value)||value<0||value>Math.min(src.maxGain,1)){AL.currentCtx.err=40963;return}src.minGain=value;break;case 4110:if(!Number.isFinite(value)||value1){AL.currentCtx.err=40963;return}src.maxGain=value;break;case 4128:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}src.refDistance=value;if(src.panner){src.panner.refDistance=value}break;case 4129:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}src.rolloffFactor=value;if(src.panner){src.panner.rolloffFactor=value}break;case 4130:if(!Number.isFinite(value)||value<0||value>1){AL.currentCtx.err=40963;return}src.coneOuterGain=value;if(src.panner){src.panner.coneOuterGain=value}break;case 4131:if(!Number.isFinite(value)||value<0){AL.currentCtx.err=40963;return}src.maxDistance=value;if(src.panner){src.panner.maxDistance=value}break;case 4132:if(value<0||value>AL.sourceDuration(src)){AL.currentCtx.err=40963;return}AL.sourceSeek(src,value);break;case 4133:var srcLen=AL.sourceDuration(src);if(srcLen>0){var frequency;for(var bufId in src.bufQueue){if(bufId){frequency=src.bufQueue[bufId].frequency;break}}value/=frequency}if(value<0||value>srcLen){AL.currentCtx.err=40963;return}AL.sourceSeek(src,value);break;case 4134:var srcLen=AL.sourceDuration(src);if(srcLen>0){var bytesPerSec;for(var bufId in src.bufQueue){if(bufId){var buf=src.bufQueue[bufId];bytesPerSec=buf.frequency*buf.bytesPerSample*buf.channels;break}}value/=bytesPerSec}if(value<0||value>srcLen){AL.currentCtx.err=40963;return}AL.sourceSeek(src,value);break;case 4628:if(value!==0&&value!==1&&value!==2){AL.currentCtx.err=40963;return}src.spatialize=value;AL.initSourcePanner(src);break;case 8201:case 8202:case 8203:AL.currentCtx.err=40964;break;case 53248:switch(value){case 0:case 53249:case 53250:case 53251:case 53252:case 53253:case 53254:src.distanceModel=value;if(AL.currentCtx.sourceDistanceModel){AL.updateContextGlobal(AL.currentCtx)}break;default:AL.currentCtx.err=40963;return}break;default:AL.currentCtx.err=40962;return}},captures:{},sharedCaptureAudioCtx:null,requireValidCaptureDevice:function(deviceId,funcname){if(deviceId===0){AL.alcErr=40961;return null}var c=AL.captures[deviceId];if(!c){AL.alcErr=40961;return null}var err=c.mediaStreamError;if(err){AL.alcErr=40961;return null}return c}};function _alBufferData(bufferId,format,pData,size,freq){if(!AL.currentCtx){return}var buf=AL.buffers[bufferId];if(!buf){AL.currentCtx.err=40963;return}if(freq<=0){AL.currentCtx.err=40963;return}var audioBuf=null;try{switch(format){case 4352:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(1,size,freq);var channel0=audioBuf.getChannelData(0);for(var i=0;i0){audioBuf=AL.currentCtx.audioCtx.createBuffer(1,size>>1,freq);var channel0=audioBuf.getChannelData(0);pData>>=1;for(var i=0;i>1;++i){channel0[i]=HEAP16[pData++]*30517578125e-15}}buf.bytesPerSample=2;buf.channels=1;buf.length=size>>1;break;case 4354:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(2,size>>1,freq);var channel0=audioBuf.getChannelData(0);var channel1=audioBuf.getChannelData(1);for(var i=0;i>1;++i){channel0[i]=HEAPU8[pData++]*.0078125-1;channel1[i]=HEAPU8[pData++]*.0078125-1}}buf.bytesPerSample=1;buf.channels=2;buf.length=size>>1;break;case 4355:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(2,size>>2,freq);var channel0=audioBuf.getChannelData(0);var channel1=audioBuf.getChannelData(1);pData>>=1;for(var i=0;i>2;++i){channel0[i]=HEAP16[pData++]*30517578125e-15;channel1[i]=HEAP16[pData++]*30517578125e-15}}buf.bytesPerSample=2;buf.channels=2;buf.length=size>>2;break;case 65552:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(1,size>>2,freq);var channel0=audioBuf.getChannelData(0);pData>>=2;for(var i=0;i>2;++i){channel0[i]=HEAPF32[pData++]}}buf.bytesPerSample=4;buf.channels=1;buf.length=size>>2;break;case 65553:if(size>0){audioBuf=AL.currentCtx.audioCtx.createBuffer(2,size>>3,freq);var channel0=audioBuf.getChannelData(0);var channel1=audioBuf.getChannelData(1);pData>>=2;for(var i=0;i>3;++i){channel0[i]=HEAPF32[pData++];channel1[i]=HEAPF32[pData++]}}buf.bytesPerSample=4;buf.channels=2;buf.length=size>>3;break;default:AL.currentCtx.err=40963;return}buf.frequency=freq;buf.audioBuf=audioBuf}catch(e){AL.currentCtx.err=40963;return}}function _alDeleteBuffers(count,pBufferIds){if(!AL.currentCtx){return}for(var i=0;i>2];if(bufId===0){continue}if(!AL.buffers[bufId]){AL.currentCtx.err=40961;return}if(AL.buffers[bufId].refCount){AL.currentCtx.err=40964;return}}for(var i=0;i>2];if(bufId===0){continue}AL.deviceRefCounts[AL.buffers[bufId].deviceId]--;delete AL.buffers[bufId];AL.freeIds.push(bufId)}}function _alSourcei(sourceId,param,value){switch(param){case 514:case 4097:case 4098:case 4103:case 4105:case 4128:case 4129:case 4131:case 4132:case 4133:case 4134:case 4628:case 8201:case 8202:case 53248:AL.setSourceParam("alSourcei",sourceId,param,value);break;default:AL.setSourceParam("alSourcei",sourceId,param,null);break}}function _alDeleteSources(count,pSourceIds){if(!AL.currentCtx){return}for(var i=0;i>2];if(!AL.currentCtx.sources[srcId]){AL.currentCtx.err=40961;return}}for(var i=0;i>2];AL.setSourceState(AL.currentCtx.sources[srcId],4116);_alSourcei(srcId,4105,0);delete AL.currentCtx.sources[srcId];AL.freeIds.push(srcId)}}function _alDistanceModel(model){AL.setGlobalParam("alDistanceModel",53248,model)}function _alDopplerFactor(value){AL.setGlobalParam("alDopplerFactor",49152,value)}function _alGenBuffers(count,pBufferIds){if(!AL.currentCtx){return}for(var i=0;i>2]=buf.id}}function _alGenSources(count,pSourceIds){if(!AL.currentCtx){return}for(var i=0;i>2]=src.id}}function _alGetBufferi(bufferId,param,pValue){var val=AL.getBufferParam("alGetBufferi",bufferId,param);if(val===null){return}if(!pValue){AL.currentCtx.err=40963;return}switch(param){case 8193:case 8194:case 8195:case 8196:HEAP32[pValue>>2]=val;break;default:AL.currentCtx.err=40962;return}}function _alGetError(){if(!AL.currentCtx){return 40964}else{var err=AL.currentCtx.err;AL.currentCtx.err=0;return err}}function _alGetFloat(param){var val=AL.getGlobalParam("alGetFloat",param);if(val===null){return 0}switch(param){case 49152:case 49155:case 53248:return val;default:return 0}}function _alGetListenerf(param,pValue){var val=AL.getListenerParam("alGetListenerf",param);if(val===null){return}if(!pValue){AL.currentCtx.err=40963;return}switch(param){case 4106:HEAPF32[pValue>>2]=val;break;default:AL.currentCtx.err=40962;return}}function _alGetListenerfv(param,pValues){var val=AL.getListenerParam("alGetListenerfv",param);if(val===null){return}if(!pValues){AL.currentCtx.err=40963;return}switch(param){case 4100:case 4102:HEAPF32[pValues>>2]=val[0];HEAPF32[pValues+4>>2]=val[1];HEAPF32[pValues+8>>2]=val[2];break;case 4111:HEAPF32[pValues>>2]=val[0];HEAPF32[pValues+4>>2]=val[1];HEAPF32[pValues+8>>2]=val[2];HEAPF32[pValues+12>>2]=val[3];HEAPF32[pValues+16>>2]=val[4];HEAPF32[pValues+20>>2]=val[5];break;default:AL.currentCtx.err=40962;return}}function _alGetSourcef(sourceId,param,pValue){var val=AL.getSourceParam("alGetSourcef",sourceId,param);if(val===null){return}if(!pValue){AL.currentCtx.err=40963;return}switch(param){case 4097:case 4098:case 4099:case 4106:case 4109:case 4110:case 4128:case 4129:case 4130:case 4131:case 4132:case 4133:case 4134:case 8203:HEAPF32[pValue>>2]=val;break;default:AL.currentCtx.err=40962;return}}function _alGetSourcefv(sourceId,param,pValues){var val=AL.getSourceParam("alGetSourcefv",sourceId,param);if(val===null){return}if(!pValues){AL.currentCtx.err=40963;return}switch(param){case 4097:case 4098:case 4099:case 4106:case 4109:case 4110:case 4128:case 4129:case 4130:case 4131:case 4132:case 4133:case 4134:case 8203:HEAPF32[pValues>>2]=val[0];break;case 4100:case 4101:case 4102:HEAPF32[pValues>>2]=val[0];HEAPF32[pValues+4>>2]=val[1];HEAPF32[pValues+8>>2]=val[2];break;default:AL.currentCtx.err=40962;return}}function _alGetSourcei(sourceId,param,pValue){var val=AL.getSourceParam("alGetSourcei",sourceId,param);if(val===null){return}if(!pValue){AL.currentCtx.err=40963;return}switch(param){case 514:case 4097:case 4098:case 4103:case 4105:case 4112:case 4117:case 4118:case 4128:case 4129:case 4131:case 4132:case 4133:case 4134:case 4135:case 4628:case 8201:case 8202:case 53248:HEAP32[pValue>>2]=val;break;default:AL.currentCtx.err=40962;return}}function _alListenerf(param,value){switch(param){case 4106:AL.setListenerParam("alListenerf",param,value);break;default:AL.setListenerParam("alListenerf",param,null);break}}function _alListenerfv(param,pValues){if(!AL.currentCtx){return}if(!pValues){AL.currentCtx.err=40963;return}switch(param){case 4100:case 4102:AL.paramArray[0]=HEAPF32[pValues>>2];AL.paramArray[1]=HEAPF32[pValues+4>>2];AL.paramArray[2]=HEAPF32[pValues+8>>2];AL.setListenerParam("alListenerfv",param,AL.paramArray);break;case 4111:AL.paramArray[0]=HEAPF32[pValues>>2];AL.paramArray[1]=HEAPF32[pValues+4>>2];AL.paramArray[2]=HEAPF32[pValues+8>>2];AL.paramArray[3]=HEAPF32[pValues+12>>2];AL.paramArray[4]=HEAPF32[pValues+16>>2];AL.paramArray[5]=HEAPF32[pValues+20>>2];AL.setListenerParam("alListenerfv",param,AL.paramArray);break;default:AL.setListenerParam("alListenerfv",param,null);break}}function _alSourcePause(sourceId){if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}AL.setSourceState(src,4115)}function _alSourcePausev(count,pSourceIds){if(!AL.currentCtx){return}if(!pSourceIds){AL.currentCtx.err=40963}for(var i=0;i>2]]){AL.currentCtx.err=40961;return}}for(var i=0;i>2],4115)}}function _alSourcePlay(sourceId){if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}AL.setSourceState(src,4114)}function _alSourcePlayv(count,pSourceIds){if(!AL.currentCtx){return}if(!pSourceIds){AL.currentCtx.err=40963}for(var i=0;i>2]]){AL.currentCtx.err=40961;return}}for(var i=0;i>2],4114)}}function _alSourceQueueBuffers(sourceId,count,pBufferIds){if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}if(src.type===4136){AL.currentCtx.err=40964;return}if(count===0){return}var templateBuf=AL.buffers[0];for(var i=0;i>2];var buf=AL.buffers[bufId];if(!buf){AL.currentCtx.err=40961;return}if(templateBuf.id!==0&&(buf.frequency!==templateBuf.frequency||buf.bytesPerSample!==templateBuf.bytesPerSample||buf.channels!==templateBuf.channels)){AL.currentCtx.err=40964}}if(src.bufQueue.length===1&&src.bufQueue[0].id===0){src.bufQueue.length=0}src.type=4137;for(var i=0;i>2];var buf=AL.buffers[bufId];buf.refCount++;src.bufQueue.push(buf)}if(src.looping){AL.cancelPendingSourceAudio(src)}AL.initSourcePanner(src);AL.scheduleSourceAudio(src)}function _alSourceStop(sourceId){if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}AL.setSourceState(src,4116)}function _alSourceStopv(count,pSourceIds){if(!AL.currentCtx){return}if(!pSourceIds){AL.currentCtx.err=40963}for(var i=0;i>2]]){AL.currentCtx.err=40961;return}}for(var i=0;i>2],4116)}}function _alSourceUnqueueBuffers(sourceId,count,pBufferIds){if(!AL.currentCtx){return}var src=AL.currentCtx.sources[sourceId];if(!src){AL.currentCtx.err=40961;return}if(count>(src.bufQueue.length===1&&src.bufQueue[0].id===0?0:src.bufsProcessed)){AL.currentCtx.err=40963;return}if(count===0){return}for(var i=0;i>2]=buf.id;src.bufsProcessed--}if(src.bufQueue.length===0){src.bufQueue.push(AL.buffers[0])}AL.initSourcePanner(src);AL.scheduleSourceAudio(src)}function _alSourcef(sourceId,param,value){switch(param){case 4097:case 4098:case 4099:case 4106:case 4109:case 4110:case 4128:case 4129:case 4130:case 4131:case 4132:case 4133:case 4134:case 8203:AL.setSourceParam("alSourcef",sourceId,param,value);break;default:AL.setSourceParam("alSourcef",sourceId,param,null);break}}function _alSourcefv(sourceId,param,pValues){if(!AL.currentCtx){return}if(!pValues){AL.currentCtx.err=40963;return}switch(param){case 4097:case 4098:case 4099:case 4106:case 4109:case 4110:case 4128:case 4129:case 4130:case 4131:case 4132:case 4133:case 4134:case 8203:var val=HEAPF32[pValues>>2];AL.setSourceParam("alSourcefv",sourceId,param,val);break;case 4100:case 4101:case 4102:AL.paramArray[0]=HEAPF32[pValues>>2];AL.paramArray[1]=HEAPF32[pValues+4>>2];AL.paramArray[2]=HEAPF32[pValues+8>>2];AL.setSourceParam("alSourcefv",sourceId,param,AL.paramArray);break;default:AL.setSourceParam("alSourcefv",sourceId,param,null);break}}function _alcCaptureCloseDevice(deviceId){var c=AL.requireValidCaptureDevice(deviceId,"alcCaptureCloseDevice");if(!c)return false;delete AL.captures[deviceId];AL.freeIds.push(deviceId);if(c.mediaStreamSourceNode)c.mediaStreamSourceNode.disconnect();if(c.mergerNode)c.mergerNode.disconnect();if(c.splitterNode)c.splitterNode.disconnect();if(c.scriptProcessorNode)c.scriptProcessorNode.disconnect();if(c.mediaStream){c.mediaStream.getTracks().forEach(function(track){track.stop()})}delete c.buffers;c.capturedFrameCount=0;c.isCapturing=false;return true}function _alcCaptureOpenDevice(pDeviceName,requestedSampleRate,format,bufferFrameCapacity){var resolvedDeviceName=AL.CAPTURE_DEVICE_NAME;if(pDeviceName!==0){resolvedDeviceName=UTF8ToString(pDeviceName);if(resolvedDeviceName!==AL.CAPTURE_DEVICE_NAME){AL.alcErr=40965;return 0}}if(bufferFrameCapacity<0){AL.alcErr=40964;return 0}navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia;var has_getUserMedia=navigator.getUserMedia||navigator.mediaDevices&&navigator.mediaDevices.getUserMedia;if(!has_getUserMedia){AL.alcErr=40965;return 0}var AudioContext=window.AudioContext||window.webkitAudioContext;if(!AL.sharedCaptureAudioCtx){try{AL.sharedCaptureAudioCtx=new AudioContext}catch(e){AL.alcErr=40965;return 0}}autoResumeAudioContext(AL.sharedCaptureAudioCtx);var outputChannelCount;switch(format){case 65552:case 4353:case 4352:outputChannelCount=1;break;case 65553:case 4355:case 4354:outputChannelCount=2;break;default:AL.alcErr=40964;return 0}function newF32Array(cap){return new Float32Array(cap)}function newI16Array(cap){return new Int16Array(cap)}function newU8Array(cap){return new Uint8Array(cap)}var requestedSampleType;var newSampleArray;switch(format){case 65552:case 65553:requestedSampleType="f32";newSampleArray=newF32Array;break;case 4353:case 4355:requestedSampleType="i16";newSampleArray=newI16Array;break;case 4352:case 4354:requestedSampleType="u8";newSampleArray=newU8Array;break}var buffers=[];try{for(var chan=0;chanoutputChannelCount){newCapture.mergerNode=newCapture.audioCtx.createChannelMerger(inputChannelCount);newCapture.mediaStreamSourceNode.connect(newCapture.mergerNode);newCapture.mergerNode.connect(newCapture.scriptProcessorNode)}else if(inputChannelCountc.capturedFrameCount){console.error("alcCaptureSamples() with invalid bufferSize");AL.alcErr=40964;return}function setF32Sample(i,sample){HEAPF32[pFrames+4*i>>2]=sample}function setI16Sample(i,sample){HEAP16[pFrames+2*i>>1]=sample}function setU8Sample(i,sample){HEAP8[pFrames+i>>0]=sample}var setSample;switch(c.requestedSampleType){case"f32":setSample=setF32Sample;break;case"i16":setSample=setI16Sample;break;case"u8":setSample=setU8Sample;break;default:return}var dstfreq=c.requestedSampleRate;var srcfreq=c.audioCtx.sampleRate;if(srcfreq==dstfreq){for(var i=0,frame_i=0;frame_i0){return 0}delete AL.deviceRefCounts[deviceId];AL.freeIds.push(deviceId);return 1}function _alcCreateContext(deviceId,pAttrList){if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return 0}var options=null;var attrs=[];var hrtf=null;pAttrList>>=2;if(pAttrList){var attr=0;var val=0;while(true){attr=HEAP32[pAttrList++];attrs.push(attr);if(attr===0){break}val=HEAP32[pAttrList++];attrs.push(val);switch(attr){case 4103:if(!options){options={}}options.sampleRate=val;break;case 4112:case 4113:break;case 6546:switch(val){case 0:hrtf=false;break;case 1:hrtf=true;break;case 2:break;default:AL.alcErr=40964;return 0}break;case 6550:if(val!==0){AL.alcErr=40964;return 0}break;default:AL.alcErr=40964;return 0}}}var AudioContext=window.AudioContext||window.webkitAudioContext;var ac=null;try{if(options){ac=new AudioContext(options)}else{ac=new AudioContext}}catch(e){if(e.name==="NotSupportedError"){AL.alcErr=40964}else{AL.alcErr=40961}return 0}autoResumeAudioContext(ac);if(typeof ac.createGain==="undefined"){ac.createGain=ac.createGainNode}var gain=ac.createGain();gain.connect(ac.destination);var ctx={deviceId:deviceId,id:AL.newId(),attrs:attrs,audioCtx:ac,listener:{position:[0,0,0],velocity:[0,0,0],direction:[0,0,0],up:[0,0,0]},sources:[],interval:setInterval(function(){AL.scheduleContextAudio(ctx)},AL.QUEUE_INTERVAL),gain:gain,distanceModel:53250,speedOfSound:343.3,dopplerFactor:1,sourceDistanceModel:false,hrtf:hrtf||false,_err:0,get err(){return this._err},set err(val){if(this._err===0||val===0){this._err=val}}};AL.deviceRefCounts[deviceId]++;AL.contexts[ctx.id]=ctx;if(hrtf!==null){for(var ctxId in AL.contexts){var c=AL.contexts[ctxId];if(c.deviceId===deviceId){c.hrtf=hrtf;AL.updateContextGlobal(c)}}}return ctx.id}function _alcDestroyContext(contextId){var ctx=AL.contexts[contextId];if(AL.currentCtx===ctx){AL.alcErr=40962;return}if(AL.contexts[contextId].interval){clearInterval(AL.contexts[contextId].interval)}AL.deviceRefCounts[ctx.deviceId]--;delete AL.contexts[contextId];AL.freeIds.push(contextId)}function _alcGetCurrentContext(){if(AL.currentCtx!==null){return AL.currentCtx.id}else{return 0}}function _alcGetError(deviceId){var err=AL.alcErr;AL.alcErr=0;return err}function _alcGetIntegerv(deviceId,param,size,pValues){if(size===0||!pValues){return}switch(param){case 4096:HEAP32[pValues>>2]=1;break;case 4097:HEAP32[pValues>>2]=1;break;case 4098:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}HEAP32[pValues>>2]=AL.currentCtx.attrs.length;break;case 4099:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}for(var i=0;i>2]=AL.currentCtx.attrs[i]}break;case 4103:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}HEAP32[pValues>>2]=AL.currentCtx.audioCtx.sampleRate;break;case 4112:case 4113:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}HEAP32[pValues>>2]=2147483647;break;case 6546:case 6547:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}var hrtfStatus=0;for(var ctxId in AL.contexts){var ctx=AL.contexts[ctxId];if(ctx.deviceId===deviceId){hrtfStatus=ctx.hrtf?1:0}}HEAP32[pValues>>2]=hrtfStatus;break;case 6548:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}HEAP32[pValues>>2]=1;break;case 131075:if(!(deviceId in AL.deviceRefCounts)){AL.alcErr=40961;return}if(!AL.currentCtx){AL.alcErr=40962;return}HEAP32[pValues>>2]=1;case 786:var c=AL.requireValidCaptureDevice(deviceId,"alcGetIntegerv");if(!c){return}var n=c.capturedFrameCount;var dstfreq=c.requestedSampleRate;var srcfreq=c.audioCtx.sampleRate;var nsamples=Math.floor(n*(dstfreq/srcfreq));HEAP32[pValues>>2]=nsamples;break;default:AL.alcErr=40963;return}}function _alcGetString(deviceId,param){if(AL.alcStringCache[param]){return AL.alcStringCache[param]}var ret;switch(param){case 0:ret="No Error";break;case 40961:ret="Invalid Device";break;case 40962:ret="Invalid Context";break;case 40963:ret="Invalid Enum";break;case 40964:ret="Invalid Value";break;case 40965:ret="Out of Memory";break;case 4100:if(typeof AudioContext!=="undefined"||typeof webkitAudioContext!=="undefined"){ret=AL.DEVICE_NAME}else{return 0}break;case 4101:if(typeof AudioContext!=="undefined"||typeof webkitAudioContext!=="undefined"){ret=AL.DEVICE_NAME.concat("\0")}else{ret="\0"}break;case 785:ret=AL.CAPTURE_DEVICE_NAME;break;case 784:if(deviceId===0)ret=AL.CAPTURE_DEVICE_NAME.concat("\0");else{var c=AL.requireValidCaptureDevice(deviceId,"alcGetString");if(!c){return 0}ret=c.deviceName}break;case 4102:if(!deviceId){AL.alcErr=40961;return 0}ret="";for(var ext in AL.ALC_EXTENSIONS){ret=ret.concat(ext);ret=ret.concat(" ")}ret=ret.trim();break;default:AL.alcErr=40963;return 0}ret=allocate(intArrayFromString(ret),"i8",ALLOC_NORMAL);AL.alcStringCache[param]=ret;return ret}function _alcMakeContextCurrent(contextId){if(contextId===0){AL.currentCtx=null;return 0}else{AL.currentCtx=AL.contexts[contextId];return 1}}function _alcOpenDevice(pDeviceName){if(pDeviceName){var name=UTF8ToString(pDeviceName);if(name!==AL.DEVICE_NAME){return 0}}if(typeof AudioContext!=="undefined"||typeof webkitAudioContext!=="undefined"){var deviceId=AL.newId();AL.deviceRefCounts[deviceId]=0;return deviceId}else{return 0}}function _clock(){if(_clock.start===undefined)_clock.start=Date.now();return(Date.now()-_clock.start)*(1e6/1e3)|0}function _difftime(time1,time0){return time1-time0}function _dlclose(handle){abort("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")}function _dlerror(){abort("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")}function _dlopen(filename,flag){abort("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")}function _dlsym(handle,symbol){abort("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")}var EGL={errorCode:12288,defaultDisplayInitialized:false,currentContext:0,currentReadSurface:0,currentDrawSurface:0,contextAttributes:{alpha:false,depth:false,stencil:false,antialias:false},stringCache:{},setErrorCode:function(code){EGL.errorCode=code},chooseConfig:function(display,attribList,config,config_size,numConfigs){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(attribList){for(;;){var param=HEAP32[attribList>>2];if(param==12321){var alphaSize=HEAP32[attribList+4>>2];EGL.contextAttributes.alpha=alphaSize>0}else if(param==12325){var depthSize=HEAP32[attribList+4>>2];EGL.contextAttributes.depth=depthSize>0}else if(param==12326){var stencilSize=HEAP32[attribList+4>>2];EGL.contextAttributes.stencil=stencilSize>0}else if(param==12337){var samples=HEAP32[attribList+4>>2];EGL.contextAttributes.antialias=samples>0}else if(param==12338){var samples=HEAP32[attribList+4>>2];EGL.contextAttributes.antialias=samples==1}else if(param==12544){var requestedPriority=HEAP32[attribList+4>>2];EGL.contextAttributes.lowLatency=requestedPriority!=12547}else if(param==12344){break}attribList+=8}}if((!config||!config_size)&&!numConfigs){EGL.setErrorCode(12300);return 0}if(numConfigs){HEAP32[numConfigs>>2]=1}if(config&&config_size>0){HEAP32[config>>2]=62002}EGL.setErrorCode(12288);return 1}};function _eglBindAPI(api){if(api==12448){EGL.setErrorCode(12288);return 1}else{EGL.setErrorCode(12300);return 0}}function _eglChooseConfig(display,attrib_list,configs,config_size,numConfigs){return EGL.chooseConfig(display,attrib_list,configs,config_size,numConfigs)}function __webgl_enable_ANGLE_instanced_arrays(ctx){var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=function(index,divisor){ext["vertexAttribDivisorANGLE"](index,divisor)};ctx["drawArraysInstanced"]=function(mode,first,count,primcount){ext["drawArraysInstancedANGLE"](mode,first,count,primcount)};ctx["drawElementsInstanced"]=function(mode,count,type,indices,primcount){ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount)};return 1}}function __webgl_enable_OES_vertex_array_object(ctx){var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=function(){return ext["createVertexArrayOES"]()};ctx["deleteVertexArray"]=function(vao){ext["deleteVertexArrayOES"](vao)};ctx["bindVertexArray"]=function(vao){ext["bindVertexArrayOES"](vao)};ctx["isVertexArray"]=function(vao){return ext["isVertexArrayOES"](vao)};return 1}}function __webgl_enable_WEBGL_draw_buffers(ctx){var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=function(n,bufs){ext["drawBuffersWEBGL"](n,bufs)};return 1}}function __webgl_enable_WEBGL_multi_draw(ctx){return!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"))}var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],uniforms:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},timerQueriesEXT:[],byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],programInfos:{},stringCache:{},unpackAlignment:4,recordError:function recordError(errorCode){if(!GL.lastError){GL.lastError=errorCode}},getNewId:function(table){var ret=GL.counter++;for(var i=table.length;i>1;var quadIndexes=new Uint16Array(numIndexes);var i=0,v=0;while(1){quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+1;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v+3;if(i>=numIndexes)break;v+=4}context.GLctx.bufferData(34963,quadIndexes,35044);context.GLctx.bindBuffer(34963,null)}},getTempVertexBuffer:function getTempVertexBuffer(sizeBytes){var idx=GL.log2ceilLookup(sizeBytes);var ringbuffer=GL.currentContext.tempVertexBuffers1[idx];var nextFreeBufferIndex=GL.currentContext.tempVertexBufferCounters1[idx];GL.currentContext.tempVertexBufferCounters1[idx]=GL.currentContext.tempVertexBufferCounters1[idx]+1&GL.numTempVertexBuffersPerSize-1;var vbo=ringbuffer[nextFreeBufferIndex];if(vbo){return vbo}var prevVBO=GLctx.getParameter(34964);ringbuffer[nextFreeBufferIndex]=GLctx.createBuffer();GLctx.bindBuffer(34962,ringbuffer[nextFreeBufferIndex]);GLctx.bufferData(34962,1<>2]:-1;source+=UTF8ToString(HEAP32[string+i*4>>2],len<0?undefined:len)}return source},calcBufLength:function calcBufLength(size,type,stride,count){if(stride>0){return count*stride}var typeSize=GL.byteSizeByType[type-GL.byteSizeByTypeRoot];return size*typeSize*count},usedTempBuffers:[],preDrawHandleClientVertexAttribBindings:function preDrawHandleClientVertexAttribBindings(count){GL.resetBufferBinding=false;for(var i=0;i>2];if(param==12440){glesContextVersion=HEAP32[contextAttribs+4>>2]}else if(param==12344){break}else{EGL.setErrorCode(12292);return 0}contextAttribs+=8}if(glesContextVersion!=2){EGL.setErrorCode(12293);return 0}EGL.contextAttributes.majorVersion=glesContextVersion-1;EGL.contextAttributes.minorVersion=0;EGL.context=GL.createContext(Module["canvas"],EGL.contextAttributes);if(EGL.context!=0){EGL.setErrorCode(12288);GL.makeContextCurrent(EGL.context);Module.useWebGL=true;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});GL.makeContextCurrent(null);return 62004}else{EGL.setErrorCode(12297);return 0}}function _eglCreateWindowSurface(display,config,win,attrib_list){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}EGL.setErrorCode(12288);return 62006}function _eglDestroyContext(display,context){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=62004){EGL.setErrorCode(12294);return 0}GL.deleteContext(EGL.context);EGL.setErrorCode(12288);if(EGL.currentContext==context){EGL.currentContext=0}return 1}function _eglDestroySurface(display,surface){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(surface!=62006){EGL.setErrorCode(12301);return 1}if(EGL.currentReadSurface==surface){EGL.currentReadSurface=0}if(EGL.currentDrawSurface==surface){EGL.currentDrawSurface=0}EGL.setErrorCode(12288);return 1}function _eglGetConfigAttrib(display,config,attribute,value){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12320:HEAP32[value>>2]=EGL.contextAttributes.alpha?32:24;return 1;case 12321:HEAP32[value>>2]=EGL.contextAttributes.alpha?8:0;return 1;case 12322:HEAP32[value>>2]=8;return 1;case 12323:HEAP32[value>>2]=8;return 1;case 12324:HEAP32[value>>2]=8;return 1;case 12325:HEAP32[value>>2]=EGL.contextAttributes.depth?24:0;return 1;case 12326:HEAP32[value>>2]=EGL.contextAttributes.stencil?8:0;return 1;case 12327:HEAP32[value>>2]=12344;return 1;case 12328:HEAP32[value>>2]=62002;return 1;case 12329:HEAP32[value>>2]=0;return 1;case 12330:HEAP32[value>>2]=4096;return 1;case 12331:HEAP32[value>>2]=16777216;return 1;case 12332:HEAP32[value>>2]=4096;return 1;case 12333:HEAP32[value>>2]=0;return 1;case 12334:HEAP32[value>>2]=0;return 1;case 12335:HEAP32[value>>2]=12344;return 1;case 12337:HEAP32[value>>2]=EGL.contextAttributes.antialias?4:0;return 1;case 12338:HEAP32[value>>2]=EGL.contextAttributes.antialias?1:0;return 1;case 12339:HEAP32[value>>2]=4;return 1;case 12340:HEAP32[value>>2]=12344;return 1;case 12341:case 12342:case 12343:HEAP32[value>>2]=-1;return 1;case 12345:case 12346:HEAP32[value>>2]=0;return 1;case 12347:HEAP32[value>>2]=0;return 1;case 12348:HEAP32[value>>2]=1;return 1;case 12349:case 12350:HEAP32[value>>2]=0;return 1;case 12351:HEAP32[value>>2]=12430;return 1;case 12352:HEAP32[value>>2]=4;return 1;case 12354:HEAP32[value>>2]=0;return 1;default:EGL.setErrorCode(12292);return 0}}function _eglGetDisplay(nativeDisplayType){EGL.setErrorCode(12288);return 62e3}function _eglGetError(){return EGL.errorCode}function _eglGetProcAddress(name_){return _emscripten_GetProcAddress(name_)}function _eglInitialize(display,majorVersion,minorVersion){if(display==62e3){if(majorVersion){HEAP32[majorVersion>>2]=1}if(minorVersion){HEAP32[minorVersion>>2]=4}EGL.defaultDisplayInitialized=true;EGL.setErrorCode(12288);return 1}else{EGL.setErrorCode(12296);return 0}}function _eglMakeCurrent(display,draw,read,context){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=0&&context!=62004){EGL.setErrorCode(12294);return 0}if(read!=0&&read!=62006||draw!=0&&draw!=62006){EGL.setErrorCode(12301);return 0}GL.makeContextCurrent(context?EGL.context:null);EGL.currentContext=context;EGL.currentDrawSurface=draw;EGL.currentReadSurface=read;EGL.setErrorCode(12288);return 1}function _eglQueryString(display,name){if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.setErrorCode(12288);if(EGL.stringCache[name])return EGL.stringCache[name];var ret;switch(name){case 12371:ret=allocateUTF8("Emscripten");break;case 12372:ret=allocateUTF8("1.4 Emscripten EGL");break;case 12373:ret=allocateUTF8("");break;case 12429:ret=allocateUTF8("OpenGL_ES");break;default:EGL.setErrorCode(12300);return 0}EGL.stringCache[name]=ret;return ret}function _eglSwapBuffers(){if(!EGL.defaultDisplayInitialized){EGL.setErrorCode(12289)}else if(!Module.ctx){EGL.setErrorCode(12290)}else if(Module.ctx.isContextLost()){EGL.setErrorCode(12302)}else{EGL.setErrorCode(12288);return 1}return 0}function _eglSwapInterval(display,interval){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(interval==0)_emscripten_set_main_loop_timing(0,0);else _emscripten_set_main_loop_timing(1,interval);EGL.setErrorCode(12288);return 1}function _eglTerminate(display){if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.currentContext=0;EGL.currentReadSurface=0;EGL.currentDrawSurface=0;EGL.defaultDisplayInitialized=false;EGL.setErrorCode(12288);return 1}function _eglWaitClient(){EGL.setErrorCode(12288);return 1}function _eglWaitGL(){return _eglWaitClient()}function _eglWaitNative(nativeEngineId){EGL.setErrorCode(12288);return 1}function _emscripten_asm_const_int(code,sigPtr,argbuf){var args=readAsmConstArgs(sigPtr,argbuf);return ASM_CONSTS[code].apply(null,args)}function _emscripten_cancel_main_loop(){Browser.mainLoop.pause();Browser.mainLoop.func=null}var JSEvents={inEventHandler:0,removeAllEventListeners:function(){for(var i=JSEvents.eventHandlers.length-1;i>=0;--i){JSEvents._removeHandler(i)}JSEvents.eventHandlers=[];JSEvents.deferredCalls=[]},registerRemoveEventListeners:function(){if(!JSEvents.removeEventListenersRegistered){__ATEXIT__.push(JSEvents.removeAllEventListeners);JSEvents.removeEventListenersRegistered=true}},deferredCalls:[],deferCall:function(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort(function(x,y){return x.precedence2?UTF8ToString(cString):cString}var specialHTMLTargets=[0,typeof document!=="undefined"?document:0,typeof window!=="undefined"?window:0];function findEventTarget(target){target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||(typeof document!=="undefined"?document.querySelector(target):undefined);return domElement}function findCanvasEventTarget(target){return findEventTarget(target)}function _emscripten_get_canvas_element_size(target,width,height){var canvas=findCanvasEventTarget(target);if(!canvas)return-4;HEAP32[width>>2]=canvas.width;HEAP32[height>>2]=canvas.height}function __get_canvas_element_size(target){var stackTop=stackSave();var w=stackAlloc(8);var h=w+4;var targetInt=stackAlloc(target.id.length+1);stringToUTF8(target.id,targetInt,target.id.length+1);var ret=_emscripten_get_canvas_element_size(targetInt,w,h);var size=[HEAP32[w>>2],HEAP32[h>>2]];stackRestore(stackTop);return size}function _emscripten_set_canvas_element_size(target,width,height){var canvas=findCanvasEventTarget(target);if(!canvas)return-4;canvas.width=width;canvas.height=height;return 0}function __set_canvas_element_size(target,width,height){if(!target.controlTransferredOffscreen){target.width=width;target.height=height}else{var stackTop=stackSave();var targetInt=stackAlloc(target.id.length+1);stringToUTF8(target.id,targetInt,target.id.length+1);_emscripten_set_canvas_element_size(targetInt,width,height);stackRestore(stackTop)}}function __registerRestoreOldStyle(canvas){var canvasSize=__get_canvas_element_size(canvas);var oldWidth=canvasSize[0];var oldHeight=canvasSize[1];var oldCssWidth=canvas.style.width;var oldCssHeight=canvas.style.height;var oldBackgroundColor=canvas.style.backgroundColor;var oldDocumentBackgroundColor=document.body.style.backgroundColor;var oldPaddingLeft=canvas.style.paddingLeft;var oldPaddingRight=canvas.style.paddingRight;var oldPaddingTop=canvas.style.paddingTop;var oldPaddingBottom=canvas.style.paddingBottom;var oldMarginLeft=canvas.style.marginLeft;var oldMarginRight=canvas.style.marginRight;var oldMarginTop=canvas.style.marginTop;var oldMarginBottom=canvas.style.marginBottom;var oldDocumentBodyMargin=document.body.style.margin;var oldDocumentOverflow=document.documentElement.style.overflow;var oldDocumentScroll=document.body.scroll;var oldImageRendering=canvas.style.imageRendering;function restoreOldStyle(){var fullscreenElement=document.fullscreenElement||document.webkitFullscreenElement||document.msFullscreenElement;if(!fullscreenElement){document.removeEventListener("fullscreenchange",restoreOldStyle);document.removeEventListener("webkitfullscreenchange",restoreOldStyle);__set_canvas_element_size(canvas,oldWidth,oldHeight);canvas.style.width=oldCssWidth;canvas.style.height=oldCssHeight;canvas.style.backgroundColor=oldBackgroundColor;if(!oldDocumentBackgroundColor)document.body.style.backgroundColor="white";document.body.style.backgroundColor=oldDocumentBackgroundColor;canvas.style.paddingLeft=oldPaddingLeft;canvas.style.paddingRight=oldPaddingRight;canvas.style.paddingTop=oldPaddingTop;canvas.style.paddingBottom=oldPaddingBottom;canvas.style.marginLeft=oldMarginLeft;canvas.style.marginRight=oldMarginRight;canvas.style.marginTop=oldMarginTop;canvas.style.marginBottom=oldMarginBottom;document.body.style.margin=oldDocumentBodyMargin;document.documentElement.style.overflow=oldDocumentOverflow;document.body.scroll=oldDocumentScroll;canvas.style.imageRendering=oldImageRendering;if(canvas.GLctxObject)canvas.GLctxObject.GLctx.viewport(0,0,oldWidth,oldHeight);if(__currentFullscreenStrategy.canvasResizedCallback){wasmTable.get(__currentFullscreenStrategy.canvasResizedCallback)(37,0,__currentFullscreenStrategy.canvasResizedCallbackUserData)}}}document.addEventListener("fullscreenchange",restoreOldStyle);document.addEventListener("webkitfullscreenchange",restoreOldStyle);return restoreOldStyle}function __setLetterbox(element,topBottom,leftRight){element.style.paddingLeft=element.style.paddingRight=leftRight+"px";element.style.paddingTop=element.style.paddingBottom=topBottom+"px"}function __getBoundingClientRect(e){return specialHTMLTargets.indexOf(e)<0?e.getBoundingClientRect():{"left":0,"top":0}}function _JSEvents_resizeCanvasForFullscreen(target,strategy){var restoreOldStyle=__registerRestoreOldStyle(target);var cssWidth=strategy.softFullscreen?innerWidth:screen.width;var cssHeight=strategy.softFullscreen?innerHeight:screen.height;var rect=__getBoundingClientRect(target);var windowedCssWidth=rect.width;var windowedCssHeight=rect.height;var canvasSize=__get_canvas_element_size(target);var windowedRttWidth=canvasSize[0];var windowedRttHeight=canvasSize[1];if(strategy.scaleMode==3){__setLetterbox(target,(cssHeight-windowedCssHeight)/2,(cssWidth-windowedCssWidth)/2);cssWidth=windowedCssWidth;cssHeight=windowedCssHeight}else if(strategy.scaleMode==2){if(cssWidth*windowedRttHeight>3]=e.chargingTime;HEAPF64[eventStruct+8>>3]=e.dischargingTime;HEAPF64[eventStruct+16>>3]=e.level;HEAP32[eventStruct+24>>2]=e.charging}function __battery(){return navigator.battery||navigator.mozBattery||navigator.webkitBattery}function _emscripten_get_battery_status(batteryState){if(!__battery())return-1;__fillBatteryEventData(batteryState,__battery());return 0}function _emscripten_get_device_pixel_ratio(){return typeof devicePixelRatio==="number"&&devicePixelRatio||1}function _emscripten_get_element_css_size(target,width,height){target=findEventTarget(target);if(!target)return-4;var rect=__getBoundingClientRect(target);HEAPF64[width>>3]=rect.width;HEAPF64[height>>3]=rect.height;return 0}function __fillGamepadEventData(eventStruct,e){HEAPF64[eventStruct>>3]=e.timestamp;for(var i=0;i>3]=e.axes[i]}for(var i=0;i>3]=e.buttons[i].value}else{HEAPF64[eventStruct+i*8+528>>3]=e.buttons[i]}}for(var i=0;i>2]=e.buttons[i].pressed}else{HEAP32[eventStruct+i*4+1040>>2]=e.buttons[i]==1}}HEAP32[eventStruct+1296>>2]=e.connected;HEAP32[eventStruct+1300>>2]=e.index;HEAP32[eventStruct+8>>2]=e.axes.length;HEAP32[eventStruct+12>>2]=e.buttons.length;stringToUTF8(e.id,eventStruct+1304,64);stringToUTF8(e.mapping,eventStruct+1368,64)}function _emscripten_get_gamepad_status(index,gamepadState){if(index<0||index>=JSEvents.lastGamepadState.length)return-5;if(!JSEvents.lastGamepadState[index])return-7;__fillGamepadEventData(gamepadState,JSEvents.lastGamepadState[index]);return 0}function _emscripten_get_num_gamepads(){return JSEvents.lastGamepadState.length}function _emscripten_get_sbrk_ptr(){return 1918800}function _emscripten_glActiveTexture(x0){GLctx["activeTexture"](x0)}function _emscripten_glAttachShader(program,shader){GLctx.attachShader(GL.programs[program],GL.shaders[shader])}function _emscripten_glBeginQueryEXT(target,id){GLctx.disjointTimerQueryExt["beginQueryEXT"](target,GL.timerQueriesEXT[id])}function _emscripten_glBindAttribLocation(program,index,name){GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}function _emscripten_glBindBuffer(target,buffer){if(target==34962){GLctx.currentArrayBufferBinding=buffer}else if(target==34963){GLctx.currentElementArrayBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])}function _emscripten_glBindFramebuffer(target,framebuffer){GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])}function _emscripten_glBindRenderbuffer(target,renderbuffer){GLctx.bindRenderbuffer(target,GL.renderbuffers[renderbuffer])}function _emscripten_glBindTexture(target,texture){GLctx.bindTexture(target,GL.textures[texture])}function _emscripten_glBindVertexArrayOES(vao){GLctx["bindVertexArray"](GL.vaos[vao]);var ibo=GLctx.getParameter(34965);GLctx.currentElementArrayBufferBinding=ibo?ibo.name|0:0}function _emscripten_glBlendColor(x0,x1,x2,x3){GLctx["blendColor"](x0,x1,x2,x3)}function _emscripten_glBlendEquation(x0){GLctx["blendEquation"](x0)}function _emscripten_glBlendEquationSeparate(x0,x1){GLctx["blendEquationSeparate"](x0,x1)}function _emscripten_glBlendFunc(x0,x1){GLctx["blendFunc"](x0,x1)}function _emscripten_glBlendFuncSeparate(x0,x1,x2,x3){GLctx["blendFuncSeparate"](x0,x1,x2,x3)}function _emscripten_glBufferData(target,size,data,usage){GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}function _emscripten_glBufferSubData(target,offset,size,data){GLctx.bufferSubData(target,offset,HEAPU8.subarray(data,data+size))}function _emscripten_glCheckFramebufferStatus(x0){return GLctx["checkFramebufferStatus"](x0)}function _emscripten_glClear(x0){GLctx["clear"](x0)}function _emscripten_glClearColor(x0,x1,x2,x3){GLctx["clearColor"](x0,x1,x2,x3)}function _emscripten_glClearDepthf(x0){GLctx["clearDepth"](x0)}function _emscripten_glClearStencil(x0){GLctx["clearStencil"](x0)}function _emscripten_glColorMask(red,green,blue,alpha){GLctx.colorMask(!!red,!!green,!!blue,!!alpha)}function _emscripten_glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _emscripten_glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCopyTexImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_glCopyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexSubImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_glCreateProgram(){var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;GL.programs[id]=program;return id}function _emscripten_glCreateShader(shaderType){var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id}function _emscripten_glCullFace(x0){GLctx["cullFace"](x0)}function _emscripten_glDeleteBuffers(n,buffers){for(var i=0;i>2];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GLctx.currentArrayBufferBinding)GLctx.currentArrayBufferBinding=0;if(id==GLctx.currentElementArrayBufferBinding)GLctx.currentElementArrayBufferBinding=0}}function _emscripten_glDeleteFramebuffers(n,framebuffers){for(var i=0;i>2];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}function _emscripten_glDeleteProgram(id){if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null;GL.programInfos[id]=null}function _emscripten_glDeleteQueriesEXT(n,ids){for(var i=0;i>2];var query=GL.timerQueriesEXT[id];if(!query)continue;GLctx.disjointTimerQueryExt["deleteQueryEXT"](query);GL.timerQueriesEXT[id]=null}}function _emscripten_glDeleteRenderbuffers(n,renderbuffers){for(var i=0;i>2];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}function _emscripten_glDeleteShader(id){if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null}function _emscripten_glDeleteTextures(n,textures){for(var i=0;i>2];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}function _emscripten_glDeleteVertexArraysOES(n,vaos){for(var i=0;i>2];GLctx["deleteVertexArray"](GL.vaos[id]);GL.vaos[id]=null}}function _emscripten_glDepthFunc(x0){GLctx["depthFunc"](x0)}function _emscripten_glDepthMask(flag){GLctx.depthMask(!!flag)}function _emscripten_glDepthRangef(x0,x1){GLctx["depthRange"](x0,x1)}function _emscripten_glDetachShader(program,shader){GLctx.detachShader(GL.programs[program],GL.shaders[shader])}function _emscripten_glDisable(x0){GLctx["disable"](x0)}function _emscripten_glDisableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=false;GLctx.disableVertexAttribArray(index)}function _emscripten_glDrawArrays(mode,first,count){GL.preDrawHandleClientVertexAttribBindings(first+count);GLctx.drawArrays(mode,first,count);GL.postDrawHandleClientVertexAttribBindings()}function _emscripten_glDrawArraysInstancedANGLE(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}var tempFixedLengthArray=[];function _emscripten_glDrawBuffersWEBGL(n,bufs){var bufArray=tempFixedLengthArray[n];for(var i=0;i>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawElements(mode,count,type,indices){var buf;if(!GLctx.currentElementArrayBufferBinding){var size=GL.calcBufLength(1,type,0,count);buf=GL.getTempIndexBuffer(size);GLctx.bindBuffer(34963,buf);GLctx.bufferSubData(34963,0,HEAPU8.subarray(indices,indices+size));indices=0}GL.preDrawHandleClientVertexAttribBindings(count);GLctx.drawElements(mode,count,type,indices);GL.postDrawHandleClientVertexAttribBindings(count);if(!GLctx.currentElementArrayBufferBinding){GLctx.bindBuffer(34963,null)}}function _emscripten_glDrawElementsInstancedANGLE(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glEnable(x0){GLctx["enable"](x0)}function _emscripten_glEnableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=true;GLctx.enableVertexAttribArray(index)}function _emscripten_glEndQueryEXT(target){GLctx.disjointTimerQueryExt["endQueryEXT"](target)}function _emscripten_glFinish(){GLctx["finish"]()}function _emscripten_glFlush(){GLctx["flush"]()}function _emscripten_glFramebufferRenderbuffer(target,attachment,renderbuffertarget,renderbuffer){GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])}function _emscripten_glFramebufferTexture2D(target,attachment,textarget,texture,level){GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)}function _emscripten_glFrontFace(x0){GLctx["frontFace"](x0)}function __glGenObject(n,buffers,createFunction,objectTable){for(var i=0;i>2]=id}}function _emscripten_glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _emscripten_glGenFramebuffers(n,ids){__glGenObject(n,ids,"createFramebuffer",GL.framebuffers)}function _emscripten_glGenQueriesEXT(n,ids){for(var i=0;i>2]=0;return}var id=GL.getNewId(GL.timerQueriesEXT);query.name=id;GL.timerQueriesEXT[id]=query;HEAP32[ids+i*4>>2]=id}}function _emscripten_glGenRenderbuffers(n,renderbuffers){__glGenObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}function _emscripten_glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _emscripten_glGenVertexArraysOES(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _emscripten_glGenerateMipmap(x0){GLctx["generateMipmap"](x0)}function __glGetActiveAttribOrUniform(funcName,program,index,bufSize,length,size,type,name){program=GL.programs[program];var info=GLctx[funcName](program,index);if(info){var numBytesWrittenExclNull=name&&stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>2]=numBytesWrittenExclNull;if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}}function _emscripten_glGetActiveAttrib(program,index,bufSize,length,size,type,name){__glGetActiveAttribOrUniform("getActiveAttrib",program,index,bufSize,length,size,type,name)}function _emscripten_glGetActiveUniform(program,index,bufSize,length,size,type,name){__glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}function _emscripten_glGetAttachedShaders(program,maxCount,count,shaders){var result=GLctx.getAttachedShaders(GL.programs[program]);var len=result.length;if(len>maxCount){len=maxCount}HEAP32[count>>2]=len;for(var i=0;i>2]=id}}function _emscripten_glGetAttribLocation(program,name){return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}function writeI53ToI64(ptr,num){HEAPU32[ptr>>2]=num;HEAPU32[ptr+4>>2]=(num-HEAPU32[ptr>>2])/4294967296}function emscriptenWebGLGet(name_,p,type){if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>2]=result[i];break;case 2:HEAPF32[p+i*4>>2]=result[i];break;case 4:HEAP8[p+i>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Unknown object returned from WebGL getParameter("+name_+")! (error: "+e+")");return}}break;default:GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Native code calling glGet"+type+"v("+name_+") and it returns "+result+" of type "+typeof result+"!");return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>2]=ret;break;case 2:HEAPF32[p>>2]=ret;break;case 4:HEAP8[p>>0]=ret?1:0;break}}function _emscripten_glGetBooleanv(name_,p){emscriptenWebGLGet(name_,p,4)}function _emscripten_glGetBufferParameteriv(target,value,data){if(!data){GL.recordError(1281);return}HEAP32[data>>2]=GLctx.getBufferParameter(target,value)}function _emscripten_glGetError(){var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error}function _emscripten_glGetFloatv(name_,p){emscriptenWebGLGet(name_,p,2)}function _emscripten_glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>2]=result}function _emscripten_glGetIntegerv(name_,p){emscriptenWebGLGet(name_,p,0)}function _emscripten_glGetProgramInfoLog(program,maxLength,length,infoLog){var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _emscripten_glGetProgramiv(program,pname,p){if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}var ptable=GL.programInfos[program];if(!ptable){GL.recordError(1282);return}if(pname==35716){var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35719){HEAP32[p>>2]=ptable.maxUniformLength}else if(pname==35722){if(ptable.maxAttributeLength==-1){program=GL.programs[program];var numAttribs=GLctx.getProgramParameter(program,35721);ptable.maxAttributeLength=0;for(var i=0;i>2]=ptable.maxAttributeLength}else if(pname==35381){if(ptable.maxUniformBlockNameLength==-1){program=GL.programs[program];var numBlocks=GLctx.getProgramParameter(program,35382);ptable.maxUniformBlockNameLength=0;for(var i=0;i>2]=ptable.maxUniformBlockNameLength}else{HEAP32[p>>2]=GLctx.getProgramParameter(GL.programs[program],pname)}}function _emscripten_glGetQueryObjecti64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}function _emscripten_glGetQueryObjectivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryObjectui64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}function _emscripten_glGetQueryObjectuivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.timerQueriesEXT[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryivEXT(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.disjointTimerQueryExt["getQueryEXT"](target,pname)}function _emscripten_glGetRenderbufferParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getRenderbufferParameter(target,pname)}function _emscripten_glGetShaderInfoLog(shader,maxLength,length,infoLog){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _emscripten_glGetShaderPrecisionFormat(shaderType,precisionType,range,precision){var result=GLctx.getShaderPrecisionFormat(shaderType,precisionType);HEAP32[range>>2]=result.rangeMin;HEAP32[range+4>>2]=result.rangeMax;HEAP32[precision>>2]=result.precision}function _emscripten_glGetShaderSource(shader,bufSize,length,source){var result=GLctx.getShaderSource(GL.shaders[shader]);if(!result)return;var numBytesWrittenExclNull=bufSize>0&&source?stringToUTF8(result,source,bufSize):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _emscripten_glGetShaderiv(shader,pname,p){if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>2]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>2]=sourceLength}else{HEAP32[p>>2]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}function stringToNewUTF8(jsString){var length=lengthBytesUTF8(jsString)+1;var cString=_malloc(length);stringToUTF8(jsString,cString,length);return cString}function _emscripten_glGetString(name_){if(GL.stringCache[name_])return GL.stringCache[name_];var ret;switch(name_){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));ret=stringToNewUTF8(exts.join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=stringToNewUTF8(s);break;case 7938:var glVersion=GLctx.getParameter(7938);{glVersion="OpenGL ES 2.0 ("+glVersion+")"}ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion="OpenGL ES GLSL ES "+ver_num[1]+" ("+glslVersion+")"}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280);return 0}GL.stringCache[name_]=ret;return ret}function _emscripten_glGetTexParameterfv(target,pname,params){if(!params){GL.recordError(1281);return}HEAPF32[params>>2]=GLctx.getTexParameter(target,pname)}function _emscripten_glGetTexParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getTexParameter(target,pname)}function _emscripten_glGetUniformLocation(program,name){name=UTF8ToString(name);var arrayIndex=0;if(name[name.length-1]=="]"){var leftBrace=name.lastIndexOf("[");arrayIndex=name[leftBrace+1]!="]"?jstoi_q(name.slice(leftBrace+1)):0;name=name.slice(0,leftBrace)}var uniformInfo=GL.programInfos[program]&&GL.programInfos[program].uniforms[name];if(uniformInfo&&arrayIndex>=0&&arrayIndex>2]=data;break;case 2:HEAPF32[params>>2]=data;break}}else{for(var i=0;i>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break}}}}function _emscripten_glGetUniformfv(program,location,params){emscriptenWebGLGetUniform(program,location,params,2)}function _emscripten_glGetUniformiv(program,location,params){emscriptenWebGLGetUniform(program,location,params,0)}function _emscripten_glGetVertexAttribPointerv(index,pname,pointer){if(!pointer){GL.recordError(1281);return}if(GL.currentContext.clientBuffers[index].enabled){err("glGetVertexAttribPointer on client-side array: not supported, bad data returned")}HEAP32[pointer>>2]=GLctx.getVertexAttribOffset(index,pname)}function emscriptenWebGLGetVertexAttrib(index,pname,params,type){if(!params){GL.recordError(1281);return}if(GL.currentContext.clientBuffers[index].enabled){err("glGetVertexAttrib*v on client-side array: not supported, bad data returned")}var data=GLctx.getVertexAttrib(index,pname);if(pname==34975){HEAP32[params>>2]=data&&data["name"]}else if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>2]=data;break;case 2:HEAPF32[params>>2]=data;break;case 5:HEAP32[params>>2]=Math.fround(data);break}}else{for(var i=0;i>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break;case 5:HEAP32[params+i*4>>2]=Math.fround(data[i]);break}}}}function _emscripten_glGetVertexAttribfv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,2)}function _emscripten_glGetVertexAttribiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,5)}function _emscripten_glHint(x0,x1){GLctx["hint"](x0,x1)}function _emscripten_glIsBuffer(buffer){var b=GL.buffers[buffer];if(!b)return 0;return GLctx.isBuffer(b)}function _emscripten_glIsEnabled(x0){return GLctx["isEnabled"](x0)}function _emscripten_glIsFramebuffer(framebuffer){var fb=GL.framebuffers[framebuffer];if(!fb)return 0;return GLctx.isFramebuffer(fb)}function _emscripten_glIsProgram(program){program=GL.programs[program];if(!program)return 0;return GLctx.isProgram(program)}function _emscripten_glIsQueryEXT(id){var query=GL.timerQueriesEXT[id];if(!query)return 0;return GLctx.disjointTimerQueryExt["isQueryEXT"](query)}function _emscripten_glIsRenderbuffer(renderbuffer){var rb=GL.renderbuffers[renderbuffer];if(!rb)return 0;return GLctx.isRenderbuffer(rb)}function _emscripten_glIsShader(shader){var s=GL.shaders[shader];if(!s)return 0;return GLctx.isShader(s)}function _emscripten_glIsTexture(id){var texture=GL.textures[id];if(!texture)return 0;return GLctx.isTexture(texture)}function _emscripten_glIsVertexArrayOES(array){var vao=GL.vaos[array];if(!vao)return 0;return GLctx["isVertexArray"](vao)}function _emscripten_glLineWidth(x0){GLctx["lineWidth"](x0)}function _emscripten_glLinkProgram(program){GLctx.linkProgram(GL.programs[program]);GL.populateUniformTable(program)}function _emscripten_glPixelStorei(pname,param){if(pname==3317){GL.unpackAlignment=param}GLctx.pixelStorei(pname,param)}function _emscripten_glPolygonOffset(x0,x1){GLctx["polygonOffset"](x0,x1)}function _emscripten_glQueryCounterEXT(id,target){GLctx.disjointTimerQueryExt["queryCounterEXT"](GL.timerQueriesEXT[id],target)}function computeUnpackAlignedImageSize(width,height,sizePerPixel,alignment){function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=width*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,alignment);return height*alignedRowSize}function __colorChannelsInGlTextureFormat(format){var colorChannels={5:3,6:4,8:2,29502:3,29504:4};return colorChannels[format-6402]||1}function heapObjectForWebGLType(type){type-=5120;if(type==1)return HEAPU8;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922)return HEAPU32;return HEAPU16}function heapAccessShiftForWebGLHeap(heap){return 31-Math.clz32(heap.BYTES_PER_ELEMENT)}function emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat){var heap=heapObjectForWebGLType(type);var shift=heapAccessShiftForWebGLHeap(heap);var byteSize=1<>shift,pixels+bytes>>shift)}function _emscripten_glReadPixels(x,y,width,height,format,type,pixels){var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}function _emscripten_glReleaseShaderCompiler(){}function _emscripten_glRenderbufferStorage(x0,x1,x2,x3){GLctx["renderbufferStorage"](x0,x1,x2,x3)}function _emscripten_glSampleCoverage(value,invert){GLctx.sampleCoverage(value,!!invert)}function _emscripten_glScissor(x0,x1,x2,x3){GLctx["scissor"](x0,x1,x2,x3)}function _emscripten_glShaderBinary(){GL.recordError(1280)}function _emscripten_glShaderSource(shader,count,string,length){var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _emscripten_glStencilFunc(x0,x1,x2){GLctx["stencilFunc"](x0,x1,x2)}function _emscripten_glStencilFuncSeparate(x0,x1,x2,x3){GLctx["stencilFuncSeparate"](x0,x1,x2,x3)}function _emscripten_glStencilMask(x0){GLctx["stencilMask"](x0)}function _emscripten_glStencilMaskSeparate(x0,x1){GLctx["stencilMaskSeparate"](x0,x1)}function _emscripten_glStencilOp(x0,x1,x2){GLctx["stencilOp"](x0,x1,x2)}function _emscripten_glStencilOpSeparate(x0,x1,x2,x3){GLctx["stencilOpSeparate"](x0,x1,x2,x3)}function _emscripten_glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _emscripten_glTexParameterf(x0,x1,x2){GLctx["texParameterf"](x0,x1,x2)}function _emscripten_glTexParameterfv(target,pname,params){var param=HEAPF32[params>>2];GLctx.texParameterf(target,pname,param)}function _emscripten_glTexParameteri(x0,x1,x2){GLctx["texParameteri"](x0,x1,x2)}function _emscripten_glTexParameteriv(target,pname,params){var param=HEAP32[params>>2];GLctx.texParameteri(target,pname,param)}function _emscripten_glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _emscripten_glUniform1f(location,v0){GLctx.uniform1f(GL.uniforms[location],v0)}var miniTempWebGLFloatBuffers=[];function _emscripten_glUniform1fv(location,count,value){if(count<=288){var view=miniTempWebGLFloatBuffers[count-1];for(var i=0;i>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1fv(GL.uniforms[location],view)}function _emscripten_glUniform1i(location,v0){GLctx.uniform1i(GL.uniforms[location],v0)}var __miniTempWebGLIntBuffers=[];function _emscripten_glUniform1iv(location,count,value){if(count<=288){var view=__miniTempWebGLIntBuffers[count-1];for(var i=0;i>2]}}else{var view=HEAP32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1iv(GL.uniforms[location],view)}function _emscripten_glUniform2f(location,v0,v1){GLctx.uniform2f(GL.uniforms[location],v0,v1)}function _emscripten_glUniform2fv(location,count,value){if(count<=144){var view=miniTempWebGLFloatBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2fv(GL.uniforms[location],view)}function _emscripten_glUniform2i(location,v0,v1){GLctx.uniform2i(GL.uniforms[location],v0,v1)}function _emscripten_glUniform2iv(location,count,value){if(count<=144){var view=__miniTempWebGLIntBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2iv(GL.uniforms[location],view)}function _emscripten_glUniform3f(location,v0,v1,v2){GLctx.uniform3f(GL.uniforms[location],v0,v1,v2)}function _emscripten_glUniform3fv(location,count,value){if(count<=96){var view=miniTempWebGLFloatBuffers[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3fv(GL.uniforms[location],view)}function _emscripten_glUniform3i(location,v0,v1,v2){GLctx.uniform3i(GL.uniforms[location],v0,v1,v2)}function _emscripten_glUniform3iv(location,count,value){if(count<=96){var view=__miniTempWebGLIntBuffers[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3iv(GL.uniforms[location],view)}function _emscripten_glUniform4f(location,v0,v1,v2,v3){GLctx.uniform4f(GL.uniforms[location],v0,v1,v2,v3)}function _emscripten_glUniform4fv(location,count,value){if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<4*count;i+=4){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4fv(GL.uniforms[location],view)}function _emscripten_glUniform4i(location,v0,v1,v2,v3){GLctx.uniform4i(GL.uniforms[location],v0,v1,v2,v3)}function _emscripten_glUniform4iv(location,count,value){if(count<=72){var view=__miniTempWebGLIntBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2];view[i+3]=HEAP32[value+(4*i+12)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4iv(GL.uniforms[location],view)}function _emscripten_glUniformMatrix2fv(location,count,transpose,value){if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniformMatrix2fv(GL.uniforms[location],!!transpose,view)}function _emscripten_glUniformMatrix3fv(location,count,transpose,value){if(count<=32){var view=miniTempWebGLFloatBuffers[9*count-1];for(var i=0;i<9*count;i+=9){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2];view[i+4]=HEAPF32[value+(4*i+16)>>2];view[i+5]=HEAPF32[value+(4*i+20)>>2];view[i+6]=HEAPF32[value+(4*i+24)>>2];view[i+7]=HEAPF32[value+(4*i+28)>>2];view[i+8]=HEAPF32[value+(4*i+32)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*36>>2)}GLctx.uniformMatrix3fv(GL.uniforms[location],!!transpose,view)}function _emscripten_glUniformMatrix4fv(location,count,transpose,value){if(count<=18){var view=miniTempWebGLFloatBuffers[16*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<16*count;i+=16){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3];view[i+4]=heap[dst+4];view[i+5]=heap[dst+5];view[i+6]=heap[dst+6];view[i+7]=heap[dst+7];view[i+8]=heap[dst+8];view[i+9]=heap[dst+9];view[i+10]=heap[dst+10];view[i+11]=heap[dst+11];view[i+12]=heap[dst+12];view[i+13]=heap[dst+13];view[i+14]=heap[dst+14];view[i+15]=heap[dst+15]}}else{var view=HEAPF32.subarray(value>>2,value+count*64>>2)}GLctx.uniformMatrix4fv(GL.uniforms[location],!!transpose,view)}function _emscripten_glUseProgram(program){GLctx.useProgram(GL.programs[program])}function _emscripten_glValidateProgram(program){GLctx.validateProgram(GL.programs[program])}function _emscripten_glVertexAttrib1f(x0,x1){GLctx["vertexAttrib1f"](x0,x1)}function _emscripten_glVertexAttrib1fv(index,v){GLctx.vertexAttrib1f(index,HEAPF32[v>>2])}function _emscripten_glVertexAttrib2f(x0,x1,x2){GLctx["vertexAttrib2f"](x0,x1,x2)}function _emscripten_glVertexAttrib2fv(index,v){GLctx.vertexAttrib2f(index,HEAPF32[v>>2],HEAPF32[v+4>>2])}function _emscripten_glVertexAttrib3f(x0,x1,x2,x3){GLctx["vertexAttrib3f"](x0,x1,x2,x3)}function _emscripten_glVertexAttrib3fv(index,v){GLctx.vertexAttrib3f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2])}function _emscripten_glVertexAttrib4f(x0,x1,x2,x3,x4){GLctx["vertexAttrib4f"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttrib4fv(index,v){GLctx.vertexAttrib4f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2],HEAPF32[v+12>>2])}function _emscripten_glVertexAttribDivisorANGLE(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribPointer(index,size,type,normalized,stride,ptr){var cb=GL.currentContext.clientBuffers[index];if(!GLctx.currentArrayBufferBinding){cb.size=size;cb.type=type;cb.normalized=normalized;cb.stride=stride;cb.ptr=ptr;cb.clientside=true;cb.vertexAttribPointerAdaptor=function(index,size,type,normalized,stride,ptr){this.vertexAttribPointer(index,size,type,normalized,stride,ptr)};return}cb.clientside=false;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _emscripten_glViewport(x0,x1,x2,x3){GLctx["viewport"](x0,x1,x2,x3)}function _emscripten_has_asyncify(){return 0}function _longjmp(env,value){_setThrew(env,value||1);throw"longjmp"}function _emscripten_longjmp(env,value){_longjmp(env,value)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function __emscripten_do_request_fullscreen(target,strategy){if(!JSEvents.fullscreenEnabled())return-1;target=findEventTarget(target);if(!target)return-4;if(!target.requestFullscreen&&!target.webkitRequestFullscreen){return-3}var canPerformRequests=JSEvents.canPerformEventHandlerRequests();if(!canPerformRequests){if(strategy.deferUntilInEventHandler){JSEvents.deferCall(_JSEvents_requestFullscreen,1,[target,strategy]);return 1}else{return-2}}return _JSEvents_requestFullscreen(target,strategy)}function _emscripten_request_fullscreen_strategy(target,deferUntilInEventHandler,fullscreenStrategy){var strategy={scaleMode:HEAP32[fullscreenStrategy>>2],canvasResolutionScaleMode:HEAP32[fullscreenStrategy+4>>2],filteringMode:HEAP32[fullscreenStrategy+8>>2],deferUntilInEventHandler:deferUntilInEventHandler,canvasResizedCallback:HEAP32[fullscreenStrategy+12>>2],canvasResizedCallbackUserData:HEAP32[fullscreenStrategy+16>>2]};return __emscripten_do_request_fullscreen(target,strategy)}function _emscripten_request_pointerlock(target,deferUntilInEventHandler){target=findEventTarget(target);if(!target)return-4;if(!target.requestPointerLock&&!target.msRequestPointerLock){return-1}var canPerformRequests=JSEvents.canPerformEventHandlerRequests();if(!canPerformRequests){if(deferUntilInEventHandler){JSEvents.deferCall(__requestPointerLock,2,[target]);return 1}else{return-2}}return __requestPointerLock(target)}function _emscripten_get_heap_size(){return HEAPU8.length}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){requestedSize=requestedSize>>>0;var oldSize=_emscripten_get_heap_size();var maxHeapSize=2147483648;if(requestedSize>maxHeapSize){return false}var minHeapSize=16777216;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(minHeapSize,requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}function _emscripten_run_script(ptr){eval(UTF8ToString(ptr))}function _emscripten_sample_gamepad_data(){return(JSEvents.lastGamepadState=navigator.getGamepads?navigator.getGamepads():navigator.webkitGetGamepads?navigator.webkitGetGamepads():null)?0:-1}function __registerBeforeUnloadEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString){var beforeUnloadEventHandlerFunc=function(ev){var e=ev||event;var confirmationMessage=wasmTable.get(callbackfunc)(eventTypeId,0,userData);if(confirmationMessage){confirmationMessage=UTF8ToString(confirmationMessage)}if(confirmationMessage){e.preventDefault();e.returnValue=confirmationMessage;return confirmationMessage}};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:beforeUnloadEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_beforeunload_callback_on_thread(userData,callbackfunc,targetThread){if(typeof onbeforeunload==="undefined")return-1;if(targetThread!==1)return-5;__registerBeforeUnloadEventCallback(2,userData,true,callbackfunc,28,"beforeunload");return 0}function __registerFocusEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.focusEvent)JSEvents.focusEvent=_malloc(256);var focusEventHandlerFunc=function(ev){var e=ev||event;var nodeName=JSEvents.getNodeNameForTarget(e.target);var id=e.target.id?e.target.id:"";var focusEvent=JSEvents.focusEvent;stringToUTF8(nodeName,focusEvent+0,128);stringToUTF8(id,focusEvent+128,128);if(wasmTable.get(callbackfunc)(eventTypeId,focusEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:focusEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_blur_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerFocusEventCallback(target,userData,useCapture,callbackfunc,12,"blur",targetThread);return 0}function _emscripten_set_element_css_size(target,width,height){target=findEventTarget(target);if(!target)return-4;target.style.width=width+"px";target.style.height=height+"px";return 0}function _emscripten_set_focus_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerFocusEventCallback(target,userData,useCapture,callbackfunc,13,"focus",targetThread);return 0}function __fillFullscreenChangeEventData(eventStruct){var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;var isFullscreen=!!fullscreenElement;HEAP32[eventStruct>>2]=isFullscreen;HEAP32[eventStruct+4>>2]=JSEvents.fullscreenEnabled();var reportedElement=isFullscreen?fullscreenElement:JSEvents.previousFullscreenElement;var nodeName=JSEvents.getNodeNameForTarget(reportedElement);var id=reportedElement&&reportedElement.id?reportedElement.id:"";stringToUTF8(nodeName,eventStruct+8,128);stringToUTF8(id,eventStruct+136,128);HEAP32[eventStruct+264>>2]=reportedElement?reportedElement.clientWidth:0;HEAP32[eventStruct+268>>2]=reportedElement?reportedElement.clientHeight:0;HEAP32[eventStruct+272>>2]=screen.width;HEAP32[eventStruct+276>>2]=screen.height;if(isFullscreen){JSEvents.previousFullscreenElement=fullscreenElement}}function __registerFullscreenChangeEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.fullscreenChangeEvent)JSEvents.fullscreenChangeEvent=_malloc(280);var fullscreenChangeEventhandlerFunc=function(ev){var e=ev||event;var fullscreenChangeEvent=JSEvents.fullscreenChangeEvent;__fillFullscreenChangeEventData(fullscreenChangeEvent);if(wasmTable.get(callbackfunc)(eventTypeId,fullscreenChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:fullscreenChangeEventhandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_fullscreenchange_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){if(!JSEvents.fullscreenEnabled())return-1;target=findEventTarget(target);if(!target)return-4;__registerFullscreenChangeEventCallback(target,userData,useCapture,callbackfunc,19,"fullscreenchange",targetThread);__registerFullscreenChangeEventCallback(target,userData,useCapture,callbackfunc,19,"webkitfullscreenchange",targetThread);return 0}function __registerGamepadEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.gamepadEvent)JSEvents.gamepadEvent=_malloc(1432);var gamepadEventHandlerFunc=function(ev){var e=ev||event;var gamepadEvent=JSEvents.gamepadEvent;__fillGamepadEventData(gamepadEvent,e["gamepad"]);if(wasmTable.get(callbackfunc)(eventTypeId,gamepadEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:gamepadEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_gamepadconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){if(!navigator.getGamepads&&!navigator.webkitGetGamepads)return-1;__registerGamepadEventCallback(2,userData,useCapture,callbackfunc,26,"gamepadconnected",targetThread);return 0}function _emscripten_set_gamepaddisconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){if(!navigator.getGamepads&&!navigator.webkitGetGamepads)return-1;__registerGamepadEventCallback(2,userData,useCapture,callbackfunc,27,"gamepaddisconnected",targetThread);return 0}function __registerKeyEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.keyEvent)JSEvents.keyEvent=_malloc(164);var keyEventHandlerFunc=function(e){var keyEventData=JSEvents.keyEvent;var idx=keyEventData>>2;HEAP32[idx+0]=e.location;HEAP32[idx+1]=e.ctrlKey;HEAP32[idx+2]=e.shiftKey;HEAP32[idx+3]=e.altKey;HEAP32[idx+4]=e.metaKey;HEAP32[idx+5]=e.repeat;HEAP32[idx+6]=e.charCode;HEAP32[idx+7]=e.keyCode;HEAP32[idx+8]=e.which;stringToUTF8(e.key||"",keyEventData+36,32);stringToUTF8(e.code||"",keyEventData+68,32);stringToUTF8(e.char||"",keyEventData+100,32);stringToUTF8(e.locale||"",keyEventData+132,32);if(wasmTable.get(callbackfunc)(eventTypeId,keyEventData,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:keyEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_keydown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerKeyEventCallback(target,userData,useCapture,callbackfunc,2,"keydown",targetThread);return 0}function _emscripten_set_keypress_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerKeyEventCallback(target,userData,useCapture,callbackfunc,1,"keypress",targetThread);return 0}function _emscripten_set_keyup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerKeyEventCallback(target,userData,useCapture,callbackfunc,3,"keyup",targetThread);return 0}function _emscripten_set_main_loop_arg(func,arg,fps,simulateInfiniteLoop){var browserIterationFunc=function(){wasmTable.get(func)(arg)};setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop,arg)}function __fillMouseEventData(eventStruct,e,target){var idx=eventStruct>>2;HEAP32[idx+0]=e.screenX;HEAP32[idx+1]=e.screenY;HEAP32[idx+2]=e.clientX;HEAP32[idx+3]=e.clientY;HEAP32[idx+4]=e.ctrlKey;HEAP32[idx+5]=e.shiftKey;HEAP32[idx+6]=e.altKey;HEAP32[idx+7]=e.metaKey;HEAP16[idx*2+16]=e.button;HEAP16[idx*2+17]=e.buttons;HEAP32[idx+9]=e["movementX"];HEAP32[idx+10]=e["movementY"];var rect=__getBoundingClientRect(target);HEAP32[idx+11]=e.clientX-rect.left;HEAP32[idx+12]=e.clientY-rect.top}function __registerMouseEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.mouseEvent)JSEvents.mouseEvent=_malloc(64);target=findEventTarget(target);var mouseEventHandlerFunc=function(ev){var e=ev||event;__fillMouseEventData(JSEvents.mouseEvent,e,target);if(wasmTable.get(callbackfunc)(eventTypeId,JSEvents.mouseEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString!="mousemove"&&eventTypeString!="mouseenter"&&eventTypeString!="mouseleave",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:mouseEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_mousedown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,5,"mousedown",targetThread);return 0}function _emscripten_set_mouseenter_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,33,"mouseenter",targetThread);return 0}function _emscripten_set_mouseleave_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,34,"mouseleave",targetThread);return 0}function _emscripten_set_mousemove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,8,"mousemove",targetThread);return 0}function _emscripten_set_mouseup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerMouseEventCallback(target,userData,useCapture,callbackfunc,6,"mouseup",targetThread);return 0}function __fillPointerlockChangeEventData(eventStruct){var pointerLockElement=document.pointerLockElement||document.mozPointerLockElement||document.webkitPointerLockElement||document.msPointerLockElement;var isPointerlocked=!!pointerLockElement;HEAP32[eventStruct>>2]=isPointerlocked;var nodeName=JSEvents.getNodeNameForTarget(pointerLockElement);var id=pointerLockElement&&pointerLockElement.id?pointerLockElement.id:"";stringToUTF8(nodeName,eventStruct+4,128);stringToUTF8(id,eventStruct+132,128)}function __registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.pointerlockChangeEvent)JSEvents.pointerlockChangeEvent=_malloc(260);var pointerlockChangeEventHandlerFunc=function(ev){var e=ev||event;var pointerlockChangeEvent=JSEvents.pointerlockChangeEvent;__fillPointerlockChangeEventData(pointerlockChangeEvent);if(wasmTable.get(callbackfunc)(eventTypeId,pointerlockChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:pointerlockChangeEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_pointerlockchange_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){if(!document||!document.body||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}target=findEventTarget(target);if(!target)return-4;__registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"pointerlockchange",targetThread);__registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"mozpointerlockchange",targetThread);__registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"webkitpointerlockchange",targetThread);__registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"mspointerlockchange",targetThread);return 0}function __registerUiEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.uiEvent)JSEvents.uiEvent=_malloc(36);target=findEventTarget(target);var uiEventHandlerFunc=function(ev){var e=ev||event;if(e.target!=target){return}var uiEvent=JSEvents.uiEvent;var b=document.body;HEAP32[uiEvent>>2]=e.detail;HEAP32[uiEvent+4>>2]=b.clientWidth;HEAP32[uiEvent+8>>2]=b.clientHeight;HEAP32[uiEvent+12>>2]=innerWidth;HEAP32[uiEvent+16>>2]=innerHeight;HEAP32[uiEvent+20>>2]=outerWidth;HEAP32[uiEvent+24>>2]=outerHeight;HEAP32[uiEvent+28>>2]=pageXOffset;HEAP32[uiEvent+32>>2]=pageYOffset;if(wasmTable.get(callbackfunc)(eventTypeId,uiEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:uiEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_resize_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerUiEventCallback(target,userData,useCapture,callbackfunc,10,"resize",targetThread);return 0}function __registerTouchEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.touchEvent)JSEvents.touchEvent=_malloc(1684);target=findEventTarget(target);var touchEventHandlerFunc=function(e){var touches={};var et=e.touches;for(var i=0;i>2;HEAP32[idx+1]=e.ctrlKey;HEAP32[idx+2]=e.shiftKey;HEAP32[idx+3]=e.altKey;HEAP32[idx+4]=e.metaKey;idx+=5;var targetRect=__getBoundingClientRect(target);var numTouches=0;for(var i in touches){var t=touches[i];HEAP32[idx+0]=t.identifier;HEAP32[idx+1]=t.screenX;HEAP32[idx+2]=t.screenY;HEAP32[idx+3]=t.clientX;HEAP32[idx+4]=t.clientY;HEAP32[idx+5]=t.pageX;HEAP32[idx+6]=t.pageY;HEAP32[idx+7]=t.isChanged;HEAP32[idx+8]=t.onTarget;HEAP32[idx+9]=t.clientX-targetRect.left;HEAP32[idx+10]=t.clientY-targetRect.top;idx+=13;if(++numTouches>31){break}}HEAP32[touchEvent>>2]=numTouches;if(wasmTable.get(callbackfunc)(eventTypeId,touchEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString=="touchstart"||eventTypeString=="touchend",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:touchEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_touchcancel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,25,"touchcancel",targetThread);return 0}function _emscripten_set_touchend_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,23,"touchend",targetThread);return 0}function _emscripten_set_touchmove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,24,"touchmove",targetThread);return 0}function _emscripten_set_touchstart_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){__registerTouchEventCallback(target,userData,useCapture,callbackfunc,22,"touchstart",targetThread);return 0}function __fillVisibilityChangeEventData(eventStruct){var visibilityStates=["hidden","visible","prerender","unloaded"];var visibilityState=visibilityStates.indexOf(document.visibilityState);HEAP32[eventStruct>>2]=document.hidden;HEAP32[eventStruct+4>>2]=visibilityState}function __registerVisibilityChangeEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.visibilityChangeEvent)JSEvents.visibilityChangeEvent=_malloc(8);var visibilityChangeEventHandlerFunc=function(ev){var e=ev||event;var visibilityChangeEvent=JSEvents.visibilityChangeEvent;__fillVisibilityChangeEventData(visibilityChangeEvent);if(wasmTable.get(callbackfunc)(eventTypeId,visibilityChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:visibilityChangeEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_visibilitychange_callback_on_thread(userData,useCapture,callbackfunc,targetThread){if(!specialHTMLTargets[1]){return-4}__registerVisibilityChangeEventCallback(specialHTMLTargets[1],userData,useCapture,callbackfunc,21,"visibilitychange",targetThread);return 0}function __registerWheelEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.wheelEvent)JSEvents.wheelEvent=_malloc(96);var wheelHandlerFunc=function(ev){var e=ev||event;var wheelEvent=JSEvents.wheelEvent;__fillMouseEventData(wheelEvent,e,target);HEAPF64[wheelEvent+64>>3]=e["deltaX"];HEAPF64[wheelEvent+72>>3]=e["deltaY"];HEAPF64[wheelEvent+80>>3]=e["deltaZ"];HEAP32[wheelEvent+88>>2]=e["deltaMode"];if(wasmTable.get(callbackfunc)(eventTypeId,wheelEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:wheelHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_wheel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target=findEventTarget(target);if(typeof target.onwheel!=="undefined"){__registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"wheel",targetThread);return 0}else{return-1}}function _emscripten_sleep(){throw"Please compile your program with async support in order to use asynchronous operations like emscripten_sleep"}var ENV={};function getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator==="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function _exit(status){exit(status)}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4;HEAP8[pbuf>>0]=type;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_read(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doReadv(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var stream=SYSCALLS.getStreamFromFD(fd);var HIGH_OFFSET=4294967296;var offset=offset_high*HIGH_OFFSET+(offset_low>>>0);var DOUBLE_LIMIT=9007199254740992;if(offset<=-DOUBLE_LIMIT||offset>=DOUBLE_LIMIT){return-61}FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops&&stream.stream_ops.fsync){return-stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doWritev(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}var GAI_ERRNO_MESSAGES={};function _gai_strerror(val){var buflen=256;if(!_gai_strerror.buffer){_gai_strerror.buffer=_malloc(buflen);GAI_ERRNO_MESSAGES["0"]="Success";GAI_ERRNO_MESSAGES[""+-1]="Invalid value for 'ai_flags' field";GAI_ERRNO_MESSAGES[""+-2]="NAME or SERVICE is unknown";GAI_ERRNO_MESSAGES[""+-3]="Temporary failure in name resolution";GAI_ERRNO_MESSAGES[""+-4]="Non-recoverable failure in name res";GAI_ERRNO_MESSAGES[""+-6]="'ai_family' not supported";GAI_ERRNO_MESSAGES[""+-7]="'ai_socktype' not supported";GAI_ERRNO_MESSAGES[""+-8]="SERVICE not supported for 'ai_socktype'";GAI_ERRNO_MESSAGES[""+-10]="Memory allocation failure";GAI_ERRNO_MESSAGES[""+-11]="System error returned in 'errno'";GAI_ERRNO_MESSAGES[""+-12]="Argument buffer overflow"}var msg="Unknown error";if(val in GAI_ERRNO_MESSAGES){if(GAI_ERRNO_MESSAGES[val].length>buflen-1){msg="Message too long"}else{msg=GAI_ERRNO_MESSAGES[val]}}writeAsciiToMemory(msg,_gai_strerror.buffer);return _gai_strerror.buffer}function _getTempRet0(){return getTempRet0()|0}function _getaddrinfo(node,service,hint,out){var addr=0;var port=0;var flags=0;var family=0;var type=0;var proto=0;var ai;function allocaddrinfo(family,type,proto,canon,addr,port){var sa,salen,ai;var res;salen=family===10?28:16;addr=family===10?__inet_ntop6_raw(addr):__inet_ntop4_raw(addr);sa=_malloc(salen);res=__write_sockaddr(sa,family,addr,port);assert(!res.errno);ai=_malloc(32);HEAP32[ai+4>>2]=family;HEAP32[ai+8>>2]=type;HEAP32[ai+12>>2]=proto;HEAP32[ai+24>>2]=canon;HEAP32[ai+20>>2]=sa;if(family===10){HEAP32[ai+16>>2]=28}else{HEAP32[ai+16>>2]=16}HEAP32[ai+28>>2]=0;return ai}if(hint){flags=HEAP32[hint>>2];family=HEAP32[hint+4>>2];type=HEAP32[hint+8>>2];proto=HEAP32[hint+12>>2]}if(type&&!proto){proto=type===2?17:6}if(!type&&proto){type=proto===17?2:1}if(proto===0){proto=6}if(type===0){type=1}if(!node&&!service){return-2}if(flags&~(1|2|4|1024|8|16|32)){return-1}if(hint!==0&&HEAP32[hint>>2]&2&&!node){return-1}if(flags&32){return-2}if(type!==0&&type!==1&&type!==2){return-7}if(family!==0&&family!==2&&family!==10){return-6}if(service){service=UTF8ToString(service);port=parseInt(service,10);if(isNaN(port)){if(flags&1024){return-2}return-8}}if(!node){if(family===0){family=2}if((flags&1)===0){if(family===2){addr=_htonl(2130706433)}else{addr=[0,0,0,1]}}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAP32[out>>2]=ai;return 0}node=UTF8ToString(node);addr=__inet_pton4_raw(node);if(addr!==null){if(family===0||family===2){family=2}else if(family===10&&flags&8){addr=[0,0,_htonl(65535),addr];family=10}else{return-2}}else{addr=__inet_pton6_raw(node);if(addr!==null){if(family===0||family===10){family=10}else{return-2}}}if(addr!=null){ai=allocaddrinfo(family,type,proto,node,addr,port);HEAP32[out>>2]=ai;return 0}if(flags&4){return-2}node=DNS.lookup_name(node);addr=__inet_pton4_raw(node);if(family===0){family=2}else if(family===10){addr=[0,0,_htonl(65535),addr]}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAP32[out>>2]=ai;return 0}function _gethostbyname(name){name=UTF8ToString(name);var ret=_malloc(20);var nameBuf=_malloc(name.length+1);stringToUTF8(name,nameBuf,name.length+1);HEAP32[ret>>2]=nameBuf;var aliasesBuf=_malloc(4);HEAP32[aliasesBuf>>2]=0;HEAP32[ret+4>>2]=aliasesBuf;var afinet=2;HEAP32[ret+8>>2]=afinet;HEAP32[ret+12>>2]=4;var addrListBuf=_malloc(12);HEAP32[addrListBuf>>2]=addrListBuf+8;HEAP32[addrListBuf+4>>2]=0;HEAP32[addrListBuf+8>>2]=__inet_pton4_raw(DNS.lookup_name(name));HEAP32[ret+16>>2]=addrListBuf;return ret}function _gethostbyaddr(addr,addrlen,type){if(type!==2){setErrNo(5);return null}addr=HEAP32[addr>>2];var host=__inet_ntop4_raw(addr);var lookup=DNS.lookup_addr(host);if(lookup){host=lookup}var hostp=allocate(intArrayFromString(host),"i8",ALLOC_STACK);return _gethostbyname(hostp)}function _getnameinfo(sa,salen,node,nodelen,serv,servlen,flags){var info=__read_sockaddr(sa,salen);if(info.errno){return-6}var port=info.port;var addr=info.addr;var overflowed=false;if(node&&nodelen){var lookup;if(flags&1||!(lookup=DNS.lookup_addr(addr))){if(flags&8){return-2}}else{addr=lookup}var numBytesWrittenExclNull=stringToUTF8(addr,node,nodelen);if(numBytesWrittenExclNull+1>=nodelen){overflowed=true}}if(serv&&servlen){port=""+port;var numBytesWrittenExclNull=stringToUTF8(port,serv,servlen);if(numBytesWrittenExclNull+1>=servlen){overflowed=true}}if(overflowed){return-12}return 0}function _getpwuid(){throw"getpwuid: TODO"}function _gettimeofday(ptr){var now=Date.now();HEAP32[ptr>>2]=now/1e3|0;HEAP32[ptr+4>>2]=now%1e3*1e3|0;return 0}function _mktime(tmPtr){_tzset();var date=new Date(HEAP32[tmPtr+20>>2]+1900,HEAP32[tmPtr+16>>2],HEAP32[tmPtr+12>>2],HEAP32[tmPtr+8>>2],HEAP32[tmPtr+4>>2],HEAP32[tmPtr>>2],0);var dst=HEAP32[tmPtr+32>>2];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>2]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>2]=date.getDay();var yday=(date.getTime()-start.getTime())/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;return date.getTime()/1e3|0}function _usleep(useconds){var start=_emscripten_get_now();while(_emscripten_get_now()-start>2];var nanoseconds=HEAP32[rqtp+4>>2];if(nanoseconds<0||nanoseconds>999999999||seconds<0){setErrNo(28);return-1}if(rmtp!==0){HEAP32[rmtp>>2]=0;HEAP32[rmtp+4>>2]=0}return _usleep(seconds*1e6+nanoseconds/1e3)}function _pthread_mutexattr_init(){}function _pthread_mutexattr_settype(){}function _setTempRet0($i){setTempRet0($i|0)}function _sigaction(signum,act,oldact){return 0}var __sigalrm_handler=0;function _signal(sig,func){if(sig==14){__sigalrm_handler=func}else{}return 0}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"},"%V":function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}function _sysconf(name){switch(name){case 30:return 16384;case 85:var maxHeapSize=2147483648;return maxHeapSize/16384;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:case 79:return 200809;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1e3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:{if(typeof navigator==="object")return navigator["hardwareConcurrency"]||1;return 1}}setErrNo(28);return-1}function _system(command){if(ENVIRONMENT_IS_NODE){if(!command)return 1;var cmdstr=UTF8ToString(command);if(!cmdstr.length)return 0;var cp=require("child_process");var ret=cp.spawnSync(cmdstr,[],{shell:true,stdio:"inherit"});var _W_EXITCODE=function(ret,sig){return ret<<8|sig};if(ret.status===null){var signalToNumber=function(sig){switch(sig){case"SIGHUP":return 1;case"SIGINT":return 2;case"SIGQUIT":return 3;case"SIGFPE":return 8;case"SIGKILL":return 9;case"SIGALRM":return 14;case"SIGTERM":return 15}return 2};return _W_EXITCODE(0,signalToNumber(ret.signal))}return _W_EXITCODE(ret.status,0)}if(!command)return 0;setErrNo(6);return-1}function _time(ptr){var ret=Date.now()/1e3|0;if(ptr){HEAP32[ptr>>2]=ret}return ret}var readAsmConstArgsArray=[];function readAsmConstArgs(sigPtr,buf){readAsmConstArgsArray.length=0;var ch;buf>>=2;while(ch=HEAPU8[sigPtr++]){var double=ch<105;if(double&&buf&1)buf++;readAsmConstArgsArray.push(double?HEAPF64[buf++>>1]:HEAP32[buf]);++buf}return readAsmConstArgsArray}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.staticInit();Module["FS_createFolder"]=FS.createFolder;Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createLink"]=FS.createLink;Module["FS_createDevice"]=FS.createDevice;Module["FS_unlink"]=FS.unlink;Module["requestFullscreen"]=function Module_requestFullscreen(lockPointer,resizeCanvas){Browser.requestFullscreen(lockPointer,resizeCanvas)};Module["requestAnimationFrame"]=function Module_requestAnimationFrame(func){Browser.requestAnimationFrame(func)};Module["setCanvasSize"]=function Module_setCanvasSize(width,height,noUpdates){Browser.setCanvasSize(width,height,noUpdates)};Module["pauseMainLoop"]=function Module_pauseMainLoop(){Browser.mainLoop.pause()};Module["resumeMainLoop"]=function Module_resumeMainLoop(){Browser.mainLoop.resume()};Module["getUserMedia"]=function Module_getUserMedia(){Browser.getUserMedia()};Module["createContext"]=function Module_createContext(canvas,useWebGL,setInModule,webGLContextAttributes){return Browser.createContext(canvas,useWebGL,setInModule,webGLContextAttributes)};var GLctx;for(var i=0;i<32;++i)tempFixedLengthArray.push(new Array(i));var miniTempWebGLFloatBuffersStorage=new Float32Array(288);for(var i=0;i<288;++i){miniTempWebGLFloatBuffers[i]=miniTempWebGLFloatBuffersStorage.subarray(0,i+1)}var __miniTempWebGLIntBuffersStorage=new Int32Array(288);for(var i=0;i<288;++i){__miniTempWebGLIntBuffers[i]=__miniTempWebGLIntBuffersStorage.subarray(0,i+1)}var ASSERTIONS=false;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var asmLibraryArg={"__clock_gettime":___clock_gettime,"__cxa_allocate_exception":___cxa_allocate_exception,"__cxa_atexit":___cxa_atexit,"__cxa_begin_catch":___cxa_begin_catch,"__cxa_end_catch":___cxa_end_catch,"__cxa_find_matching_catch_2":___cxa_find_matching_catch_2,"__cxa_find_matching_catch_3":___cxa_find_matching_catch_3,"__cxa_free_exception":___cxa_free_exception,"__cxa_rethrow":___cxa_rethrow,"__cxa_throw":___cxa_throw,"__cxa_uncaught_exceptions":___cxa_uncaught_exceptions,"__gmtime_r":___gmtime_r,"__localtime_r":___localtime_r,"__map_file":___map_file,"__resumeException":___resumeException,"__sys__newselect":___sys__newselect,"__sys_access":___sys_access,"__sys_dup2":___sys_dup2,"__sys_dup3":___sys_dup3,"__sys_fcntl64":___sys_fcntl64,"__sys_fstat64":___sys_fstat64,"__sys_getcwd":___sys_getcwd,"__sys_getdents64":___sys_getdents64,"__sys_getpid":___sys_getpid,"__sys_getuid32":___sys_getuid32,"__sys_ioctl":___sys_ioctl,"__sys_lstat64":___sys_lstat64,"__sys_mkdir":___sys_mkdir,"__sys_munmap":___sys_munmap,"__sys_open":___sys_open,"__sys_poll":___sys_poll,"__sys_read":___sys_read,"__sys_readlink":___sys_readlink,"__sys_rename":___sys_rename,"__sys_rmdir":___sys_rmdir,"__sys_socketcall":___sys_socketcall,"__sys_stat64":___sys_stat64,"__sys_uname":___sys_uname,"__sys_unlink":___sys_unlink,"abort":_abort,"alBufferData":_alBufferData,"alDeleteBuffers":_alDeleteBuffers,"alDeleteSources":_alDeleteSources,"alDistanceModel":_alDistanceModel,"alDopplerFactor":_alDopplerFactor,"alGenBuffers":_alGenBuffers,"alGenSources":_alGenSources,"alGetBufferi":_alGetBufferi,"alGetError":_alGetError,"alGetFloat":_alGetFloat,"alGetListenerf":_alGetListenerf,"alGetListenerfv":_alGetListenerfv,"alGetSourcef":_alGetSourcef,"alGetSourcefv":_alGetSourcefv,"alGetSourcei":_alGetSourcei,"alListenerf":_alListenerf,"alListenerfv":_alListenerfv,"alSourcePause":_alSourcePause,"alSourcePausev":_alSourcePausev,"alSourcePlay":_alSourcePlay,"alSourcePlayv":_alSourcePlayv,"alSourceQueueBuffers":_alSourceQueueBuffers,"alSourceStop":_alSourceStop,"alSourceStopv":_alSourceStopv,"alSourceUnqueueBuffers":_alSourceUnqueueBuffers,"alSourcef":_alSourcef,"alSourcefv":_alSourcefv,"alSourcei":_alSourcei,"alcCaptureCloseDevice":_alcCaptureCloseDevice,"alcCaptureOpenDevice":_alcCaptureOpenDevice,"alcCaptureSamples":_alcCaptureSamples,"alcCaptureStart":_alcCaptureStart,"alcCaptureStop":_alcCaptureStop,"alcCloseDevice":_alcCloseDevice,"alcCreateContext":_alcCreateContext,"alcDestroyContext":_alcDestroyContext,"alcGetCurrentContext":_alcGetCurrentContext,"alcGetError":_alcGetError,"alcGetIntegerv":_alcGetIntegerv,"alcGetString":_alcGetString,"alcMakeContextCurrent":_alcMakeContextCurrent,"alcOpenDevice":_alcOpenDevice,"atexit":_atexit,"clock":_clock,"clock_gettime":_clock_gettime,"difftime":_difftime,"dlclose":_dlclose,"dlerror":_dlerror,"dlopen":_dlopen,"dlsym":_dlsym,"eglBindAPI":_eglBindAPI,"eglChooseConfig":_eglChooseConfig,"eglCreateContext":_eglCreateContext,"eglCreateWindowSurface":_eglCreateWindowSurface,"eglDestroyContext":_eglDestroyContext,"eglDestroySurface":_eglDestroySurface,"eglGetConfigAttrib":_eglGetConfigAttrib,"eglGetDisplay":_eglGetDisplay,"eglGetError":_eglGetError,"eglGetProcAddress":_eglGetProcAddress,"eglInitialize":_eglInitialize,"eglMakeCurrent":_eglMakeCurrent,"eglQueryString":_eglQueryString,"eglSwapBuffers":_eglSwapBuffers,"eglSwapInterval":_eglSwapInterval,"eglTerminate":_eglTerminate,"eglWaitGL":_eglWaitGL,"eglWaitNative":_eglWaitNative,"emscripten_asm_const_int":_emscripten_asm_const_int,"emscripten_cancel_main_loop":_emscripten_cancel_main_loop,"emscripten_exit_fullscreen":_emscripten_exit_fullscreen,"emscripten_exit_pointerlock":_emscripten_exit_pointerlock,"emscripten_get_battery_status":_emscripten_get_battery_status,"emscripten_get_device_pixel_ratio":_emscripten_get_device_pixel_ratio,"emscripten_get_element_css_size":_emscripten_get_element_css_size,"emscripten_get_gamepad_status":_emscripten_get_gamepad_status,"emscripten_get_now":_emscripten_get_now,"emscripten_get_num_gamepads":_emscripten_get_num_gamepads,"emscripten_get_sbrk_ptr":_emscripten_get_sbrk_ptr,"emscripten_glActiveTexture":_emscripten_glActiveTexture,"emscripten_glAttachShader":_emscripten_glAttachShader,"emscripten_glBeginQueryEXT":_emscripten_glBeginQueryEXT,"emscripten_glBindAttribLocation":_emscripten_glBindAttribLocation,"emscripten_glBindBuffer":_emscripten_glBindBuffer,"emscripten_glBindFramebuffer":_emscripten_glBindFramebuffer,"emscripten_glBindRenderbuffer":_emscripten_glBindRenderbuffer,"emscripten_glBindTexture":_emscripten_glBindTexture,"emscripten_glBindVertexArrayOES":_emscripten_glBindVertexArrayOES,"emscripten_glBlendColor":_emscripten_glBlendColor,"emscripten_glBlendEquation":_emscripten_glBlendEquation,"emscripten_glBlendEquationSeparate":_emscripten_glBlendEquationSeparate,"emscripten_glBlendFunc":_emscripten_glBlendFunc,"emscripten_glBlendFuncSeparate":_emscripten_glBlendFuncSeparate,"emscripten_glBufferData":_emscripten_glBufferData,"emscripten_glBufferSubData":_emscripten_glBufferSubData,"emscripten_glCheckFramebufferStatus":_emscripten_glCheckFramebufferStatus,"emscripten_glClear":_emscripten_glClear,"emscripten_glClearColor":_emscripten_glClearColor,"emscripten_glClearDepthf":_emscripten_glClearDepthf,"emscripten_glClearStencil":_emscripten_glClearStencil,"emscripten_glColorMask":_emscripten_glColorMask,"emscripten_glCompileShader":_emscripten_glCompileShader,"emscripten_glCompressedTexImage2D":_emscripten_glCompressedTexImage2D,"emscripten_glCompressedTexSubImage2D":_emscripten_glCompressedTexSubImage2D,"emscripten_glCopyTexImage2D":_emscripten_glCopyTexImage2D,"emscripten_glCopyTexSubImage2D":_emscripten_glCopyTexSubImage2D,"emscripten_glCreateProgram":_emscripten_glCreateProgram,"emscripten_glCreateShader":_emscripten_glCreateShader,"emscripten_glCullFace":_emscripten_glCullFace,"emscripten_glDeleteBuffers":_emscripten_glDeleteBuffers,"emscripten_glDeleteFramebuffers":_emscripten_glDeleteFramebuffers,"emscripten_glDeleteProgram":_emscripten_glDeleteProgram,"emscripten_glDeleteQueriesEXT":_emscripten_glDeleteQueriesEXT,"emscripten_glDeleteRenderbuffers":_emscripten_glDeleteRenderbuffers,"emscripten_glDeleteShader":_emscripten_glDeleteShader,"emscripten_glDeleteTextures":_emscripten_glDeleteTextures,"emscripten_glDeleteVertexArraysOES":_emscripten_glDeleteVertexArraysOES,"emscripten_glDepthFunc":_emscripten_glDepthFunc,"emscripten_glDepthMask":_emscripten_glDepthMask,"emscripten_glDepthRangef":_emscripten_glDepthRangef,"emscripten_glDetachShader":_emscripten_glDetachShader,"emscripten_glDisable":_emscripten_glDisable,"emscripten_glDisableVertexAttribArray":_emscripten_glDisableVertexAttribArray,"emscripten_glDrawArrays":_emscripten_glDrawArrays,"emscripten_glDrawArraysInstancedANGLE":_emscripten_glDrawArraysInstancedANGLE,"emscripten_glDrawBuffersWEBGL":_emscripten_glDrawBuffersWEBGL,"emscripten_glDrawElements":_emscripten_glDrawElements,"emscripten_glDrawElementsInstancedANGLE":_emscripten_glDrawElementsInstancedANGLE,"emscripten_glEnable":_emscripten_glEnable,"emscripten_glEnableVertexAttribArray":_emscripten_glEnableVertexAttribArray,"emscripten_glEndQueryEXT":_emscripten_glEndQueryEXT,"emscripten_glFinish":_emscripten_glFinish,"emscripten_glFlush":_emscripten_glFlush,"emscripten_glFramebufferRenderbuffer":_emscripten_glFramebufferRenderbuffer,"emscripten_glFramebufferTexture2D":_emscripten_glFramebufferTexture2D,"emscripten_glFrontFace":_emscripten_glFrontFace,"emscripten_glGenBuffers":_emscripten_glGenBuffers,"emscripten_glGenFramebuffers":_emscripten_glGenFramebuffers,"emscripten_glGenQueriesEXT":_emscripten_glGenQueriesEXT,"emscripten_glGenRenderbuffers":_emscripten_glGenRenderbuffers,"emscripten_glGenTextures":_emscripten_glGenTextures,"emscripten_glGenVertexArraysOES":_emscripten_glGenVertexArraysOES,"emscripten_glGenerateMipmap":_emscripten_glGenerateMipmap,"emscripten_glGetActiveAttrib":_emscripten_glGetActiveAttrib,"emscripten_glGetActiveUniform":_emscripten_glGetActiveUniform,"emscripten_glGetAttachedShaders":_emscripten_glGetAttachedShaders,"emscripten_glGetAttribLocation":_emscripten_glGetAttribLocation,"emscripten_glGetBooleanv":_emscripten_glGetBooleanv,"emscripten_glGetBufferParameteriv":_emscripten_glGetBufferParameteriv,"emscripten_glGetError":_emscripten_glGetError,"emscripten_glGetFloatv":_emscripten_glGetFloatv,"emscripten_glGetFramebufferAttachmentParameteriv":_emscripten_glGetFramebufferAttachmentParameteriv,"emscripten_glGetIntegerv":_emscripten_glGetIntegerv,"emscripten_glGetProgramInfoLog":_emscripten_glGetProgramInfoLog,"emscripten_glGetProgramiv":_emscripten_glGetProgramiv,"emscripten_glGetQueryObjecti64vEXT":_emscripten_glGetQueryObjecti64vEXT,"emscripten_glGetQueryObjectivEXT":_emscripten_glGetQueryObjectivEXT,"emscripten_glGetQueryObjectui64vEXT":_emscripten_glGetQueryObjectui64vEXT,"emscripten_glGetQueryObjectuivEXT":_emscripten_glGetQueryObjectuivEXT,"emscripten_glGetQueryivEXT":_emscripten_glGetQueryivEXT,"emscripten_glGetRenderbufferParameteriv":_emscripten_glGetRenderbufferParameteriv,"emscripten_glGetShaderInfoLog":_emscripten_glGetShaderInfoLog,"emscripten_glGetShaderPrecisionFormat":_emscripten_glGetShaderPrecisionFormat,"emscripten_glGetShaderSource":_emscripten_glGetShaderSource,"emscripten_glGetShaderiv":_emscripten_glGetShaderiv,"emscripten_glGetString":_emscripten_glGetString,"emscripten_glGetTexParameterfv":_emscripten_glGetTexParameterfv,"emscripten_glGetTexParameteriv":_emscripten_glGetTexParameteriv,"emscripten_glGetUniformLocation":_emscripten_glGetUniformLocation,"emscripten_glGetUniformfv":_emscripten_glGetUniformfv,"emscripten_glGetUniformiv":_emscripten_glGetUniformiv,"emscripten_glGetVertexAttribPointerv":_emscripten_glGetVertexAttribPointerv,"emscripten_glGetVertexAttribfv":_emscripten_glGetVertexAttribfv,"emscripten_glGetVertexAttribiv":_emscripten_glGetVertexAttribiv,"emscripten_glHint":_emscripten_glHint,"emscripten_glIsBuffer":_emscripten_glIsBuffer,"emscripten_glIsEnabled":_emscripten_glIsEnabled,"emscripten_glIsFramebuffer":_emscripten_glIsFramebuffer,"emscripten_glIsProgram":_emscripten_glIsProgram,"emscripten_glIsQueryEXT":_emscripten_glIsQueryEXT,"emscripten_glIsRenderbuffer":_emscripten_glIsRenderbuffer,"emscripten_glIsShader":_emscripten_glIsShader,"emscripten_glIsTexture":_emscripten_glIsTexture,"emscripten_glIsVertexArrayOES":_emscripten_glIsVertexArrayOES,"emscripten_glLineWidth":_emscripten_glLineWidth,"emscripten_glLinkProgram":_emscripten_glLinkProgram,"emscripten_glPixelStorei":_emscripten_glPixelStorei,"emscripten_glPolygonOffset":_emscripten_glPolygonOffset,"emscripten_glQueryCounterEXT":_emscripten_glQueryCounterEXT,"emscripten_glReadPixels":_emscripten_glReadPixels,"emscripten_glReleaseShaderCompiler":_emscripten_glReleaseShaderCompiler,"emscripten_glRenderbufferStorage":_emscripten_glRenderbufferStorage,"emscripten_glSampleCoverage":_emscripten_glSampleCoverage,"emscripten_glScissor":_emscripten_glScissor,"emscripten_glShaderBinary":_emscripten_glShaderBinary,"emscripten_glShaderSource":_emscripten_glShaderSource,"emscripten_glStencilFunc":_emscripten_glStencilFunc,"emscripten_glStencilFuncSeparate":_emscripten_glStencilFuncSeparate,"emscripten_glStencilMask":_emscripten_glStencilMask,"emscripten_glStencilMaskSeparate":_emscripten_glStencilMaskSeparate,"emscripten_glStencilOp":_emscripten_glStencilOp,"emscripten_glStencilOpSeparate":_emscripten_glStencilOpSeparate,"emscripten_glTexImage2D":_emscripten_glTexImage2D,"emscripten_glTexParameterf":_emscripten_glTexParameterf,"emscripten_glTexParameterfv":_emscripten_glTexParameterfv,"emscripten_glTexParameteri":_emscripten_glTexParameteri,"emscripten_glTexParameteriv":_emscripten_glTexParameteriv,"emscripten_glTexSubImage2D":_emscripten_glTexSubImage2D,"emscripten_glUniform1f":_emscripten_glUniform1f,"emscripten_glUniform1fv":_emscripten_glUniform1fv,"emscripten_glUniform1i":_emscripten_glUniform1i,"emscripten_glUniform1iv":_emscripten_glUniform1iv,"emscripten_glUniform2f":_emscripten_glUniform2f,"emscripten_glUniform2fv":_emscripten_glUniform2fv,"emscripten_glUniform2i":_emscripten_glUniform2i,"emscripten_glUniform2iv":_emscripten_glUniform2iv,"emscripten_glUniform3f":_emscripten_glUniform3f,"emscripten_glUniform3fv":_emscripten_glUniform3fv,"emscripten_glUniform3i":_emscripten_glUniform3i,"emscripten_glUniform3iv":_emscripten_glUniform3iv,"emscripten_glUniform4f":_emscripten_glUniform4f,"emscripten_glUniform4fv":_emscripten_glUniform4fv,"emscripten_glUniform4i":_emscripten_glUniform4i,"emscripten_glUniform4iv":_emscripten_glUniform4iv,"emscripten_glUniformMatrix2fv":_emscripten_glUniformMatrix2fv,"emscripten_glUniformMatrix3fv":_emscripten_glUniformMatrix3fv,"emscripten_glUniformMatrix4fv":_emscripten_glUniformMatrix4fv,"emscripten_glUseProgram":_emscripten_glUseProgram,"emscripten_glValidateProgram":_emscripten_glValidateProgram,"emscripten_glVertexAttrib1f":_emscripten_glVertexAttrib1f,"emscripten_glVertexAttrib1fv":_emscripten_glVertexAttrib1fv,"emscripten_glVertexAttrib2f":_emscripten_glVertexAttrib2f,"emscripten_glVertexAttrib2fv":_emscripten_glVertexAttrib2fv,"emscripten_glVertexAttrib3f":_emscripten_glVertexAttrib3f,"emscripten_glVertexAttrib3fv":_emscripten_glVertexAttrib3fv,"emscripten_glVertexAttrib4f":_emscripten_glVertexAttrib4f,"emscripten_glVertexAttrib4fv":_emscripten_glVertexAttrib4fv,"emscripten_glVertexAttribDivisorANGLE":_emscripten_glVertexAttribDivisorANGLE,"emscripten_glVertexAttribPointer":_emscripten_glVertexAttribPointer,"emscripten_glViewport":_emscripten_glViewport,"emscripten_has_asyncify":_emscripten_has_asyncify,"emscripten_longjmp":_emscripten_longjmp,"emscripten_memcpy_big":_emscripten_memcpy_big,"emscripten_request_fullscreen_strategy":_emscripten_request_fullscreen_strategy,"emscripten_request_pointerlock":_emscripten_request_pointerlock,"emscripten_resize_heap":_emscripten_resize_heap,"emscripten_run_script":_emscripten_run_script,"emscripten_sample_gamepad_data":_emscripten_sample_gamepad_data,"emscripten_set_beforeunload_callback_on_thread":_emscripten_set_beforeunload_callback_on_thread,"emscripten_set_blur_callback_on_thread":_emscripten_set_blur_callback_on_thread,"emscripten_set_canvas_element_size":_emscripten_set_canvas_element_size,"emscripten_set_element_css_size":_emscripten_set_element_css_size,"emscripten_set_focus_callback_on_thread":_emscripten_set_focus_callback_on_thread,"emscripten_set_fullscreenchange_callback_on_thread":_emscripten_set_fullscreenchange_callback_on_thread,"emscripten_set_gamepadconnected_callback_on_thread":_emscripten_set_gamepadconnected_callback_on_thread,"emscripten_set_gamepaddisconnected_callback_on_thread":_emscripten_set_gamepaddisconnected_callback_on_thread,"emscripten_set_keydown_callback_on_thread":_emscripten_set_keydown_callback_on_thread,"emscripten_set_keypress_callback_on_thread":_emscripten_set_keypress_callback_on_thread,"emscripten_set_keyup_callback_on_thread":_emscripten_set_keyup_callback_on_thread,"emscripten_set_main_loop_arg":_emscripten_set_main_loop_arg,"emscripten_set_mousedown_callback_on_thread":_emscripten_set_mousedown_callback_on_thread,"emscripten_set_mouseenter_callback_on_thread":_emscripten_set_mouseenter_callback_on_thread,"emscripten_set_mouseleave_callback_on_thread":_emscripten_set_mouseleave_callback_on_thread,"emscripten_set_mousemove_callback_on_thread":_emscripten_set_mousemove_callback_on_thread,"emscripten_set_mouseup_callback_on_thread":_emscripten_set_mouseup_callback_on_thread,"emscripten_set_pointerlockchange_callback_on_thread":_emscripten_set_pointerlockchange_callback_on_thread,"emscripten_set_resize_callback_on_thread":_emscripten_set_resize_callback_on_thread,"emscripten_set_touchcancel_callback_on_thread":_emscripten_set_touchcancel_callback_on_thread,"emscripten_set_touchend_callback_on_thread":_emscripten_set_touchend_callback_on_thread,"emscripten_set_touchmove_callback_on_thread":_emscripten_set_touchmove_callback_on_thread,"emscripten_set_touchstart_callback_on_thread":_emscripten_set_touchstart_callback_on_thread,"emscripten_set_visibilitychange_callback_on_thread":_emscripten_set_visibilitychange_callback_on_thread,"emscripten_set_wheel_callback_on_thread":_emscripten_set_wheel_callback_on_thread,"emscripten_sleep":_emscripten_sleep,"environ_get":_environ_get,"environ_sizes_get":_environ_sizes_get,"exit":_exit,"fd_close":_fd_close,"fd_fdstat_get":_fd_fdstat_get,"fd_read":_fd_read,"fd_seek":_fd_seek,"fd_sync":_fd_sync,"fd_write":_fd_write,"gai_strerror":_gai_strerror,"getTempRet0":_getTempRet0,"getaddrinfo":_getaddrinfo,"gethostbyaddr":_gethostbyaddr,"gethostbyname":_gethostbyname,"getnameinfo":_getnameinfo,"getpwuid":_getpwuid,"gettimeofday":_gettimeofday,"invoke_diii":invoke_diii,"invoke_fiii":invoke_fiii,"invoke_i":invoke_i,"invoke_ii":invoke_ii,"invoke_iii":invoke_iii,"invoke_iiii":invoke_iiii,"invoke_iiiii":invoke_iiiii,"invoke_iiiiii":invoke_iiiiii,"invoke_iiiiiii":invoke_iiiiiii,"invoke_iiiiiiii":invoke_iiiiiiii,"invoke_iiiiiiiiiii":invoke_iiiiiiiiiii,"invoke_iiiiiiiiiiii":invoke_iiiiiiiiiiii,"invoke_iiiiiiiiiiiii":invoke_iiiiiiiiiiiii,"invoke_iiiiij":invoke_iiiiij,"invoke_jiiii":invoke_jiiii,"invoke_v":invoke_v,"invoke_vi":invoke_vi,"invoke_vii":invoke_vii,"invoke_viii":invoke_viii,"invoke_viiii":invoke_viiii,"invoke_viiiiiii":invoke_viiiiiii,"invoke_viiiiiiiiii":invoke_viiiiiiiiii,"invoke_viiiiiiiiiiiiiii":invoke_viiiiiiiiiiiiiii,"memory":wasmMemory,"mktime":_mktime,"nanosleep":_nanosleep,"pthread_mutexattr_init":_pthread_mutexattr_init,"pthread_mutexattr_settype":_pthread_mutexattr_settype,"setTempRet0":_setTempRet0,"sigaction":_sigaction,"signal":_signal,"strftime":_strftime,"strftime_l":_strftime_l,"sysconf":_sysconf,"system":_system,"table":wasmTable,"time":_time};var asm=createWasm();var ___wasm_call_ctors=Module["___wasm_call_ctors"]=function(){return(___wasm_call_ctors=Module["___wasm_call_ctors"]=Module["asm"]["__wasm_call_ctors"]).apply(null,arguments)};var _main=Module["_main"]=function(){return(_main=Module["_main"]=Module["asm"]["main"]).apply(null,arguments)};var _memcpy=Module["_memcpy"]=function(){return(_memcpy=Module["_memcpy"]=Module["asm"]["memcpy"]).apply(null,arguments)};var _realloc=Module["_realloc"]=function(){return(_realloc=Module["_realloc"]=Module["asm"]["realloc"]).apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return(_malloc=Module["_malloc"]=Module["asm"]["malloc"]).apply(null,arguments)};var _free=Module["_free"]=function(){return(_free=Module["_free"]=Module["asm"]["free"]).apply(null,arguments)};var _strstr=Module["_strstr"]=function(){return(_strstr=Module["_strstr"]=Module["asm"]["strstr"]).apply(null,arguments)};var ___errno_location=Module["___errno_location"]=function(){return(___errno_location=Module["___errno_location"]=Module["asm"]["__errno_location"]).apply(null,arguments)};var _testSetjmp=Module["_testSetjmp"]=function(){return(_testSetjmp=Module["_testSetjmp"]=Module["asm"]["testSetjmp"]).apply(null,arguments)};var _saveSetjmp=Module["_saveSetjmp"]=function(){return(_saveSetjmp=Module["_saveSetjmp"]=Module["asm"]["saveSetjmp"]).apply(null,arguments)};var _htons=Module["_htons"]=function(){return(_htons=Module["_htons"]=Module["asm"]["htons"]).apply(null,arguments)};var _htonl=Module["_htonl"]=function(){return(_htonl=Module["_htonl"]=Module["asm"]["htonl"]).apply(null,arguments)};var _ntohs=Module["_ntohs"]=function(){return(_ntohs=Module["_ntohs"]=Module["asm"]["ntohs"]).apply(null,arguments)};var _emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=function(){return(_emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=Module["asm"]["emscripten_GetProcAddress"]).apply(null,arguments)};var __get_tzname=Module["__get_tzname"]=function(){return(__get_tzname=Module["__get_tzname"]=Module["asm"]["_get_tzname"]).apply(null,arguments)};var __get_daylight=Module["__get_daylight"]=function(){return(__get_daylight=Module["__get_daylight"]=Module["asm"]["_get_daylight"]).apply(null,arguments)};var __get_timezone=Module["__get_timezone"]=function(){return(__get_timezone=Module["__get_timezone"]=Module["asm"]["_get_timezone"]).apply(null,arguments)};var _setThrew=Module["_setThrew"]=function(){return(_setThrew=Module["_setThrew"]=Module["asm"]["setThrew"]).apply(null,arguments)};var stackSave=Module["stackSave"]=function(){return(stackSave=Module["stackSave"]=Module["asm"]["stackSave"]).apply(null,arguments)};var stackRestore=Module["stackRestore"]=function(){return(stackRestore=Module["stackRestore"]=Module["asm"]["stackRestore"]).apply(null,arguments)};var stackAlloc=Module["stackAlloc"]=function(){return(stackAlloc=Module["stackAlloc"]=Module["asm"]["stackAlloc"]).apply(null,arguments)};var dynCall_iiiiij=Module["dynCall_iiiiij"]=function(){return(dynCall_iiiiij=Module["dynCall_iiiiij"]=Module["asm"]["dynCall_iiiiij"]).apply(null,arguments)};var dynCall_jiiii=Module["dynCall_jiiii"]=function(){return(dynCall_jiiii=Module["dynCall_jiiii"]=Module["asm"]["dynCall_jiiii"]).apply(null,arguments)};var dynCall_viiiji=Module["dynCall_viiiji"]=function(){return(dynCall_viiiji=Module["dynCall_viiiji"]=Module["asm"]["dynCall_viiiji"]).apply(null,arguments)};var dynCall_ji=Module["dynCall_ji"]=function(){return(dynCall_ji=Module["dynCall_ji"]=Module["asm"]["dynCall_ji"]).apply(null,arguments)};var dynCall_iij=Module["dynCall_iij"]=function(){return(dynCall_iij=Module["dynCall_iij"]=Module["asm"]["dynCall_iij"]).apply(null,arguments)};var dynCall_jiij=Module["dynCall_jiij"]=function(){return(dynCall_jiij=Module["dynCall_jiij"]=Module["asm"]["dynCall_jiij"]).apply(null,arguments)};var dynCall_iiij=Module["dynCall_iiij"]=function(){return(dynCall_iiij=Module["dynCall_iiij"]=Module["asm"]["dynCall_iiij"]).apply(null,arguments)};var dynCall_viiij=Module["dynCall_viiij"]=function(){return(dynCall_viiij=Module["dynCall_viiij"]=Module["asm"]["dynCall_viiij"]).apply(null,arguments)};var dynCall_viijii=Module["dynCall_viijii"]=function(){return(dynCall_viijii=Module["dynCall_viijii"]=Module["asm"]["dynCall_viijii"]).apply(null,arguments)};var dynCall_iiji=Module["dynCall_iiji"]=function(){return(dynCall_iiji=Module["dynCall_iiji"]=Module["asm"]["dynCall_iiji"]).apply(null,arguments)};var dynCall_jiji=Module["dynCall_jiji"]=function(){return(dynCall_jiji=Module["dynCall_jiji"]=Module["asm"]["dynCall_jiji"]).apply(null,arguments)};var dynCall_jij=Module["dynCall_jij"]=function(){return(dynCall_jij=Module["dynCall_jij"]=Module["asm"]["dynCall_jij"]).apply(null,arguments)};var dynCall_ij=Module["dynCall_ij"]=function(){return(dynCall_ij=Module["dynCall_ij"]=Module["asm"]["dynCall_ij"]).apply(null,arguments)};var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=function(){return(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=Module["asm"]["dynCall_iiiiijj"]).apply(null,arguments)};var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=function(){return(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=Module["asm"]["dynCall_iiiiiijj"]).apply(null,arguments)};var __growWasmMemory=Module["__growWasmMemory"]=function(){return(__growWasmMemory=Module["__growWasmMemory"]=Module["asm"]["__growWasmMemory"]).apply(null,arguments)};function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{wasmTable.get(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return wasmTable.get(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{wasmTable.get(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vii(index,a1,a2){var sp=stackSave();try{wasmTable.get(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_v(index){var sp=stackSave();try{wasmTable.get(index)()}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return wasmTable.get(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_fiii(index,a1,a2,a3){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_diii(index,a1,a2,a3){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_i(index){var sp=stackSave();try{return wasmTable.get(index)()}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11){var sp=stackSave();try{return wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{wasmTable.get(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15){var sp=stackSave();try{wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiij(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return dynCall_iiiiij(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_jiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return dynCall_jiiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}Module["getMemory"]=getMemory;Module["addRunDependency"]=addRunDependency;Module["removeRunDependency"]=removeRunDependency;Module["FS_createFolder"]=FS.createFolder;Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createLink"]=FS.createLink;Module["FS_createDevice"]=FS.createDevice;Module["FS_unlink"]=FS.unlink;var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}var calledMain=false;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args){var entryFunction=Module["_main"];args=args||[];var argc=args.length+1;var argv=stackAlloc((argc+1)*4);HEAP32[argv>>2]=allocateUTF8OnStack(thisProgram);for(var i=1;i>2)+i]=allocateUTF8OnStack(args[i-1])}HEAP32[(argv>>2)+argc]=0;try{var ret=entryFunction(argc,argv);exit(ret,true)}catch(e){if(e instanceof ExitStatus){return}else if(e=="unwind"){noExitRuntime=true;return}else{var toLog=e;if(e&&typeof e==="object"&&e.stack){toLog=[e,e.stack]}err("exception thrown: "+toLog);quit_(1,e)}}finally{calledMain=true}}function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){if(implicit&&noExitRuntime&&status===0){return}if(noExitRuntime){}else{ABORT=true;EXITSTATUS=status;exitRuntime();if(Module["onExit"])Module["onExit"](status)}quit_(status,new ExitStatus(status))}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;noExitRuntime=true;run();if(typeof ENVIRONMENT_IS_PTHREAD==="undefined"||!ENVIRONMENT_IS_PTHREAD){Module.addRunDependency("IDBFS_sync");FS.mkdir("/home/web_user/love");FS.mount(IDBFS,{},"/home/web_user/love");FS.syncfs(true,function(err){if(err){Module["printErr"](err)}else{Module.removeRunDependency("IDBFS_sync")}});window.addEventListener("beforeunload",function(event){FS.syncfs(false,function(err){if(err){Module["printErr"](err)}})})}
-
-
- return Love.ready
-}
-);
-})();
-if (typeof exports === 'object' && typeof module === 'object')
- module.exports = Love;
- else if (typeof define === 'function' && define['amd'])
- define([], function() { return Love; });
- else if (typeof exports === 'object')
- exports["Love"] = Love;
-
\ No newline at end of file
diff --git a/.github/build/web/love.wasm b/.github/build/web/love.wasm
deleted file mode 100644
index ab96086b..00000000
Binary files a/.github/build/web/love.wasm and /dev/null differ
diff --git a/.github/build/web/favicon.ico b/.github/build/web/release/favicon.ico
similarity index 100%
rename from .github/build/web/favicon.ico
rename to .github/build/web/release/favicon.ico
diff --git a/.github/build/web/index.html b/.github/build/web/release/index.html
similarity index 96%
rename from .github/build/web/index.html
rename to .github/build/web/release/index.html
index 8e28dc34..d7f4f0b1 100644
--- a/.github/build/web/index.html
+++ b/.github/build/web/release/index.html
@@ -5,9 +5,10 @@
Techmino
-
-
+
+
+
@@ -61,7 +62,7 @@
var Module = {
arguments: ["./game.love"],
- INITIAL_MEMORY: 536870912,
+ INITIAL_MEMORY: 128000000,
printErr: console.error.bind(console),
canvas: (function() {
var canvas = document.getElementById('canvas');
diff --git a/.github/build/web/theme/bg.png b/.github/build/web/theme/bg.png
deleted file mode 100644
index 77ef798d..00000000
Binary files a/.github/build/web/theme/bg.png and /dev/null differ
diff --git a/.github/build/web/theme/love.css b/.github/build/web/theme/love.css
deleted file mode 100644
index 96bc2c23..00000000
--- a/.github/build/web/theme/love.css
+++ /dev/null
@@ -1,49 +0,0 @@
-* {
- box-sizing: border-box;
-}
-
-h1 {
- font-family: arial;
- color: rgb( 11, 86, 117 );
-}
-
-body {
- background-image: url(bg.png);
- background-repeat: no-repeat;
- font-family: arial;
- margin: 0;
- padding: none;
- background-color: rgb( 154, 205, 237 );
- color: rgb( 28, 78, 104 );
-}
-
-footer {
- font-family: arial;
- font-size: 12px;
- padding-left: 10px;
- position:absolute;
- bottom: 0;
- width: 100%;
-}
-
-/* Links */
-a {
- text-decoration: none;
-}
-a:link {
- color: rgb( 233, 73, 154 );
-}
-a:visited {
- color: rgb( 110, 30, 71 );
-}
-a:hover {
- color: rgb( 252, 207, 230 );
-}
-
-/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-#canvas {
- padding-right: 0;
- display: block;
- border: 0px none;
- visibility: hidden;
-}
diff --git a/.github/donate/donate.png b/.github/donate/donate.png
new file mode 100644
index 00000000..d7462656
Binary files /dev/null and b/.github/donate/donate.png differ
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index e03b8ae0..1a9bf557 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -8,9 +8,11 @@ on:
branches: [main]
env:
+ BUILD_ASSETS_FOLDER: ./.github/build
BUILD_TYPE: ${{ fromJSON('["dev", "release"]')[startsWith(github.ref, 'refs/tags/v')] }}
- CORE_LOVE_PACKAGE_PATH: ./core.love
+ COLD_CLEAR_DOWNLOAD_URL: https://github.com/26F-Studio/cold_clear_ai_love2d_wrapper/releases/download/11.5
CORE_LOVE_ARTIFACT_NAME: core_love_package
+ CORE_LOVE_PACKAGE_PATH: ./core.love
jobs:
get-info:
@@ -25,7 +27,7 @@ jobs:
commit-hash: ${{ steps.git-info.outputs.commit-hash }}
base-name: ${{ steps.assemble-base-name.outputs.base-name }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install lua
run: |
sudo apt-get install lua5.3 -y
@@ -73,7 +75,7 @@ jobs:
OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- name: Process app name
@@ -95,13 +97,13 @@ jobs:
build-list: ./media/ ./parts/ ./Zframework/ ./conf.lua ./main.lua ./version.lua ./legals.md ./license.txt
package-path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
- name: Upload core love package
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
- name: Add icon to love package
run: |
- cp ./.github/build/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png
+ cp ${{ env.BUILD_ASSETS_FOLDER }}/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png
zip -u ${{ env.CORE_LOVE_PACKAGE_PATH }} media/image/icon.png
rm media/image/icon.png
- name: Rename love package
@@ -109,7 +111,7 @@ jobs:
mkdir -p ${{ env.OUTPUT_FOLDER }}
mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.love
- name: Upload artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ needs.get-info.outputs.base-name }}_Core_love
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.love
@@ -130,10 +132,12 @@ jobs:
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
auto-test:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
needs: build-core
+ env:
+ APPIMAGE_PATH: ./love.AppImage
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- name: Love actions for testing
@@ -141,16 +145,35 @@ jobs:
with:
font-path: ./parts/fonts/proportional.otf
language-folder: ./parts/language
+ - name: Download core love package
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
+ - name: Download love
+ shell: bash
+ run: |
+ curl --retry 5 https://github.com/love2d/love/releases/download/11.5/love-11.5-x86_64.AppImage -o ${{ env.APPIMAGE_PATH }}
+ chmod +x ${{ env.APPIMAGE_PATH }}
+ - name: Install dependencies
+ shell: bash
+ run: |
+ sudo apt-get update
+ sudo apt-get install alsa-oss alsa-utils libfuse2 pavucontrol pulseaudio pulseaudio-utils x11-xserver-utils xvfb -y
+ - name: Run automated test
+ shell: bash
+ run: |
+ xvfb-run --auto-servernum ${{ env.APPIMAGE_PATH }} ${{ env.CORE_LOVE_PACKAGE_PATH }} --test
build-android:
runs-on: ubuntu-latest
needs: [get-info, build-core, auto-test]
if: github.event_name != 'pull_request'
env:
+ COLD_CLEAR_FOLDER: ./libAndroid
OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- name: Process app name
@@ -159,6 +182,7 @@ jobs:
run: |
import os
import re
+
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
if "${{ env.BUILD_TYPE }}" == "dev":
f.write('bundle-id=org.f26_studio.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '.snapshot\n')
@@ -167,17 +191,17 @@ jobs:
f.write('bundle-id=org.f26_studio.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}') + '\n')
- name: Download core love package
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Download ColdClear
- uses: ./.github/actions/get-cc
+ uses: ./.github/actions/get-unzip
with:
- platform: Android
- dir: ./libAndroid
+ url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Android.zip
+ dir: ${{ env.COLD_CLEAR_FOLDER }}
- name: Build Android packages
id: build-packages
- uses: love-actions/love-actions-android@main
+ uses: love-actions/love-actions-android@v2
with:
app-name: ${{ needs.get-info.outputs.app-name }}
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
@@ -187,15 +211,15 @@ jobs:
keystore-key-password: ${{ secrets.ANDROID_KEYSTORE_KEYPASSWORD }}
keystore-store-password: ${{ secrets.ANDROID_KEYSTORE_STOREPASSWORD }}
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
- resource-path: ./.github/build/android/${{ env.BUILD_TYPE }}/res
- extra-assets: ./libAndroid/
+ resource-path: ${{ env.BUILD_ASSETS_FOLDER }}/android/${{ env.BUILD_TYPE }}/res
+ extra-assets: ${{ env.COLD_CLEAR_FOLDER }}
custom-scheme: studio26f://oauth
product-name: ${{ steps.process-app-name.outputs.product-name }}
version-string: ${{ needs.get-info.outputs.version-string }}
version-code: ${{ needs.get-info.outputs.version-code }}
output-folder: ${{ env.OUTPUT_FOLDER }}
- name: Upload artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ needs.get-info.outputs.base-name }}_Android_release
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}-release.apk
@@ -219,10 +243,11 @@ jobs:
runs-on: ubuntu-latest
needs: [get-info, build-core, auto-test]
env:
+ COLD_CLEAR_FOLDER: ./ColdClear
OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- name: Process app name
@@ -237,45 +262,45 @@ jobs:
f.write('bundle-id=org.26f-studio.' + product_name + '\n')
f.write('product-name=' + product_name + '\n')
- name: Download core love package
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Add icon to love package
run: |
- cp ./.github/build/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png
+ cp ${{ env.BUILD_ASSETS_FOLDER }}/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png
zip -u ${{ env.CORE_LOVE_PACKAGE_PATH }} media/image/icon.png
rm media/image/icon.png
- name: Download ColdClear
- uses: ./.github/actions/get-cc
+ uses: ./.github/actions/get-unzip
with:
- platform: Linux
- dir: ./ColdClear
+ url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Linux.zip
+ dir: ${{ env.COLD_CLEAR_FOLDER }}
- name: Process ColdClear
shell: bash
run: |
- cd ./ColdClear
+ cd ${{ env.COLD_CLEAR_FOLDER }}
mkdir -p ./lib/lua/5.1
mv ./x64/CCloader.so ./lib/lua/5.1
- name: Build Linux packages
id: build-packages
- uses: love-actions/love-actions-linux@v1
+ uses: love-actions/love-actions-linux@v2
with:
app-name: ${{ needs.get-info.outputs.app-name }}
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
description: Techmino is fun!
version-string: ${{ needs.get-info.outputs.version-string }}
- icon-path: ./.github/build/linux/${{ env.BUILD_TYPE }}/icon.png
+ icon-path: ${{ env.BUILD_ASSETS_FOLDER }}/linux/${{ env.BUILD_TYPE }}/icon.png
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
- lib-path: ./ColdClear/lib
+ lib-path: ${{ env.COLD_CLEAR_FOLDER }}/lib
product-name: ${{ steps.process-app-name.outputs.product-name }}
output-folder: ${{ env.OUTPUT_FOLDER }}
- name: Upload AppImage artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ needs.get-info.outputs.base-name }}_Linux_AppImage
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.AppImage
- name: Upload Debian artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ needs.get-info.outputs.base-name }}_Linux_Debian
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.deb
@@ -298,138 +323,58 @@ jobs:
name: ${{ needs.get-info.outputs.update-title }}
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
- build-macos-portable:
- runs-on: macos-latest
- needs: [get-info, build-core, auto-test]
- if: github.event_name != 'pull_request'
- env:
- OUTPUT_FOLDER: ./build
- RELEASE_FOLDER: ./release
- steps:
- - uses: actions/checkout@v3
- with:
- submodules: recursive
- - name: Process app name
- id: process-app-name
- shell: python3 {0}
- run: |
- import os
- import re
- with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
- f.write('bundle-id=org.26f-studio.techmino\n')
- f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
- - name: Download core love package
- uses: actions/download-artifact@v3
- with:
- name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- - name: Download ColdClear
- uses: ./.github/actions/get-cc
- with:
- platform: macOS
- dir: ./ColdClear
- - name: Process ColdClear
- shell: bash
- run: |
- rm ./ColdClear/universal/libcold_clear.a
- - name: Build macOS packages
- id: build-packages
- uses: love-actions/love-actions-macos-portable@v1
- with:
- app-name: ${{ needs.get-info.outputs.app-name }}
- bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
- copyright: "Copyright © 2019-2023 26F-Studio. Some Rights Reserved."
- icon-path: ./.github/build/macOS/${{ env.BUILD_TYPE }}/icon.icns
- love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
- libs-path: ./ColdClear/universal/
- product-name: ${{ steps.process-app-name.outputs.product-name }}
- version-string: ${{ needs.get-info.outputs.version-string }}
- output-folder: ${{ env.OUTPUT_FOLDER }}
- account-username: ${{ secrets.APPLE_ACCOUNT_USERNAME }}
- account-password: ${{ secrets.APPLE_ACCOUNT_PASSWORD }}
- team-id: "${{ secrets.APPLE_DEVELOPER_TEAM_ID }}"
- developer-id-application-base64: ${{ secrets.APPLE_CERT_DEVELOPER_ID_APPLICATION }}
- developer-id-application-password: ${{ secrets.APPLE_CERT_DEVELOPER_ID_APPLICATION_PWD }}
- developer-id-installer-base64: ${{ secrets.APPLE_CERT_DEVELOPER_ID_INSTALLER }}
- developer-id-installer-password: ${{ secrets.APPLE_CERT_DEVELOPER_ID_INSTALLER_PWD }}
- dmg-background-path: ./.github/build/macOS/${{ env.BUILD_TYPE }}/dmg.png
- dmg-icon-position: "239 203"
- dmg-icon-size: "100"
- dmg-link-position: "565 203"
- dmg-text-size: "12"
- dmg-volume-icon-path: ./.github/build/macOS/${{ env.BUILD_TYPE }}/dmg.icns
- dmg-volume-name: ${{ steps.process-app-name.outputs.product-name }}
- dmg-window-position: "200 120"
- dmg-window-size: "800 500"
- - name: Upload pkg artifact
- uses: actions/upload-artifact@v3
- with:
- name: ${{ needs.get-info.outputs.base-name }}_macOS_portable_pkg
- path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.pkg
- - name: Upload dmg artifact
- uses: actions/upload-artifact@v3
- with:
- name: ${{ needs.get-info.outputs.base-name }}_macOS_portable_dmg
- path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.dmg
- - name: Upload bare artifact
- uses: actions/upload-artifact@v3
- with:
- name: ${{ needs.get-info.outputs.base-name }}_macOS_portable_bare
- path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.zip
- - name: Prepare for release
- if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
- shell: bash
- run: |
- mkdir -p ${{ env.RELEASE_FOLDER }}
- cp ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.pkg ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_macOS_portable.pkg
- cp ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.dmg ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_macOS_portable.dmg
- - name: Upload release
- if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
- uses: ncipollo/release-action@v1
- with:
- allowUpdates: true
- artifacts: |
- ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_macOS_portable.pkg
- ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_macOS_portable.dmg
- body: ${{ needs.get-info.outputs.update-note }}
- name: ${{ needs.get-info.outputs.update-title }}
- prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
-
- build-web:
+ build-web-compat:
runs-on: ubuntu-latest
needs: [get-info, build-core, auto-test]
+ env:
+ MEMORY_LIMIT: 128000000
+ OUTPUT_FOLDER: ./build
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- name: Download core love package
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- - name: Move core love package
+ - name: Build web packages
run: |
- mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ./.github/build/web/game.data
+ npx love.js ${{ env.CORE_LOVE_PACKAGE_PATH }} ${{ env.OUTPUT_FOLDER }} -t "${{ needs.get-info.outputs.app-name }}" -m ${{ env.MEMORY_LIMIT }} -c
+ - name: Move assets
+ run: |
+ mv ${{ env.BUILD_ASSETS_FOLDER }}/web/${{ env.BUILD_TYPE }}/* ${{ env.OUTPUT_FOLDER }}
+ - name: Initialize Love.js Api Player
+ run: |
+ pushd ${{ env.OUTPUT_FOLDER }}
+ wget https://raw.githubusercontent.com/MrcSnm/Love.js-Api-Player/refs/heads/master/consolewrapper.js
+ wget https://raw.githubusercontent.com/MrcSnm/Love.js-Api-Player/refs/heads/master/globalizeFS.js
+ wget https://raw.githubusercontent.com/MrcSnm/Love.js-Api-Player/refs/heads/master/webdb.js
+ node globalizeFS.js
+ rm globalizeFS.js
+ popd
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ needs.get-info.outputs.base-name }}_Web
+ path: ${{ env.OUTPUT_FOLDER }}
- name: Deploy to GitHub Pages
- uses: crazy-max/ghaction-github-pages@v3
+ uses: crazy-max/ghaction-github-pages@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
- build_dir: ./.github/build/web/
+ build_dir: ${{ env.OUTPUT_FOLDER }}
keep_history: false
- target_branch: web-dev
- - name: Upload artifact
- uses: actions/upload-artifact@v3
- with:
- name: ${{ needs.get-info.outputs.base-name }}_Web_PWA
- path: ./.github/build/web/
+ target_branch: gh-pages
build-windows:
runs-on: windows-latest
needs: [get-info, build-core, auto-test]
env:
+ COLD_CLEAR_FOLDER: ./ColdClear
OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- name: Process app name
@@ -441,20 +386,20 @@ jobs:
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
- name: Download core love package
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Download ColdClear
- uses: ./.github/actions/get-cc
+ uses: ./.github/actions/get-unzip
with:
- platform: Windows
- dir: ./ColdClear
+ url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Windows.zip
+ dir: ${{ env.COLD_CLEAR_FOLDER }}
- name: Update Windows template
shell: python3 {0}
run: |
version_string = "${{ needs.get-info.outputs.version-string }}"
file_version = (f"{version_string.replace('.', ',')},0")
- with open("./.github/build/windows/${{ env.BUILD_TYPE }}/template.rc", "r+", encoding="utf8") as file:
+ with open("${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/template.rc", "r+", encoding="utf8") as file:
data = file.read()
data = data\
.replace("@Version", version_string)\
@@ -464,30 +409,30 @@ jobs:
file.write(data)
- name: Build Windows packages
id: build-packages
- uses: love-actions/love-actions-windows@v1
+ uses: love-actions/love-actions-windows@v2
with:
- icon-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/icon.ico
- rc-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/template.rc
+ icon-path: ${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/icon.ico
+ rc-path: ${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/template.rc
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
- extra-assets-x86: ./ColdClear/x86/CCloader.dll ./ColdClear/x86/cold_clear.dll
- extra-assets-x64: ./ColdClear/x64/CCloader.dll ./ColdClear/x64/cold_clear.dll
+ extra-assets-x86: ${{ env.COLD_CLEAR_FOLDER }}/x86/CCloader.dll ${{ env.COLD_CLEAR_FOLDER }}/x86/cold_clear.dll ${{ env.BUILD_ASSETS_FOLDER }}/extraLibs/Windows_x64/discord-rpc.dll
+ extra-assets-x64: ${{ env.COLD_CLEAR_FOLDER }}/x64/CCloader.dll ${{ env.COLD_CLEAR_FOLDER }}/x64/cold_clear.dll ${{ env.BUILD_ASSETS_FOLDER }}/extraLibs/Windows_x86/discord-rpc.dll
product-name: ${{ steps.process-app-name.outputs.product-name }}
app-id: ${{ secrets.WINDOWS_APP_ID }}
project-website: https://www.studio26f.org/
installer-languages: ChineseSimplified.isl ChineseTraditional.isl English.isl Spanish.isl French.isl Indonesian.isl Japanese.isl Portuguese.isl
output-folder: ${{ env.OUTPUT_FOLDER }}
- name: Upload 32-bit artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ needs.get-info.outputs.base-name }}_Windows_x86
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x86.zip
- name: Upload 64-bit artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ needs.get-info.outputs.base-name }}_Windows_x64
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x64.zip
- name: Upload installer artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ needs.get-info.outputs.base-name }}_Windows_installer
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_installer.exe
@@ -522,38 +467,58 @@ jobs:
build-core,
build-android,
build-linux,
- build-macos-portable,
- build-web,
+ build-web-compat,
build-windows,
]
env:
ACTION_TYPE: ${{ fromJSON('[["Development", "Pre-release"], ["Release", "Release"]]')[startsWith(github.ref, 'refs/tags/v')][startsWith(github.ref, 'refs/tags/pre')] }}
steps:
- name: Cleanup
- uses: geekyeggo/delete-artifact@v2
+ uses: geekyeggo/delete-artifact@v5
with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Send Discord message
- if: github.event_name != 'pull_request'
- uses: Sniddl/discord-commits@v1.6
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK }}
- message: "Github Actions for **${{ github.repository }}**."
- embed: '{
- "author":{
- "name":"${{ needs.get-info.outputs.app-name }} [${{ env.ACTION_TYPE }}]",
- "url":"https://github.com/${{ github.repository }}"
- },
- "title":"${{ needs.get-info.outputs.app-name }} (${{ needs.get-info.outputs.version-name }}) Build Result",
- "description": "CI triggered at ${{ needs.get-info.outputs.commit-hash }}",
- "url":"https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
- "thumbnail":{
- "url":"https://raw.githubusercontent.com/${{ github.repository }}/main/.github/build/linux/${{ env.BUILD_TYPE }}/icon.png"
- },
- "color":36863,
- "fields":[
- {"name":"Version","value":"${{ needs.get-info.outputs.version-string }}","inline": true},
- {"name":"Package Name","value":"${{ needs.get-info.outputs.base-name }}","inline": true},
- {"name":"Status","value":"**Automatic Test:** ${{ needs.auto-test.result }}\n**Core:** ${{ needs.build-core.result }}\n**Android:** ${{ needs.build-android.result }}\n**Linux:** ${{ needs.build-linux.result }}\n**macOS portable:** ${{ needs.build-macos-portable.result }}\n**Windows:** ${{ needs.build-windows.result }}"}
+ if: github.ref == 'refs/heads/main'
+ shell: python
+ run: |
+ import requests
+ import json
+
+ headers = {
+ 'Content-Type': 'application/json',
+ }
+ payload = json.dumps({
+ "content": "Github Actions for **${{ github.repository }}**.",
+ "embeds": [
+ {
+ "author": {
+ "name": "${{ needs.get-info.outputs.app-name }} [${{ env.ACTION_TYPE }}]",
+ "url": "https://github.com/${{ github.repository }}"
+ },
+ "title": "${{ needs.get-info.outputs.app-name }} (${{ needs.get-info.outputs.version-name }}) Build Result",
+ "description": "CI triggered at ${{ needs.get-info.outputs.commit-hash }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "thumbnail": {
+ "url": "https://raw.githubusercontent.com/${{ github.repository }}/main/.github/build/linux/${{ env.BUILD_TYPE }}/icon.png"
+ },
+ "color": 36863,
+ "fields": [
+ {
+ "name": "Version",
+ "value": "${{ needs.get-info.outputs.version-string }}",
+ "inline": True
+ },
+ {
+ "name": "Package Name",
+ "value": "${{ needs.get-info.outputs.base-name }}",
+ "inline": True
+ },
+ {
+ "name": "Status",
+ "value": "**Automatic Test:** ${{ needs.auto-test.result }}\n**Core:** ${{ needs.build-core.result }}\n**Android:** ${{ needs.build-android.result }}\n**Linux:** ${{ needs.build-linux.result }}\n**Web compatible:** ${{ needs.build-web-compat.result }}\n**Windows:** ${{ needs.build-windows.result }}"
+ }
+ ]
+ }
]
- }'
+ })
+ requests.request("POST", "${{ secrets.DISCORD_WEBHOOK }}", headers=headers, data=payload)
diff --git a/.gitignore b/.gitignore
index be29303f..4a7b924b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
.vscode
-libAndroid
*.ini
.DS_Store
Thumbs.db
diff --git a/Zframework/clipboard.lua b/Zframework/clipboard.lua
new file mode 100644
index 00000000..bfa41060
--- /dev/null
+++ b/Zframework/clipboard.lua
@@ -0,0 +1,103 @@
+local function _sanitize(content)
+ if type(content)=='boolean' then
+ content=content and 'true' or 'false'
+ end
+ if type(content)=='nil' then
+ content=''
+ end
+ if type(content)=='number' then
+ content=tostring(content)
+ end
+ if type(content)~='string' then
+ MES.new('error',"Invalid content type!")
+ MES.traceback()
+ return ''
+ end
+ return content
+end
+
+if SYSTEM~='Web' then
+ local get=love.system.getClipboardText
+ local set=love.system.setClipboardText
+ return {
+ get=function() return get() or '' end,
+ set=function(content) set(_sanitize(content)) end,
+ setFreshInterval=NULL,
+ _update=NULL,
+ }
+end
+
+if WEB_COMPAT_MODE then
+ local _clipboardBuffer=''
+ return {
+ get=function()
+ JS.newPromiseRequest(
+ JS.stringFunc(
+ [[
+ window.navigator.clipboard
+ .readText()
+ .then((text) => _$_(text))
+ .catch((e) => {
+ console.warn(e);
+ _$_('');
+ });
+ ]]
+ ),
+ function(data) _clipboardBuffer=data end,
+ function() _clipboardBuffer='' end,
+ 3,
+ 'getClipboardText'
+ )
+ if TASK.lock('clipboard_compat_interval',2.6) then
+ _clipboardBuffer=''
+ MES.new('warn',"Web-Compat mode, paste again to confirm",2.6)
+ end
+ return _clipboardBuffer
+ end,
+ set=function(str)
+ JS.callJS(JS.stringFunc(
+ [[
+ window.navigator.clipboard
+ .writeText('%s')
+ .then(() => console.log('Copied to clipboard'))
+ .catch((e) => console.warn(e));
+ ]],
+ _sanitize(str)
+ ))
+ end,
+ setFreshInterval=NULL,
+ _update=NULL,
+ }
+end
+
+local getCHN=love.thread.getChannel('CLIP_get')
+local setCHN=love.thread.getChannel('CLIP_set')
+local trigCHN=love.thread.getChannel('CLIP_trig')
+
+local clipboard_thread=love.thread.newThread('Zframework/clipboard_thread.lua')
+local isStarted,errorMessage=clipboard_thread:start()
+
+if not isStarted then
+ MES.new("error",errorMessage,26)
+end
+
+local freshInterval=1
+local timer=-.626
+return {
+ get=function() return getCHN:peek() or '' end,
+ set=function(content) setCHN:push(_sanitize(content)) end,
+ setFreshInterval=function(val)
+ freshInterval=val
+ end,
+ _update=function(dt)
+ timer=timer+dt
+ if timer>freshInterval then
+ if isStarted and not clipboard_thread:isRunning() then
+ MES.new("warn",clipboard_thread:getError(),26)
+ isStarted=false
+ end
+ trigCHN:push(timer)
+ timer=0
+ end
+ end,
+}
diff --git a/Zframework/clipboard_thread.lua b/Zframework/clipboard_thread.lua
new file mode 100644
index 00000000..8299c124
--- /dev/null
+++ b/Zframework/clipboard_thread.lua
@@ -0,0 +1,48 @@
+local getCHN=love.thread.getChannel('CLIP_get')
+local setCHN=love.thread.getChannel('CLIP_set')
+local trigCHN=love.thread.getChannel('CLIP_trig')
+
+JS=require'Zframework.js'
+local sleep=require'love.timer'.sleep
+
+local retrieving=false
+while true do
+ if trigCHN:getCount()>0 then
+ local dt=trigCHN:pop()
+ if setCHN:getCount()>0 then
+ while setCHN:getCount()>1 do setCHN:pop() end
+ -- Set Clipboard
+ JS.callJS(JS.stringFunc(
+ [[
+ window.navigator.clipboard
+ .writeText('%s')
+ .then(() => console.log('Copied to clipboard'))
+ .catch((e) => console.warn(e));
+ ]],
+ setCHN:pop()
+ ))
+ end
+ -- Get Clipboard
+ if not retrieving then
+ JS.newPromiseRequest(
+ JS.stringFunc[[
+ window.navigator.clipboard
+ .readText()
+ .then((text) => _$_(text))
+ .catch((e)=>{});
+ ]],
+ function(data)
+ while getCHN:getCount()>0 do getCHN:pop() end
+ getCHN:push(data)
+ retrieving=false
+ end,
+ function() retrieving=false end,
+ 1,
+ 'getClipboardText'
+ )
+ retrieving=true
+ end
+ JS.retrieveData(dt)
+ end
+ sleep(.001)
+end
diff --git a/Zframework/http.lua b/Zframework/http.lua
index 55484e64..4576c661 100644
--- a/Zframework/http.lua
+++ b/Zframework/http.lua
@@ -1,5 +1,5 @@
-local sendCHN=love.thread.getChannel('inputChannel')
-local recvCHN=love.thread.getChannel('outputChannel')
+local sendCHN=love.thread.getChannel('HTTP_inputChannel')
+local recvCHN=love.thread.getChannel('HTTP_outputChannel')
local threads={}
local threadCount=0
@@ -9,11 +9,15 @@ local threadCode=[[
local http=require'socket.http'
local ltn12=require'ltn12'
- local sendCHN=love.thread.getChannel('inputChannel')
- local recvCHN=love.thread.getChannel('outputChannel')
+ local sendCHN=love.thread.getChannel('HTTP_inputChannel')
+ local recvCHN=love.thread.getChannel('HTTP_outputChannel')
+ local sleep=require'love.timer'.sleep
while true do
- local arg=sendCHN:demand()
+ -- local arg=sendCHN:demand()
+ -- Warning: workaround for love.js
+ while sendCHN:getCount()==0 do sleep(.0626) end
+ local arg=sendCHN:pop()
if arg._destroy then
recvCHN:push{
diff --git a/Zframework/init.lua b/Zframework/init.lua
index 5ba02375..95798b6b 100644
--- a/Zframework/init.lua
+++ b/Zframework/init.lua
@@ -3,8 +3,16 @@
NONE={}function NULL() end PAPER=love.graphics.newCanvas(1,1)
EDITING=""
LOADED=false
+
+---@type 'Windows'|'Android'|'Linux'|'iOS'|'macOS'|'Web'
SYSTEM=love.system.getOS()
-if SYSTEM=='OS X' then SYSTEM='macOS' end
+WEB_COMPAT_MODE=false
+if SYSTEM=='OS X' then
+ SYSTEM='macOS'
+elseif SYSTEM=='Web' then
+ WEB_COMPAT_MODE=not love.thread.newThread('\n'):start()
+ print('Web compatible mode: ', WEB_COMPAT_MODE)
+end
-- Bit module
local success
@@ -72,6 +80,7 @@ do
end
-- Love-based modules (basic)
+CLIPBOARD= require'Zframework.clipboard'
HTTP= require'Zframework.http'
WS= require'Zframework.websocket'
FILE= require'Zframework.file'
@@ -94,6 +103,10 @@ IMG= require'Zframework.image'
BGM= require'Zframework.bgm'
VOC= require'Zframework.voice'
+if SYSTEM=='Web' then
+ JS=require'Zframework.js'
+end
+
local ms,kb=love.mouse,love.keyboard
local KBisDown=kb.isDown
@@ -174,6 +187,7 @@ local function updatePowerInfo()
gc_pop()
gc.setCanvas()
end
+
-------------------------------------------------------------
local lastX,lastY=0,0-- Last click pos
local function _updateMousePos(x,y,dx,dy)
@@ -423,38 +437,38 @@ local dPadToKey={
start='return',
back='escape',
}
-function love.joystickadded(JS)
+function love.joystickadded(joystick)
table.insert(jsState,{
- _id=JS:getID(),
- _jsObj=JS,
+ _id=joystick:getID(),
+ _jsObj=joystick,
leftx=0,lefty=0,
rightx=0,righty=0,
triggerleft=0,triggerright=0
})
MES.new('info',"Joystick added")
end
-function love.joystickremoved(JS)
+function love.joystickremoved(joystick)
for i=1,#jsState do
- if jsState[i]._jsObj==JS then
+ if jsState[i]._jsObj==joystick then
for j=1,#gamePadKeys do
- if JS:isGamepadDown(gamePadKeys[j]) then
- love.gamepadreleased(JS,gamePadKeys[j])
+ if joystick:isGamepadDown(gamePadKeys[j]) then
+ love.gamepadreleased(joystick,gamePadKeys[j])
end
end
- love.gamepadaxis(JS,'leftx',0)
- love.gamepadaxis(JS,'lefty',0)
- love.gamepadaxis(JS,'rightx',0)
- love.gamepadaxis(JS,'righty',0)
- love.gamepadaxis(JS,'triggerleft',-1)
- love.gamepadaxis(JS,'triggerright',-1)
+ love.gamepadaxis(joystick,'leftx',0)
+ love.gamepadaxis(joystick,'lefty',0)
+ love.gamepadaxis(joystick,'rightx',0)
+ love.gamepadaxis(joystick,'righty',0)
+ love.gamepadaxis(joystick,'triggerleft',-1)
+ love.gamepadaxis(joystick,'triggerright',-1)
MES.new('info',"Joystick removed")
table.remove(jsState,i)
break
end
end
end
-function love.gamepadaxis(JS,axis,val)
- if jsState[1] and JS==jsState[1]._jsObj then
+function love.gamepadaxis(joystick,axis,val)
+ if jsState[1] and joystick==jsState[1]._jsObj then
local js=jsState[1]
if axis=='leftx' or axis=='lefty' or axis=='rightx' or axis=='righty' then
local newVal=-- range: [0,1]
@@ -463,14 +477,14 @@ function love.gamepadaxis(JS,axis,val)
0
if newVal~=js[axis] then
if js[axis]==-1 then
- love.gamepadreleased(JS,jsAxisEventName[axis][1])
+ love.gamepadreleased(joystick,jsAxisEventName[axis][1])
elseif js[axis]~=0 then
- love.gamepadreleased(JS,jsAxisEventName[axis][2])
+ love.gamepadreleased(joystick,jsAxisEventName[axis][2])
end
if newVal==-1 then
- love.gamepadpressed(JS,jsAxisEventName[axis][1])
+ love.gamepadpressed(joystick,jsAxisEventName[axis][1])
elseif newVal==1 then
- love.gamepadpressed(JS,jsAxisEventName[axis][2])
+ love.gamepadpressed(joystick,jsAxisEventName[axis][2])
end
js[axis]=newVal
end
@@ -478,9 +492,9 @@ function love.gamepadaxis(JS,axis,val)
local newVal=val>.3 and 1 or 0-- range: [0,1]
if newVal~=js[axis] then
if newVal==1 then
- love.gamepadpressed(JS,jsAxisEventName[axis])
+ love.gamepadpressed(joystick,jsAxisEventName[axis])
else
- love.gamepadreleased(JS,jsAxisEventName[axis])
+ love.gamepadreleased(joystick,jsAxisEventName[axis])
end
js[axis]=newVal
end
@@ -720,6 +734,10 @@ function love.run()
-- UPDATE
STEP()
+ if SYSTEM == 'Web' then
+ JS.retrieveData(dt)
+ CLIPBOARD._update(dt)
+ end
if mouseShow then mouse_update(dt) end
if next(jsState) then gp_update(jsState[1],dt) end
VOC.update()
diff --git a/Zframework/js.lua b/Zframework/js.lua
new file mode 100644
index 00000000..c5a30417
--- /dev/null
+++ b/Zframework/js.lua
@@ -0,0 +1,142 @@
+local __requestQueue={}
+local _requestCount=0
+local _Request={
+ command="",
+ currentTime=0,
+ timeOut=2,
+ id='0',
+}
+local __defaultErrorFunction=nil
+local isDebugActive=false
+
+local JS={}
+
+function JS.callJS(funcToCall)
+ print("callJavascriptFunction "..funcToCall)
+end
+
+--You can pass a set of commands here and, it is a syntactic sugar for executing many commands inside callJS, as it only calls a function
+--If you pass arguments to the func beyond the string, it will perform automatically string.format
+--Return statement is possible inside this structure
+--This will return a string containing a function to be called by JS.callJS
+function JS.stringFunc(str,...)
+ str="(function(){"..str.."})()"
+ if (#arg>0) then
+ str=str:format(unpack(arg))
+ end
+ str=str:gsub("[\n\t]","")
+ return str
+end
+
+--The call will store in the webDB the return value from the function passed it timeouts
+local function retrieveJS(funcToCall,filename)
+ --Used for retrieveData function
+ JS.callJS(("FS.writeFile('%s/%s',%s);"):format(love.filesystem.getSaveDirectory(),filename,funcToCall))
+end
+
+--Call JS.newRequest instead
+function _Request:new(isPromise,command,onDataLoaded,onError,timeout,id)
+ local obj={}
+ setmetatable(obj,self)
+ obj.command=command
+ obj.onError=onError or __defaultErrorFunction
+ if not isPromise then
+ retrieveJS(command,self.filename)
+ else
+ JS.callJS(command)
+ end
+ obj.onDataLoaded=onDataLoaded
+ obj.timeOut=(timeout==nil) and obj.timeOut or timeout
+ obj.id=id
+ obj.filename="__temp"..id
+
+
+ function obj:getData()
+ --Try to read from webdb
+ if love.filesystem.getInfo(self.filename) then
+ return love.filesystem.read(self.filename)
+ end
+ end
+
+ function obj:purgeData()
+ --Data must be purged for not allowing old data to be retrieved
+ love.filesystem.remove(self.filename)
+ end
+
+ function obj:update(dt)
+ self.timeOut=self.timeOut-dt
+ local retData=self:getData()
+
+ if ((retData~=nil and retData~="nil") or self.timeOut<=0) then
+ if (retData~=nil and retData:match("ERROR")==nil) then
+ if isDebugActive then
+ print("Data has been retrieved "..retData)
+ end
+ self.onDataLoaded(retData)
+ else
+ self.onError(self.id,retData)
+ end
+ self:purgeData()
+ return false
+ else
+ return true
+ end
+ end
+ return obj
+end
+
+--Place this function on love.update and set it to return if it returns false (This API is synchronous)
+function JS.retrieveData(dt)
+ local isRetrieving=#__requestQueue~=0
+ local deadRequests={}
+ for i=1,#__requestQueue do
+ local isUpdating=__requestQueue[i]:update(dt)
+ if not isUpdating then
+ table.insert(deadRequests,i)
+ end
+ end
+ for i=1,#deadRequests do
+ if (isDebugActive) then
+ print("Request died: "..deadRequests[i])
+ end
+ table.remove(__requestQueue,deadRequests[i])
+ end
+ return isRetrieving
+end
+
+--May only be used for functions that don't return a promise
+function JS.newRequest(funcToCall,onDataLoaded,onError,timeout,optionalId)
+ table.insert(__requestQueue,_Request:new(false,funcToCall,onDataLoaded,onError,timeout or 5,optionalId or _requestCount))
+end
+
+--This function can be handled manually (in JS code)
+--How to: add the function call when your events resolve: FS.writeFile("Put love.filesystem.getSaveDirectory here", "Pass a string here (NUMBER DONT WORK"))
+--Or it can be handled by Lua, it auto sets your data if you write the following command:
+-- _$_(yourStringOrFunctionHere)
+function JS.newPromiseRequest(funcToCall,onDataLoaded,onError,timeout,optionalId)
+ optionalId=optionalId or _requestCount
+ funcToCall=funcToCall:gsub("_$_%(","FS.writeFile('"..love.filesystem.getSaveDirectory().."/__temp"..optionalId.."', ")
+ table.insert(__requestQueue,_Request:new(true,funcToCall,onDataLoaded,onError,timeout or 5,optionalId))
+end
+
+
+--It receives the ID from ther request
+--Don't try printing the request.command, as it will execute the javascript command
+function JS.setDefaultErrorFunction(func)
+ __defaultErrorFunction=func
+end
+
+JS.setDefaultErrorFunction(function(id,error)
+ if (isDebugActive) then
+ local msg="Data could not be loaded for id:'"..id.."'"
+ if (error) then
+ msg=msg.."\nError: "..error
+ end
+ print(msg)
+ end
+end)
+
+
+JS.callJS(JS.stringFunc("__getWebDB('%s');","__LuaJSDB"))
+
+return JS
diff --git a/Zframework/profile.lua b/Zframework/profile.lua
index 85ba3a55..722ebfc4 100644
--- a/Zframework/profile.lua
+++ b/Zframework/profile.lua
@@ -140,7 +140,7 @@ function profile.switch()
switch=not switch
if not switch then
profile.stop()
- love.system.setClipboardText(profile.report())
+ CLIPBOARD.set(profile.report())
profile.reset()
return false
else
diff --git a/Zframework/stringExtend.lua b/Zframework/stringExtend.lua
index 72ba1229..141fc897 100644
--- a/Zframework/stringExtend.lua
+++ b/Zframework/stringExtend.lua
@@ -131,9 +131,8 @@ function STRING.time_short(t)
-- floor seconds
timeUnits[#timeUnits]=floorint(timeUnits[#timeUnits])
- local outputStr=''
for i=1,#timeUnits do
- if timeUnits>0 then
+ if timeUnits[i]>0 then
return timeUnits[i]..timeLetters[i]..' '..timeUnits[i+1]..timeLetters[i+1]
end
end
@@ -190,7 +189,7 @@ do-- functions to shorted big numbers
function STRING.bigInt(t)
if t<1000 then
return tostring(t)
- elseif t~=1e999 then
+ elseif t~=1/0 then
local e=floorint(lg(t)/3)
return(t/10^(e*3))..units[e+1]
else
diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua
index 854ec3dd..d91d87d3 100644
--- a/Zframework/websocket.lua
+++ b/Zframework/websocket.lua
@@ -8,8 +8,6 @@ local path=''
local type=type
local timer=love.timer.getTime
-local TRD=love.thread.newThread("\n")
-local TRD_isRunning=TRD.isRunning
local WS={}
local wsList=setmetatable({},{
@@ -151,7 +149,7 @@ function WS.update(dt)
local time=timer()
for name,ws in next,wsList do
if ws.real and ws.status~='dead' then
- if TRD_isRunning(ws.thread) then
+ if ws.thread:isRunning() then
if ws.triggerCHN:getCount()==0 then
ws.triggerCHN:push(0)
end
diff --git a/Zframework/websocket_thread.lua b/Zframework/websocket_thread.lua
index e2fda4c4..6588577d 100644
--- a/Zframework/websocket_thread.lua
+++ b/Zframework/websocket_thread.lua
@@ -1,3 +1,4 @@
+---@type love.Channel,love.Channel,love.Channel
local triggerCHN,sendCHN,readCHN=...
local CHN_demand,CHN_getCount=triggerCHN.demand,triggerCHN.getCount
@@ -5,16 +6,20 @@ local CHN_push,CHN_pop=triggerCHN.push,triggerCHN.pop
local SOCK=require'socket'.tcp()
local JSON=require'Zframework.json'
+local sleep=require'love.timer'.sleep
do-- Connect
- local host=CHN_demand(sendCHN)
- local port=CHN_demand(sendCHN)
- local path=CHN_demand(sendCHN)
- local head=CHN_demand(sendCHN)
- local timeout=CHN_demand(sendCHN)
+ -- Warning: workaround for love.js, used to use CHN_demand instead
+ while CHN_getCount(sendCHN)<5 do sleep(.0626) end
+ local host=CHN_pop(sendCHN)
+ local port=CHN_pop(sendCHN)
+ local path=CHN_pop(sendCHN)
+ local head=CHN_pop(sendCHN)
+ local timeout=CHN_pop(sendCHN)
SOCK:settimeout(timeout)
local res,err=SOCK:connect(host,port)
+ -- print('C0',res,err)
assert(res,err)
-- WebSocket handshake
@@ -31,6 +36,7 @@ do-- Connect
-- First line of HTTP
res,err=SOCK:receive('*l')
+ -- print('C',res,err)
assert(res,err)
local code,ctLen
code=res:find(' ')
@@ -39,22 +45,28 @@ do-- Connect
-- Get body length from headers and remove headers
repeat
res,err=SOCK:receive('*l')
+ -- print('H',res,err)
assert(res,err)
- if not ctLen and res:find('length') then
- ctLen=tonumber(res:match('%d+'))
+ if not ctLen and res:find('content-length') then
+ ctLen=tonumber(res:match('%d+')) or 0
end
until res==''
-- Result
+ if code=='101' then
+ CHN_push(readCHN,'success')
+ end
+
+ -- Content(?)
if ctLen then
- if code=='101' then
- CHN_push(readCHN,'success')
- else
- res,err=SOCK:receive(ctLen)
+ res,err=SOCK:receive(ctLen)
+ -- print('R',res,err)
+ if code~='101' then
res=JSON.decode(assert(res,err))
error((code or "XXX")..":"..(res and res.reason or "Server Error"))
end
end
+
SOCK:settimeout(0)
end
@@ -136,10 +148,10 @@ local readThread=coroutine.wrap(function()
assert(res,err)
length=shl(byte(res,1),8)+byte(res,2)
elseif length==127 then
- local lenData
- lenData,err=_receive(SOCK,8)
+ -- 'res' is 'lenData' here
+ res,err=_receive(SOCK,8)
assert(res,err)
- local _,_,_,_,_5,_6,_7,_8=byte(lenData,1,8)
+ local _,_,_,_,_5,_6,_7,_8=byte(res,1,8)
length=shl(_5,24)+shl(_6,16)+shl(_7,8)+_8
end
res,err=_receive(SOCK,length)
@@ -158,12 +170,14 @@ local readThread=coroutine.wrap(function()
lBuffer=lBuffer..res
if fin then
CHN_push(readCHN,lBuffer)
+ -- print('M',lBuffer)
lBuffer=""
end
else
CHN_push(readCHN,op)
if fin then
CHN_push(readCHN,res)
+ -- print('S',res)
lBuffer=""
else
lBuffer=res
@@ -176,7 +190,8 @@ end)
local success,err
while true do-- Running
- CHN_demand(triggerCHN)
+ while CHN_getCount(triggerCHN)==0 do sleep(.0626) end
+ CHN_pop(triggerCHN)
success,err=pcall(sendThread)
if not success or err then break end
success,err=pcall(readThread)
diff --git a/Zframework/widget.lua b/Zframework/widget.lua
index 876206ad..83e8842a 100644
--- a/Zframework/widget.lua
+++ b/Zframework/widget.lua
@@ -15,6 +15,7 @@ local timer=love.timer.getTime
local next=next
local floor,ceil=math.floor,math.ceil
local max,min=math.max,math.min
+local match=string.match
local sub,ins,rem=string.sub,table.insert,table.remove
local xOy=SCR.xOy
local FONT=FONT
@@ -142,13 +143,21 @@ local button={
type='button',
mustHaveText=true,
ATV=0,-- Activating time(0~8)
+ textAlreadyWrapped=false,-- Text already wrapped? (Managed by :setObject, can be override, this will be true if obj has a '\n')
}
function button:reset()
self.ATV=0
end
function button:setObject(obj)
if type(obj)=='string' or type(obj)=='number' then
- self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
+ if match(obj,"\n") then
+ self.textAlreadyWrapped=true
+ self.obj=gc.newText(FONT.get(self.font,self.fType))
+ self.obj:addf(obj,self.w-self.edge*2,(self.align=='L' and 'left') or (self.align=='R' and 'right') or 'center')
+ else
+ self.textAlreadyWrapped=false
+ self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
+ end
elseif obj then
self.obj=obj
end
@@ -194,16 +203,7 @@ function button:draw()
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
local y0=y+h*.5
gc_setColor(1,1,1,.2+ATV*.05)
- if self.align=='M' then
- local x0=x+w*.5
- local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
- gc_draw(obj,x0-1,y0-1,nil,kx,1,ox,oy)
- gc_draw(obj,x0-1,y0+1,nil,kx,1,ox,oy)
- gc_draw(obj,x0+1,y0-1,nil,kx,1,ox,oy)
- gc_draw(obj,x0+1,y0+1,nil,kx,1,ox,oy)
- gc_setColor(r*.55,g*.55,b*.55)
- gc_draw(obj,x0,y0,nil,kx,1,ox,oy)
- elseif self.align=='L' then
+ if self.align=='L' or self.textAlreadyWrapped then
local edge=self.edge
gc_draw(obj,x+edge-1,y0-1-oy)
gc_draw(obj,x+edge-1,y0+1-oy)
@@ -219,6 +219,15 @@ function button:draw()
gc_draw(obj,x0+1,y0+1-oy)
gc_setColor(r*.55,g*.55,b*.55)
gc_draw(obj,x0,y0-oy)
+ else--if self.align=='M' then
+ local x0=x+w*.5
+ local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
+ gc_draw(obj,x0-1,y0-1,nil,kx,1,ox,oy)
+ gc_draw(obj,x0-1,y0+1,nil,kx,1,ox,oy)
+ gc_draw(obj,x0+1,y0-1,nil,kx,1,ox,oy)
+ gc_draw(obj,x0+1,y0+1,nil,kx,1,ox,oy)
+ gc_setColor(r*.55,g*.55,b*.55)
+ gc_draw(obj,x0,y0,nil,kx,1,ox,oy)
end
end
function button:getInfo()
@@ -290,13 +299,21 @@ local key={
type='key',
mustHaveText=true,
ATV=0,-- Activating time(0~4)
+ textAlreadyWrapped=false,---See button.setObject (line 146)
}
function key:reset()
self.ATV=0
end
function key:setObject(obj)
if type(obj)=='string' or type(obj)=='number' then
- self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
+ if match(obj,"\n") then
+ self.textAlreadyWrapped=true
+ self.obj=gc.newText(FONT.get(self.font,self.fType))
+ self.obj:addf(obj,self.w-self.edge*2,(self.align=='L' and 'left') or (self.align=='R' and 'right') or 'center')
+ else
+ self.textAlreadyWrapped=false
+ self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
+ end
elseif obj then
self.obj=obj
end
@@ -354,14 +371,15 @@ function key:draw()
-- Drawable
local obj=self.obj
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
+
gc_setColor(r,g,b)
- if align=='M' then
- local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
- gc_draw(obj,x+w*.5,y+h*.5,nil,kx,1,ox,oy)
- elseif align=='L' then
- gc_draw(obj,x+self.edge,y-oy+h*.5)
+ if align=='L' or self.textAlreadyWrapped then
+ gc_draw(obj,x+self.edge,y+h*.5-oy)
elseif align=='R' then
gc_draw(obj,x+w-self.edge-ox*2,y-oy+h*.5)
+ else--if align=='M' then
+ local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
+ gc_draw(obj,x+w*.5,y+h*.5,nil,kx,1,ox,oy)
end
end
function key:getInfo()
@@ -1382,10 +1400,13 @@ function WIDGET.setLang(widgetText)
t=W.name or "##"
W.color=COLOR.dV
end
- if type(t)=='string' and W.font then
- t=gc.newText(FONT.get(W.font),t)
+ if type(W.setObject)=='function' then
+ W:setObject(t)
+ elseif type(t)=='string' and W.font then
+ W.obj=gc.newText(FONT.get(W.font or 30),t)
+ else
+ W.obj=t
end
- W.obj=t
end
end
end
diff --git a/conf.lua b/conf.lua
index c0f3b86e..306f8e47 100644
--- a/conf.lua
+++ b/conf.lua
@@ -1,9 +1,9 @@
-local OS=love._os
-if OS=='OS X' then OS='macOS' end
-MOBILE=OS=='Android' or OS=='iOS'
-FNNS=OS:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol
+local system=love._os
+if system=='OS X' then system='macOS' end
+MOBILE=system=='Android' or system=='iOS'
+FNNS=system:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol
-if OS=='Web' then
+if system=='Web' then
local oldRead=love.filesystem.read
function love.filesystem.read(name,size)
if love.filesystem.getInfo(name) then
@@ -23,12 +23,13 @@ function love.conf(t)
local fileData=fs.read('conf/settings')
if fileData then
msaa=tonumber(fileData:match('"msaa":(%d+)')) or 0;
+ msaa=msaa==0 and 0 or 2*msaa
portrait=MOBILE and fileData:find('"portrait":true') and true
end
end
t.identity=identity -- Saving folder
- t.version="11.4"
+ t.version="11.5"
t.gammacorrect=false
t.appendidentity=true -- Search files in source then in save directory
t.accelerometerjoystick=false -- Accelerometer=joystick on ios/android
diff --git a/legals.md b/legals.md
index d4bdfe4a..614a0f7f 100644
--- a/legals.md
+++ b/legals.md
@@ -12,6 +12,8 @@ Lua is free software distributed under the terms of the MIT license. Copyright
json.lua is copyrighted by rxi. © 2022 rxi.
+discord-rpc.dll is copyrighted by Discord, Inc. © 2017 Discord, Inc.
+
IBM Plex is copyrighted by the International Business Machines Corporation. IBM and IBM Plex are trademarks of IBM Corp, registered in many jurisdictions worldwide. IBM Plex is licensed under the SIL Open Font License, Version 1.1.
diff --git a/main.lua b/main.lua
index e1be36d3..b4227891 100644
--- a/main.lua
+++ b/main.lua
@@ -49,6 +49,10 @@ SCR.setSize(1280,720) -- Initialize Screen size
BGM.setMaxSources(5)
VOC.setDiversion(.62)
+if SYSTEM == 'Web' and not WEB_COMPAT_MODE then
+ CLIPBOARD.setFreshInterval(.5)
+end
+
WIDGET.setOnChange(function()
if SCN.cur=='net_game' or SCN.cur=='custom_field' then return end
local colorList=THEME.getThemeColor()
@@ -294,39 +298,41 @@ IMG.init{
},
}
SKIN.load{
- {name="crystal_scf", path='media/image/skin/crystal_scf.png'},
- {name="matte_mrz", path='media/image/skin/matte_mrz.png'},
- {name="shiny_chno", path='media/image/skin/shiny_chno.png'},
- {name="contrast_mrz", path='media/image/skin/contrast_mrz.png'},
- {name="polkadots_scf", path='media/image/skin/polkadots_scf.png'},
- {name="toy_scf", path='media/image/skin/toy_scf.png'},
- {name="smooth_mrz", path='media/image/skin/smooth_mrz.png'},
- {name="simple_scf", path='media/image/skin/simple_scf.png'},
- {name="glass_scf", path='media/image/skin/glass_scf.png'},
- {name="penta_scf", path='media/image/skin/penta_scf.png'},
- {name="bubble_scf", path='media/image/skin/bubble_scf.png'},
- {name="minoes_scf", path='media/image/skin/minoes_scf.png'},
- {name="pure_mrz", path='media/image/skin/pure_mrz.png'},
- {name="bright_scf", path='media/image/skin/bright_scf.png'},
- {name="glow_mrz", path='media/image/skin/glow_mrz.png'},
- {name="plastic_mrz", path='media/image/skin/plastic_mrz.png'},
- {name="paper_mrz", path='media/image/skin/paper_mrz.png'},
- {name="yinyang_scf", path='media/image/skin/yinyang_scf.png'},
- {name="cartooncup_earety", path='media/image/skin/cartooncup_earety.png'},
- {name="jelly_miya", path='media/image/skin/jelly_miya.png'},
- {name="guidetris_xmiao_lusisi",path='media/image/skin/guidetris_xmiao_lusisi.png'},
- {name="brick_notypey", path='media/image/skin/brick_notypey.png'},
- {name="gem_notypey", path='media/image/skin/gem_notypey.png'},
- {name="classic", path='media/image/skin/classic_unknown.png'},
- {name="ball_shaw", path='media/image/skin/ball_shaw.png'},
- {name="retro_notypey", path='media/image/skin/retro_notypey.png'},
- {name="pixel_chno", path='media/image/skin/pixel_chno.png'},
- {name="pastel_chno", path='media/image/skin/pastel_chno.png'},
- {name="letters_chno", path='media/image/skin/letters_chno.png'},
- {name="kanji_chno", path='media/image/skin/kanji_chno.png'},
- {name="textbone_mrz", path='media/image/skin/textbone_mrz.png'},
- {name="coloredbone_mrz", path='media/image/skin/coloredbone_mrz.png'},
- {name="wtf", path='media/image/skin/wtf_mrz.png'},
+ {name="Crystal (Scf)", path='media/image/skin/scf/crystal.png'},
+ {name="Smooth (MrZ)", path='media/image/skin/mrz/smooth.png'},
+ {name="Matte (MrZ)", path='media/image/skin/mrz/matte.png'},
+ {name="Glass (Scf)", path='media/image/skin/scf/glass.png'},
+ {name="Jelly (Miya)", path='media/image/skin/miya/jelly.png'},
+ {name="Simple (Scf)", path='media/image/skin/scf/simple.png'},
+ {name="Contrast (MrZ)", path='media/image/skin/mrz/contrast.png'},
+ {name="Plastic (MrZ)", path='media/image/skin/mrz/plastic.png'},
+ {name="Glow (MrZ)", path='media/image/skin/mrz/glow.png'},
+ {name="Bright (Scf)", path='media/image/skin/scf/bright.png'},
+ {name="Penta (Scf)", path='media/image/skin/scf/penta.png'},
+ {name="Bubble (Scf)", path='media/image/skin/scf/bubble.png'},
+ {name="Pure (MrZ)", path='media/image/skin/mrz/pure.png'},
+ {name="Letters (CHNO)", path='media/image/skin/chno/letters.png'},
+ {name="Kanji (CHNO)", path='media/image/skin/chno/kanji.png'},
+ {name="Pastel (CHNO)", path='media/image/skin/chno/pastel.png'},
+ {name="Classic", path='media/image/skin/unknown/classic.png'},
+ {name="Arcade (Asriel)", path='media/image/skin/asriel/arcade.png'},
+ {name="Shiny (CHNO)", path='media/image/skin/chno/shiny.png'},
+ {name="Brick (Notypey)", path='media/image/skin/notypey/brick.png'},
+ {name="Cartooncup (Earety)", path='media/image/skin/earety/cartooncup.png'},
+ {name="Paper (MrZ)", path='media/image/skin/mrz/paper.png'},
+ {name="Toy (Scf)", path='media/image/skin/scf/toy.png'},
+ {name="Polkadots (Scf)", path='media/image/skin/scf/polkadots.png'},
+ {name="Yinyang (Scf)", path='media/image/skin/scf/yinyang.png'},
+ {name="Minoes (Scf)", path='media/image/skin/scf/minoes.png'},
+ {name="Cardboard (Asriel, slimenergy)", path='media/image/skin/asriel/cardboard.png'},
+ {name="Ball (Shaw)", path='media/image/skin/shaw/ball.png'},
+ {name="Gem (Notypey)", path='media/image/skin/notypey/gem.png'},
+ {name="Pixel (CHNO)", path='media/image/skin/chno/pixel.png'},
+ {name="Retro (Notypey)", path='media/image/skin/notypey/retro.png'},
+ {name="Guidetris (xmiao, lusisi)", path='media/image/skin/guidetris_xmiao_lusisi.png'},
+ {name="Textbone (MrZ)", path='media/image/skin/mrz/textbone.png'},
+ {name="Coloredbone (MrZ)", path='media/image/skin/mrz/coloredbone.png'},
+ {name="WTF (MrZ)", path='media/image/skin/mrz/wtf.png'},
}
-- Initialize sound libs
@@ -398,8 +404,12 @@ do
RANKS.rhythm_h=nil; fs.remove('record/rhythm_h.rec')
RANKS.rhythm_u=nil; fs.remove('record/rhythm_u.rec')
end
- if RANKS.bigbang then fs.remove('record/bigbang.rec') end
- if RANKS.clearRush then fs.remove('record/clearRush.rec') end
+ if RANKS.bigbang then RANKS.bigbang=nil; fs.remove('record/bigbang.rec') end
+ if RANKS.clearRush then RANKS.clearRush=nil; fs.remove('record/clearRush.rec') end
+ if RANKS.strategy_e then RANKS.strategy_e=nil; fs.remove('record/strategy_e.rec') end
+ if RANKS.strategy_h_plus then RANKS.strategy_h_plus=nil; fs.remove('record/strategy_h_plus.rec') end
+ if RANKS.strategy_u_plus then RANKS.strategy_u_plus=nil; fs.remove('record/strategy_u_plus.rec') end
+
if STAT.version<1715 then fs.remove('record/dig_quad_10l.rec') end
if STAT.version~=VERSION.code then
@@ -425,7 +435,8 @@ do
for _,v in next,SETTING.skin do if v<1 or v>17 then v=17 end end
if not RSlist[SETTING.RS] then SETTING.RS='TRS' end
if SETTING.ghostType=='greyCell' then SETTING.ghostType='grayCell' end
- if type(SETTING.skinSet)=='number' then SETTING.skinSet='crystal_scf' end
+ if type(SETTING.skinSet)=='number' then SETTING.skinSet='Crystal (Scf)' end
+ if string.find(SETTING.skinSet,"_") then SETTING.skinSet='Crystal (Scf)' end
if not TABLE.find({8,10,13,17,22,29,37,47,62,80,100},SETTING.frameMul) then SETTING.frameMul=100 end
if SETTING.cv then SETTING.vocPack,SETTING.cv=SETTING.cv end
if type(SETTING.bg)~='string' then SETTING.bg='on' end
@@ -433,6 +444,7 @@ do
if SETTING.reTime>3 or SETTING.reTime<.5 then SETTING.reTime=2 end
if SETTING.locale=='zh_full' then SETTING.locale='zh' end
if SETTING.vocPack=='rin' then SETTING.vocPack='miku' end
+ if SETTING.msaa>4 then SETTING.msaa=4 end
if RANKS.infinite then RANKS.infinite=0 end
if RANKS.infinite_dig then RANKS.infinite_dig=0 end
if not RANKS.sprint_10l then RANKS.sprint_10l=0 end
@@ -591,18 +603,22 @@ for _,fileName in next,fs.getDirectoryItems('replay') do
end
table.sort(REPLAY,function(a,b) return a.fileName>b.fileName end)
-AUTHURL="https://studio26f.org/oauth?product=techmino"
-AUTHHOST="cafuuchino1.3322.org:8081"
-WS.switchHost('cafuuchino1.3322.org','10026','/techmino/ws/v1')
-HTTP.setHost("cafuuchino1.3322.org:10026")
+AUTHURL="https://www.studio26f.org/oauth?product=techmino"
+AUTHHOST="www.studio26f.org:8080"
+WS.switchHost('www.studio26f.org','8081','/techmino/ws/v1')
+HTTP.setHost("www.studio26f.org:8081")
HTTP.setThreadCount(1)
+-- Discord RPC
+DiscordRPC=require'parts.discordRPC'
+DiscordRPC.update()
+
table.insert(_LOADTIMELIST_,("Load Resources: %.3fs"):format(TIME()-_LOADTIME_))
for i=1,#_LOADTIMELIST_ do LOG(_LOADTIMELIST_[i]) end
-- Launch testing task if launch param received
-if TABLE.find(arg,'-- test') then
+if TABLE.find(arg,'--test') then
TASK.new(function()
while not LOADED do coroutine.yield() end
diff --git a/media/image/skin/asriel/arcade.png b/media/image/skin/asriel/arcade.png
new file mode 100755
index 00000000..1af2600c
Binary files /dev/null and b/media/image/skin/asriel/arcade.png differ
diff --git a/media/image/skin/asriel/cardboard.png b/media/image/skin/asriel/cardboard.png
new file mode 100644
index 00000000..f0385efd
Binary files /dev/null and b/media/image/skin/asriel/cardboard.png differ
diff --git a/media/image/skin/kanji_chno.png b/media/image/skin/chno/kanji.png
similarity index 100%
rename from media/image/skin/kanji_chno.png
rename to media/image/skin/chno/kanji.png
diff --git a/media/image/skin/letters_chno.png b/media/image/skin/chno/letters.png
similarity index 100%
rename from media/image/skin/letters_chno.png
rename to media/image/skin/chno/letters.png
diff --git a/media/image/skin/pastel_chno.png b/media/image/skin/chno/pastel.png
similarity index 100%
rename from media/image/skin/pastel_chno.png
rename to media/image/skin/chno/pastel.png
diff --git a/media/image/skin/pixel_chno.png b/media/image/skin/chno/pixel.png
similarity index 100%
rename from media/image/skin/pixel_chno.png
rename to media/image/skin/chno/pixel.png
diff --git a/media/image/skin/shiny_chno.png b/media/image/skin/chno/shiny.png
similarity index 100%
rename from media/image/skin/shiny_chno.png
rename to media/image/skin/chno/shiny.png
diff --git a/media/image/skin/cartooncup_earety.png b/media/image/skin/earety/cartooncup.png
similarity index 100%
rename from media/image/skin/cartooncup_earety.png
rename to media/image/skin/earety/cartooncup.png
diff --git a/media/image/skin/jelly_miya.png b/media/image/skin/miya/jelly.png
similarity index 100%
rename from media/image/skin/jelly_miya.png
rename to media/image/skin/miya/jelly.png
diff --git a/media/image/skin/coloredbone_mrz.png b/media/image/skin/mrz/coloredbone.png
similarity index 100%
rename from media/image/skin/coloredbone_mrz.png
rename to media/image/skin/mrz/coloredbone.png
diff --git a/media/image/skin/contrast_mrz.png b/media/image/skin/mrz/contrast.png
similarity index 100%
rename from media/image/skin/contrast_mrz.png
rename to media/image/skin/mrz/contrast.png
diff --git a/media/image/skin/glow_mrz.png b/media/image/skin/mrz/glow.png
similarity index 100%
rename from media/image/skin/glow_mrz.png
rename to media/image/skin/mrz/glow.png
diff --git a/media/image/skin/matte_mrz.png b/media/image/skin/mrz/matte.png
similarity index 100%
rename from media/image/skin/matte_mrz.png
rename to media/image/skin/mrz/matte.png
diff --git a/media/image/skin/paper_mrz.png b/media/image/skin/mrz/paper.png
similarity index 100%
rename from media/image/skin/paper_mrz.png
rename to media/image/skin/mrz/paper.png
diff --git a/media/image/skin/plastic_mrz.png b/media/image/skin/mrz/plastic.png
similarity index 100%
rename from media/image/skin/plastic_mrz.png
rename to media/image/skin/mrz/plastic.png
diff --git a/media/image/skin/pure_mrz.png b/media/image/skin/mrz/pure.png
similarity index 100%
rename from media/image/skin/pure_mrz.png
rename to media/image/skin/mrz/pure.png
diff --git a/media/image/skin/smooth_mrz.png b/media/image/skin/mrz/smooth.png
similarity index 100%
rename from media/image/skin/smooth_mrz.png
rename to media/image/skin/mrz/smooth.png
diff --git a/media/image/skin/textbone_mrz.png b/media/image/skin/mrz/textbone.png
similarity index 100%
rename from media/image/skin/textbone_mrz.png
rename to media/image/skin/mrz/textbone.png
diff --git a/media/image/skin/wtf_mrz.png b/media/image/skin/mrz/wtf.png
similarity index 100%
rename from media/image/skin/wtf_mrz.png
rename to media/image/skin/mrz/wtf.png
diff --git a/media/image/skin/brick_notypey.png b/media/image/skin/notypey/brick.png
similarity index 100%
rename from media/image/skin/brick_notypey.png
rename to media/image/skin/notypey/brick.png
diff --git a/media/image/skin/gem_notypey.png b/media/image/skin/notypey/gem.png
similarity index 100%
rename from media/image/skin/gem_notypey.png
rename to media/image/skin/notypey/gem.png
diff --git a/media/image/skin/retro_notypey.png b/media/image/skin/notypey/retro.png
similarity index 100%
rename from media/image/skin/retro_notypey.png
rename to media/image/skin/notypey/retro.png
diff --git a/media/image/skin/bright_scf.png b/media/image/skin/scf/bright.png
similarity index 100%
rename from media/image/skin/bright_scf.png
rename to media/image/skin/scf/bright.png
diff --git a/media/image/skin/bubble_scf.png b/media/image/skin/scf/bubble.png
similarity index 100%
rename from media/image/skin/bubble_scf.png
rename to media/image/skin/scf/bubble.png
diff --git a/media/image/skin/crystal_scf.png b/media/image/skin/scf/crystal.png
similarity index 100%
rename from media/image/skin/crystal_scf.png
rename to media/image/skin/scf/crystal.png
diff --git a/media/image/skin/glass_scf.png b/media/image/skin/scf/glass.png
similarity index 100%
rename from media/image/skin/glass_scf.png
rename to media/image/skin/scf/glass.png
diff --git a/media/image/skin/minoes_scf.png b/media/image/skin/scf/minoes.png
similarity index 100%
rename from media/image/skin/minoes_scf.png
rename to media/image/skin/scf/minoes.png
diff --git a/media/image/skin/penta_scf.png b/media/image/skin/scf/penta.png
similarity index 100%
rename from media/image/skin/penta_scf.png
rename to media/image/skin/scf/penta.png
diff --git a/media/image/skin/polkadots_scf.png b/media/image/skin/scf/polkadots.png
similarity index 100%
rename from media/image/skin/polkadots_scf.png
rename to media/image/skin/scf/polkadots.png
diff --git a/media/image/skin/simple_scf.png b/media/image/skin/scf/simple.png
similarity index 100%
rename from media/image/skin/simple_scf.png
rename to media/image/skin/scf/simple.png
diff --git a/media/image/skin/toy_scf.png b/media/image/skin/scf/toy.png
similarity index 100%
rename from media/image/skin/toy_scf.png
rename to media/image/skin/scf/toy.png
diff --git a/media/image/skin/yinyang_scf.png b/media/image/skin/scf/yinyang.png
similarity index 100%
rename from media/image/skin/yinyang_scf.png
rename to media/image/skin/scf/yinyang.png
diff --git a/media/image/skin/ball_shaw.png b/media/image/skin/shaw/ball.png
similarity index 100%
rename from media/image/skin/ball_shaw.png
rename to media/image/skin/shaw/ball.png
diff --git a/media/image/skin/classic_unknown.png b/media/image/skin/unknown/classic.png
similarity index 100%
rename from media/image/skin/classic_unknown.png
rename to media/image/skin/unknown/classic.png
diff --git a/parts/char.lua b/parts/char.lua
index 3b623524..4cbd3dc0 100644
--- a/parts/char.lua
+++ b/parts/char.lua
@@ -330,20 +330,20 @@ local L={
},
cards={-- F0300 - F070F
cardBack= 0xF0300,
- clubA= 0xF0301,
- club2= 0xF0302,
- club3= 0xF0303,
- club4= 0xF0304,
- club5= 0xF0305,
- club6= 0xF0306,
- club7= 0xF0307,
- club8= 0xF0308,
- club9= 0xF0309,
- club10= 0xF030A,
- clubJ= 0xF030B,
- clubC= 0xF030C,
- clubQ= 0xF030D,
- clubK= 0xF030E,
+ spadeA= 0xF0301,
+ spade2= 0xF0302,
+ spade3= 0xF0303,
+ spade4= 0xF0304,
+ spade5= 0xF0305,
+ spade6= 0xF0306,
+ spade7= 0xF0307,
+ spade8= 0xF0308,
+ spade9= 0xF0309,
+ spade10= 0xF030A,
+ spadeJ= 0xF030B,
+ spadeC= 0xF030C,
+ spadeQ= 0xF030D,
+ spadeK= 0xF030E,
heartA= 0xF0401,
heart2= 0xF0402,
heart3= 0xF0403,
diff --git a/parts/data.lua b/parts/data.lua
index a035ea5f..987051a4 100644
--- a/parts/data.lua
+++ b/parts/data.lua
@@ -256,54 +256,34 @@ end
large value will be encoded as 1xxxxxxx(high)-1xxxxxxx-...-0xxxxxxx(low)
Example (decoded):
- 6,1, 20,-1, 0,2, 26,-2, 872,4, ...
+ 26,1, 42,-1, ...
This means:
- Press key1 at 6f
- Release key1 at 26f (6+20)
- Press key2 at the same time (26+0)
- Release key 2 after 26 frame (26+26)
- Press key 4 after 872 frame (52+872)
+ Press key1 at 26f
+ Release key1 at 42f
...
]]
function DATA.dumpRecording(list,ptr)
local out=""
local buffer=""
if not ptr then ptr=1 end
- local prevFrm=list[ptr-2] or 0
while list[ptr] do
- -- Flush buffer
- if #buffer>10 then
+ if #buffer>26 then
out=out..buffer
buffer=""
end
-
- -- Encode time
- local t=list[ptr]-prevFrm
- prevFrm=list[ptr]
- buffer=buffer.._encode(t)
-
- -- Encode event
- buffer=buffer.._encode(list[ptr+1])
-
- -- Step
- ptr=ptr+2
+ buffer=buffer.._encode(list[ptr])
+ ptr=ptr+1
end
return out..buffer,ptr
end
function DATA.pumpRecording(str,L)
local len=#str
local p=1
+ local data
- local curFrm=L[#L-1] or 0
while p<=len do
- local code,event
- -- Read delta time
- code,p=_decode(str,p)
- curFrm=curFrm+code
- ins(L,curFrm)
-
- event,p=_decode(str,p)
- ins(L,event)
+ data,p=_decode(str,p)
+ ins(L,data)
end
end
do-- function DATA.saveReplay()
diff --git a/parts/discordRPC.lua b/parts/discordRPC.lua
new file mode 100644
index 00000000..fa16caac
--- /dev/null
+++ b/parts/discordRPC.lua
@@ -0,0 +1,331 @@
+if SYSTEM=='Web' then
+ return {update=NULL}
+end
+
+local appId='1288557386700951554'
+
+local ffi=require"ffi"
+
+local RPC_C
+if SYSTEM=='Windows' then
+ local suc
+ suc,RPC_C=pcall(ffi.load,"discord-rpc")
+ if not (suc and RPC_C) then
+ print("Failed to load Discord-RPC lib",RPC_C)
+ MES.new('error',"Failed to load Discord-RPC lib")
+ RPC_C=nil
+ end
+end
+
+local RPC
+if RPC_C then
+ RPC={}
+ ffi.cdef[[
+ typedef struct DiscordRichPresence {
+ const char* state; /* max 128 bytes */
+ const char* details; /* max 128 bytes */
+ int64_t startTimestamp;
+ int64_t endTimestamp;
+ const char* largeImageKey; /* max 32 bytes */
+ const char* largeImageText; /* max 128 bytes */
+ const char* smallImageKey; /* max 32 bytes */
+ const char* smallImageText; /* max 128 bytes */
+ const char* partyId; /* max 128 bytes */
+ int partySize;
+ int partyMax;
+ const char* matchSecret; /* max 128 bytes */
+ const char* joinSecret; /* max 128 bytes */
+ const char* spectateSecret; /* max 128 bytes */
+ int8_t instance;
+ } DiscordRichPresence;
+
+ typedef struct DiscordUser {
+ const char* userId;
+ const char* username;
+ const char* discriminator;
+ const char* avatar;
+ } DiscordUser;
+
+ typedef void (*readyPtr)(const DiscordUser* request);
+ typedef void (*disconnectedPtr)(int errorCode, const char* message);
+ typedef void (*erroredPtr)(int errorCode, const char* message);
+ typedef void (*joinGamePtr)(const char* joinSecret);
+ typedef void (*spectateGamePtr)(const char* spectateSecret);
+ typedef void (*joinRequestPtr)(const DiscordUser* request);
+
+ typedef struct DiscordEventHandlers {
+ readyPtr ready;
+ disconnectedPtr disconnected;
+ erroredPtr errored;
+ joinGamePtr joinGame;
+ spectateGamePtr spectateGame;
+ joinRequestPtr joinRequest;
+ } DiscordEventHandlers;
+
+ void Discord_Initialize(const char* applicationId,
+ DiscordEventHandlers* handlers,
+ int autoRegister,
+ const char* optionalSteamId);
+ void Discord_Shutdown(void);
+ void Discord_RunCallbacks(void);
+ void Discord_UpdatePresence(const DiscordRichPresence* presence);
+ void Discord_ClearPresence(void);
+ void Discord_Respond(const char* userid, int reply);
+ void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
+ ]]
+
+ local function unpackDiscordUser(request)
+ return ffi.string(request.userId),ffi.string(request.username),
+ ffi.string(request.discriminator),ffi.string(request.avatar)
+ end
+
+ -- callback proxies
+ -- note: callbacks are not JIT compiled (= SLOW), try to avoid doing performance critical tasks in them
+ -- luajit.org/ext_ffi_semantics.html
+ local ready_proxy=ffi.cast("readyPtr",function(request)
+ if RPC.ready then
+ RPC.ready(unpackDiscordUser(request))
+ end
+ end)
+
+ local disconnected_proxy=ffi.cast("disconnectedPtr",function(errorCode,message)
+ if RPC.disconnected then
+ RPC.disconnected(errorCode,ffi.string(message))
+ end
+ end)
+
+ local errored_proxy=ffi.cast("erroredPtr",function(errorCode,message)
+ if RPC.errored then
+ RPC.errored(errorCode,ffi.string(message))
+ end
+ end)
+
+ local joinGame_proxy=ffi.cast("joinGamePtr",function(joinSecret)
+ if RPC.joinGame then
+ RPC.joinGame(ffi.string(joinSecret))
+ end
+ end)
+
+ local spectateGame_proxy=ffi.cast("spectateGamePtr",function(spectateSecret)
+ if RPC.spectateGame then
+ RPC.spectateGame(ffi.string(spectateSecret))
+ end
+ end)
+
+ local joinRequest_proxy=ffi.cast("joinRequestPtr",function(request)
+ if RPC.joinRequest then
+ RPC.joinRequest(unpackDiscordUser(request))
+ end
+ end)
+
+ -- helpers
+ local function checkArg(arg,argType,argName,func,maybeNil)
+ assert(type(arg)==argType or (maybeNil and arg==nil),
+ string.format("Argument \"%s\" to function \"%s\" has to be of type \"%s\"",
+ argName,func,argType))
+ end
+
+ local function checkStrArg(arg,maxLen,argName,func,maybeNil)
+ if maxLen then
+ assert(type(arg)=="string" and arg:len()<=maxLen or (maybeNil and arg==nil),
+ string.format("Argument \"%s\" of function \"%s\" has to be of type string with maximum length %d",
+ argName,func,maxLen))
+ else
+ checkArg(arg,"string",argName,func,true)
+ end
+ end
+
+ local function checkIntArg(arg,maxBits,argName,func,maybeNil)
+ maxBits=math.min(maxBits or 32,52) -- lua number (double) can only store integers < 2^53
+ local maxVal=2^(maxBits-1) -- assuming signed integers, which, for now, are the only ones in use
+ assert(type(arg)=="number" and math.floor(arg)==arg
+ and arg=-maxVal
+ or (maybeNil and arg==nil),
+ string.format("Argument \"%s\" of function \"%s\" has to be a whole number <= %d",
+ argName,func,maxVal))
+ end
+
+ -- function wrappers
+ function RPC.initialize(applicationId,autoRegister,optionalSteamId)
+ local func="discordRPC.Initialize"
+ checkStrArg(applicationId,nil,"applicationId",func)
+ checkArg(autoRegister,"boolean","autoRegister",func)
+ if optionalSteamId~=nil then
+ checkStrArg(optionalSteamId,nil,"optionalSteamId",func)
+ end
+
+ local eventHandlers=ffi.new("struct DiscordEventHandlers")
+ eventHandlers.ready=ready_proxy
+ eventHandlers.disconnected=disconnected_proxy
+ eventHandlers.errored=errored_proxy
+ eventHandlers.joinGame=joinGame_proxy
+ eventHandlers.spectateGame=spectateGame_proxy
+ eventHandlers.joinRequest=joinRequest_proxy
+
+ RPC_C.Discord_Initialize(applicationId,eventHandlers,
+ autoRegister and 1 or 0,optionalSteamId)
+ end
+
+ function RPC.shutdown()
+ RPC_C.Discord_Shutdown()
+ end
+
+ function RPC.runCallbacks()
+ RPC_C.Discord_RunCallbacks()
+ end
+ -- http://luajit.org/ext_ffi_semantics.html#callback :
+ -- It is not allowed, to let an FFI call into a C function (runCallbacks)
+ -- get JIT-compiled, which in turn calls a callback, calling into Lua again (e.g. discordRPC.ready).
+ -- Usually this attempt is caught by the interpreter first and the C function
+ -- is blacklisted for compilation.
+ -- solution:
+ -- "Then you'll need to manually turn off JIT-compilation with jit.off() for
+ -- the surrounding Lua function that invokes such a message polling function."
+ jit.off(RPC.runCallbacks)
+
+ function RPC.updatePresence(presence)
+ local func="discordRPC.updatePresence"
+ checkArg(presence,"table","presence",func)
+
+ -- -1 for string length because of 0-termination
+ checkStrArg(presence.state,127,"presence.state",func,true)
+ checkStrArg(presence.details,127,"presence.details",func,true)
+
+ checkIntArg(presence.startTimestamp,64,"presence.startTimestamp",func,true)
+ checkIntArg(presence.endTimestamp,64,"presence.endTimestamp",func,true)
+
+ checkStrArg(presence.largeImageKey,31,"presence.largeImageKey",func,true)
+ checkStrArg(presence.largeImageText,127,"presence.largeImageText",func,true)
+ checkStrArg(presence.smallImageKey,31,"presence.smallImageKey",func,true)
+ checkStrArg(presence.smallImageText,127,"presence.smallImageText",func,true)
+ checkStrArg(presence.partyId,127,"presence.partyId",func,true)
+
+ checkIntArg(presence.partySize,32,"presence.partySize",func,true)
+ checkIntArg(presence.partyMax,32,"presence.partyMax",func,true)
+
+ checkStrArg(presence.matchSecret,127,"presence.matchSecret",func,true)
+ checkStrArg(presence.joinSecret,127,"presence.joinSecret",func,true)
+ checkStrArg(presence.spectateSecret,127,"presence.spectateSecret",func,true)
+
+ checkIntArg(presence.instance,8,"presence.instance",func,true)
+
+ local cpresence=ffi.new("struct DiscordRichPresence")
+ cpresence.state=presence.state
+ cpresence.details=presence.details
+ cpresence.startTimestamp=presence.startTimestamp or 0
+ cpresence.endTimestamp=presence.endTimestamp or 0
+ cpresence.largeImageKey=presence.largeImageKey
+ cpresence.largeImageText=presence.largeImageText
+ cpresence.smallImageKey=presence.smallImageKey
+ cpresence.smallImageText=presence.smallImageText
+ cpresence.partyId=presence.partyId
+ cpresence.partySize=presence.partySize or 0
+ cpresence.partyMax=presence.partyMax or 0
+ cpresence.matchSecret=presence.matchSecret
+ cpresence.joinSecret=presence.joinSecret
+ cpresence.spectateSecret=presence.spectateSecret
+ cpresence.instance=presence.instance or 0
+
+ RPC_C.Discord_UpdatePresence(cpresence)
+ end
+
+ function RPC.clearPresence()
+ RPC_C.Discord_ClearPresence()
+ end
+
+ local replyMap={
+ no=0,
+ yes=1,
+ ignore=2,
+ }
+
+ -- maybe let reply take ints too (0, 1, 2) and add constants to the module
+ function RPC.respond(userId,reply)
+ checkStrArg(userId,nil,"userId","discordRPC.respond")
+ assert(replyMap[reply],"Argument 'reply' to discordRPC.respond must be 'yes'|'no'|'ignore'")
+ RPC_C.Discord_Respond(userId,replyMap[reply])
+ end
+
+ -- garbage collection callback
+ RPC.gcDummy=newproxy(true)
+ getmetatable(RPC.gcDummy).__gc=function()
+ RPC.shutdown()
+ ready_proxy:free()
+ disconnected_proxy:free()
+ errored_proxy:free()
+ joinGame_proxy:free()
+ spectateGame_proxy:free()
+ joinRequest_proxy:free()
+ end
+
+ function RPC.ready(userId,username,discriminator,avatar)
+ print(string.format("Discord: ready (%s,%s,%s,%s)",userId,username,discriminator,avatar))
+ end
+ function RPC.disconnected(errorCode,message)
+ print(string.format("Discord: disconnected (%d: %s)",errorCode,message))
+ end
+ function RPC.errored(errorCode,message)
+ print(string.format("Discord: error (%d: %s)",errorCode,message))
+ end
+ function RPC.joinGame(joinSecret)
+ print(string.format("Discord: join (%s)",joinSecret))
+ end
+ function RPC.spectateGame(spectateSecret)
+ print(string.format("Discord: spectate (%s)",spectateSecret))
+ end
+ function RPC.joinRequest(userId,username,discriminator,avatar)
+ print(string.format("Discord: join request (%s,%s,%s,%s)",userId,username,discriminator,avatar))
+ RPC.respond(userId,'yes')
+ end
+ RPC.initialize(appId,true)
+end
+
+local MyRPC={
+ C=RPC_C,
+ RPC=RPC,
+ presence={
+ startTimestamp=os.time(),
+ state="Loading...",
+ details="",
+ largeImageKey='',
+ largeImageText="Techmino",
+ smallImageKey='',
+ smallImageText="",
+ },
+}
+
+---@class DiscordRPC.presence
+---@field state? string
+---@field details? string
+---@field startTimestamp? number
+---@field endTimestamp? number
+---@field largeImageKey? string
+---@field largeImageText? string
+---@field smallImageKey? string
+---@field smallImageText? string
+---@field partyId? string
+---@field partySize? number
+---@field partyMax? number
+---@field matchSecret? string
+---@field joinSecret? string
+---@field spectateSecret? string
+---@field instance? number
+
+---@overload fun()
+---@overload fun(state: DiscordRPC.presence)
+---@param state string
+---@param details string
+function MyRPC.update(state,details)
+ if state then
+ for k,v in next,
+ type(state)=='string'
+ and {state=state,details=details}
+ or state
+ do
+ MyRPC.presence[k]=v
+ end
+ end
+ if RPC then RPC.updatePresence(MyRPC.presence) end
+end
+
+return MyRPC
diff --git a/parts/eventsets/classic_e.lua b/parts/eventsets/classic_e.lua
index 98061047..7913e843 100644
--- a/parts/eventsets/classic_e.lua
+++ b/parts/eventsets/classic_e.lua
@@ -26,7 +26,7 @@ end
return {
das=16,arr=6,
sddas=6,sdarr=6,
- irs=false,ims=false,
+ logicalIRS=false,logicalIMS=false,
drop=6,lock=6,
wait=10,fall=25,
freshLimit=0,
diff --git a/parts/eventsets/classic_h.lua b/parts/eventsets/classic_h.lua
index 0cd353e5..83fb3196 100644
--- a/parts/eventsets/classic_h.lua
+++ b/parts/eventsets/classic_h.lua
@@ -26,7 +26,7 @@ end
return {
das=16,arr=6,
sddas=3,sdarr=3,
- irs=false,ims=false,
+ logicalIRS=false,logicalIMS=false,
drop=3,lock=3,
wait=10,fall=25,
freshLimit=0,
diff --git a/parts/eventsets/classic_l.lua b/parts/eventsets/classic_l.lua
index 1b603412..893972bd 100644
--- a/parts/eventsets/classic_l.lua
+++ b/parts/eventsets/classic_l.lua
@@ -26,7 +26,7 @@ end
return {
das=16,arr=6,
sddas=2,sdarr=2,
- irs=false,ims=false,
+ logicalIRS=false,logicalIMS=false,
drop=2,lock=2,
wait=10,fall=25,
freshLimit=0,
diff --git a/parts/eventsets/classic_u.lua b/parts/eventsets/classic_u.lua
index f6c9d14e..72cfc184 100644
--- a/parts/eventsets/classic_u.lua
+++ b/parts/eventsets/classic_u.lua
@@ -7,7 +7,7 @@ end
return {
das=16,arr=6,
sddas=1,sdarr=1,
- irs=false,ims=false,
+ logicalIRS=false,logicalIMS=false,
drop=1,lock=1,
wait=10,fall=25,
freshLimit=0,
diff --git a/parts/eventsets/master_g.lua b/parts/eventsets/master_g.lua
index 1f869da5..2fcc12b8 100644
--- a/parts/eventsets/master_g.lua
+++ b/parts/eventsets/master_g.lua
@@ -149,7 +149,7 @@ return {
keyCancel={10,11,12,14,15,16,17,18,19,20},
das=16,arr=1,
minsdarr=1,
- ihs=true,irs=true,ims=false,
+ logicalIRS=true,logicalIHS=true,logicalIMS=false,
mesDisp=function(P)
local D=P.modeData
GC.setColor(1,1,1,1)
diff --git a/parts/fonts/monospaced.otf b/parts/fonts/monospaced.otf
index 95ee3761..4c188a3e 100644
Binary files a/parts/fonts/monospaced.otf and b/parts/fonts/monospaced.otf differ
diff --git a/parts/gameFuncs.lua b/parts/gameFuncs.lua
index 4492901e..1cd9373e 100644
--- a/parts/gameFuncs.lua
+++ b/parts/gameFuncs.lua
@@ -161,12 +161,12 @@ do-- function applySettings()
if SETTING.bg=='on' then
BG.unlock()
BG.setDefault(SETTING.defaultBG)
+ BG.set()
if SETTING.lockBG then
BG.lock()
- elseif reason=='lockBG' then -- Don't load theme too soon!
+ elseif reason=='lockBG' then -- We only reload theme again when at settings scene.
THEME.set(THEME.calculate(),GAME.playing)
end
- BG.set()
elseif SETTING.bg=='off' then
BG.unlock()
BG.set('fixColor',SETTING.bgAlpha,SETTING.bgAlpha,SETTING.bgAlpha)
@@ -973,7 +973,7 @@ end
do-- function dumpBasicConfig()
local gameSetting={
-- Tuning
- 'das','arr','dascut','dropcut','sddas','sdarr',
+ 'das','arr','dascut','irscut','dropcut','sddas','sdarr',
'ihs','irs','ims','RS',
-- System
@@ -1024,7 +1024,7 @@ do-- function resetGameData(args)
end
local gameSetting={
-- Tuning
- 'das','arr','dascut','dropcut','sddas','sdarr',
+ 'das','arr','dascut','irscut','dropcut','sddas','sdarr',
'ihs','irs','ims','RS',
-- System
@@ -1054,6 +1054,8 @@ do-- function resetGameData(args)
GAME.rank=0
GAME.warnLVL0=0
GAME.warnLVL=0
+ GAME.pauseCount=0
+ GAME.pauseTime=0
if args:find'r' then
GAME.frameStart=0
GAME.recording=false
@@ -1061,8 +1063,6 @@ do-- function resetGameData(args)
else
GAME.frameStart=args:find'n' and 0 or 180-SETTING.reTime*60
GAME.seed=seed or math.random(1046101471)
- GAME.pauseTime=0
- GAME.pauseCount=0
GAME.saved=false
GAME.setting=_copyGameSetting()
GAME.tasUsed=false
@@ -1239,7 +1239,7 @@ do-- function pressKey(k)
end
do-- SETXXX(k) & ROOMXXX(k)
local warnList={
- 'das','arr','dascut','dropcut','sddas','sdarr',
+ 'das','arr','dascut','irscut','dropcut','sddas','sdarr',
'ihs','irs','ims','RS',
'frameMul','highCam',
'VKSwitch','VKIcon','VKTrack','VKDodge',
diff --git a/parts/gameTables.lua b/parts/gameTables.lua
index d37d64c6..a28dbbd1 100644
--- a/parts/gameTables.lua
+++ b/parts/gameTables.lua
@@ -635,7 +635,7 @@ do-- Userdata tables
SETTING={-- Settings
-- Tuning
das=10,arr=2,
- dascut=0,dropcut=0,
+ dascut=0,irscut=6,dropcut=0,
sddas=0,sdarr=2,
ihs=true,irs=true,ims=true,
holdMode='hold',
@@ -653,7 +653,7 @@ do-- Userdata tables
maxFPS=60,
frameMul=100,
locale='zh',
- skinSet='crystal_scf',
+ skinSet='Crystal (Scf)',
skin={
1,7,11,3,14,4,9,
1,7,2,6,10,2,13,5,9,15,4,11,3,12,2,16,8,4,
diff --git a/parts/language/dict_en.lua b/parts/language/dict_en.lua
index 213f114a..74a4ae71 100644
--- a/parts/language/dict_en.lua
+++ b/parts/language/dict_en.lua
@@ -30,11 +30,11 @@ return {
"The official website of Techmino!\nYou can download the latest stable build of Techmino and change your profile there.\nClick on the globe icon to open the website in your browser.",
"http://studio26f.org",
},
- {"Huiji Wiki",
- "huiji wiki",
+ {"Chinese Tetris Wiki",
+ "china tetris wiki chinese tetris wiki",
"help",
- "(灰机wiki)\nA Chinese Tetris wiki by Tetris enthusiasts from Chinese Tetris Research Community groups and affiliates. Most pages have been referenced and translated from Hard Drop Wiki and Tetris Wiki for now. Link in Simplified Chinese.",
- "https://tetris.huijiwiki.com",
+ "A Chinese Tetris wiki by Tetris enthusiasts from Chinese Tetris Study Community groups and affiliates. Most pages have been referenced and translated from Hard Drop Wiki and Tetris Wiki for now. Link in Simplified Chinese.",
+ "http://tetriswiki.cn",
},
{"Hard Drop Wiki",
"harddrop hd wiki",
@@ -865,6 +865,11 @@ FNNS and {"Support 3",
"term",
"A special delay applied to DAS when a new block is spawned. When this happens, a small delay is added before the DAS starts timing, so that a piece doesn't start moving immediately when a sideways direction key is pressed.\nOther games may have similar mechanisms, but they may work differently.",
},
+ {"IRS cut",
+ "irscut icd",
+ "term",
+ "A special delay applied to IRS when a new block is spawned. When entry delay is disabled, this will delay IRS from being applied, allowing you to release the rotation button in the period to avoid a misdrop.",
+ },
{"Auto-lock cut",
"autolockcut mdcut",
"term",
diff --git a/parts/language/dict_ja.lua b/parts/language/dict_ja.lua
index 00aebf9d..ce836efc 100644
--- a/parts/language/dict_ja.lua
+++ b/parts/language/dict_ja.lua
@@ -29,12 +29,12 @@ return {
"Techminoの公式ホームページです!\n最新の安定版Techminoをダウンロードしたり、プロフィールを編集したりできます\n地球儀ボタンから是非アクセスしてください",
"http://studio26f.org",
},
- {"灰机wiki",
- "huiji wiki ウィキ うぃき 灰机 フイジ",
- "help",
- "huiji wiki\n\n中国のテトリス研究グループとそのサブグループに所属しているテトリスプレーヤー達が管理している中国のテトリスwikiです\n現在、大部分のページがHard drop wikiとTetris wikiから参照、翻訳されたページになっています",
- "https://tetris.huijiwiki.com",
- },
+ -- {"Chinese Tetris Wiki",
+ -- "china tetris wiki",
+ -- "help",
+ -- "A Chinese Tetris wiki by Tetris enthusiasts from Chinese Tetris Research Community groups and affiliates. Most pages have been referenced and translated from Hard Drop Wiki and Tetris Wiki for now. Link in Simplified Chinese.",
+ -- "http://tetriswiki.cn",
+ -- },
{"HardDrop wiki",
"harddrop hd wiki ハードドロップ ハードロ ウィキ うぃき",
"help",
@@ -961,6 +961,11 @@ FNNS and {"サポート3",
"term",
"*Techmino用語*通常、ミノが出現する前にDAS時間以上入力をしているとミノが出現した瞬間に動き出します\nDASカットはこのような現象を減らすためにDAS時間以上入力していても出現時にDASカット分減算する機能です\n他のゲームにも似たようなものがありますが恐らく異なるでしょう",
},
+ -- {"IRS cut",
+ -- "irscut icd",
+ -- "term",
+ -- "A special delay applied to IRS when a new block is spawned. When entry delay is disabled, this will delay IRS from being applied, allowing you to release the rotation button in the period to avoid a misdrop.",
+ -- },
{"Auto-lock cut(自動設置カット)",
"autolockcut mdcut 自動 カット",
"term",
diff --git a/parts/language/dict_vi.lua b/parts/language/dict_vi.lua
index 6bb54c31..9772a38f 100644
--- a/parts/language/dict_vi.lua
+++ b/parts/language/dict_vi.lua
@@ -42,7 +42,7 @@ Bạn muốn đóng góp vào bản dịch? Bạn có thể vào trang dự án
05B. Hệ thống xoay gạch: ARS, ASC, ASC+, BRS, BiRS, C2RS, C2sym, NRS, SRS, SRS+, TRS, XRS
05C. Hệ thống điều khiển: IRS, IHS, IMS
05D. Cách kiểu xáo gạch: Túi 7 gạch, His, EZ-Start, Reverb, C2
- (và vấn đề Drought của một vài kiểu xáo)
+ (và hiện tượng Drought của một vài kiểu xáo)
05E. Thông số
05E1. Thông số của game:
@@ -50,7 +50,7 @@ Bạn muốn đóng góp vào bản dịch? Bạn có thể vào trang dự án
- ARE, Line ARE, Death ARE
- Lockdown Delay, Spawn & Clear delay
05E2. Thông số điều khiển:
- DAS & ARR, DAS cut, Auto-lock cut, SDF
+ DAS & ARR, DAS cut, Auto-lock cut, IRS cut, SDF
05F. Điều khiển
05F1. Tốc độ: LPM, PPS, BPM, KPM, KPP
05F2. Kỹ thuật: Hypertapping, Rolling, Finesse
@@ -77,7 +77,7 @@ Bạn muốn đóng góp vào bản dịch? Bạn có thể vào trang dự án
08. Bot: Cold Clear, ZZZbot
09. Wiki; các trang web bày setup & cung cấp câu đố, chia sẻ setup
- 09A. Wiki: Huiji Wiki, Wiki Hard Drop, tetris.wiki, Tetris Wiki Fandom
+ 09A. Wiki: Chinese Tetris Wiki, Wiki Hard Drop, tetris.wiki, Tetris Wiki Fandom
09B. Bày setup: Four.lol, Tetris Hall, Tetris Template Collections, tetristemplate.info, 4-Wide Trainer
09C. Chia sẻ câu đố: TTT, TTPC, NAZO, TPO
09D. Chia sẻ setup: Fumen, Fumen bản Điện thoại
@@ -272,7 +272,7 @@ Khái niệm về trò chơi Tetris hay trò chơi xếp gạch "hiện đại"
Nói chung, một game xếp gạch hiện đại thường sẽ bám sát theo Tetris Design Guideline (Bộ nguyên tắc thiết kế cho một game Tetris). Game nào thỏa mãn đa số các tiêu chí dưới đây có thể được coi là game xếp gạch hiện đại.
1. Phần có thể nhìn thấy được của bảng có kích thước 10 cột × 20 hàng, cùng với 2 - 3 hàng ẩn ở trên cùng. (Kích thước bảng thực tế ở trong mã nguồn game thường cố định ở 10 cột × 40 hàng).
- 2. Gạch mới xuất hiện ở giữa trên cùng của vùng có thể nhìn thấy (thường là ở hàng 21-22). Mỗi gạch đều có màu sắc và hướng xuất hiện mặc định riêng. Với những gạch có chiều dài lẻ có thể lệch sang trái hoặc phải 1 ô.
+ 2. Gạch mới xuất hiện ở giữa trên cùng của vùng có thể nhìn thấy (thường là ở hàng 21-22). Mỗi gạch đều có màu sắc và hướng xuất hiện mặc định riêng. Với những gạch có chiều rộng là số lẻ (Z, S, J, L, T) có thể lệch sang trái hoặc phải 1 ô khi xuất hiện.
3. Có một bộ xáo gạch như 7-Bag hay His được thiết kế để giảm hoặc tránh tình trạng Flood hay Drought.
4. Có một hệ thống xoay, và cho phép xoay theo ít nhất 2 hướng. Ưu tiên hệ thống xoay SRS hoặc các biến thể tương tự.
5. Có hệ thống chờ khóa gạch thích hợp.
@@ -286,25 +286,25 @@ Nói chung, một game xếp gạch hiện đại thường sẽ bám sát theo
{"Next (Kế / Tiếp)",
"nhom05 preview",
"term",
- "Là một hàng dùng để hiện chuỗi gạch sẽ lần lượt xuất hiện. Có một kỹ năng cần thiết đó là lên kế hoạch trước cách đặt các gạch từ hàng NEXT. Số lượng gạch bạn muốn lên kế hoạch là tùy thuộc vào bạn và có thể thay đổi tùy theo chế độ chơi và tình trạng bảng chơi hiện tại của bạn.",
+ "Là một hàng dùng để hiện chuỗi gạch sẽ lần lượt xuất hiện.\n\nCó một kỹ năng cần thiết đó là lên kế hoạch trước cách đặt các gạch từ hàng NEXT. Số lượng gạch bạn muốn lên kế hoạch là tùy thuộc vào bạn và có thể thay đổi tùy theo chế độ chơi và tình trạng bảng chơi hiện tại của bạn.",
},
{"Hold (Giữ/Trữ/Cất)",
"nhom05",
"term",
- "Một chức năng cho phép bạn sử dụng gạch ở trong ô HOLD\n(hoặc gạch đầu tiên ở hàng NEXT nếu bạn chưa cất gạch trước đó)\nvà cất gạch đang rơi vào ô HOLD \n\nBình thường, Hold chỉ có thể được sử dụng 1 lần cho mỗi gạch.\n\nTrên thực tế, việc dùng Hold hay không cũng có ưu nhược của nó.\nNếu không dùng Hold:\n\t- Có thể giảm áp lực cho người chơi khi điều khiển gạch.\n\t- Đồng thời có thể giảm số phím cần nhấn trong game → có thể tăng KPS lên.\nTrên thực tế, đã có nhiều kỷ lục 40L được xác lập mà không cần Hold.\n\nNếu dùng Hold:\n\t- Hold có thể có ích trong nhiều trường hợp khác nhau (ví dụ như khi đang chơi ở tốc độ rơi cao).\n\t- Cho phép người chơi có thể làm được nhiều setup phức tạp hơn mà không đẩy thêm áp lực cho người chơi."
+ "Một chức năng cho phép bạn sử dụng gạch ở trong ô HOLD và cất gạch đang rơi vào ô HOLD (hoặc cất gạch hiện tại vào HOLD và sử dụng gạch ở ô đầu tiên trong hàng NEXT, nếu như chưa có gạch nào trong ô HOLD)\n\nBình thường, Hold chỉ có thể được sử dụng 1 lần cho mỗi gạch.\n\nTrên thực tế, việc dùng Hold hay không cũng có ưu nhược của nó.\nNếu không dùng Hold:\n\t- Có thể giảm áp lực cho người chơi khi điều khiển gạch.\n\t- Đồng thời có thể giảm số phím cần nhấn trong game → có thể tăng KPS lên.\nTrên thực tế, đã có nhiều kỷ lục 40L được xác lập mà không cần Hold.\n\nNếu dùng Hold:\n\t- Hold có thể có ích trong nhiều trường hợp khác nhau (ví dụ như khi đang chơi ở tốc độ rơi cao).\n\t- Cho phép người chơi có thể làm được nhiều setup phức tạp hơn mà không đẩy thêm áp lực cho người chơi."
},
{"Hold tại chỗ",
"nhom05 physicalhold physics inplacehold",
"term",
- "*Chỉ có trên Techmino*\n\"Giữ ngay tại chỗ\".\n\nMột kiểu Hold đặc biệt cho phép gạch được lấy ra từ HOLD sẽ xuất hiện ngay tại vị trí mà gạch hiện tại đang rơi (khác với Hold thông thường khi mà gạch sẽ xuất hiện ở trên cùng của bảng).\nBạn có thể bật chức năng này trong Chế độ tự do.\n\nFun fact: người Trung gọi cái này là \"Physical Hold\"",
+ "*Chỉ có trên Techmino*\n\"Giữ ngay tại chỗ\".\n\nMột kiểu Hold đặc biệt cho phép gạch được lấy ra từ ô HOLD sẽ xuất hiện ngay tại vị trí mà gạch hiện tại đang rơi (khác với Hold thông thường khi mà gạch sẽ xuất hiện ở trên cùng của bảng).\nBạn có thể bật chức năng này trong Chế độ tự do.\n\nFun fact: người Trung gọi cái này là \"Physical Hold\"",
},
{"Swap (Chuyển)",
"nhom05 hold",
"term",
"Một biến thể khác của \"Hold\". Swap sẽ đổi gạch đang rơi với gạch tiếp theo trong NEXT. Bạn có thể bật chức năng này trong Chế độ tự do.",
},
- {"Topping out",
- "nhom05 topout toppingout game over",
+ {"Game over",
+ "nhom05 topout toppingout",
"term",
[[
Một tựa game xếp gạch hiện đại thường có 3 điều kiện để "game over":
@@ -319,7 +319,7 @@ Techmino mặc định sẽ không kiểm tra điều kiện Lock out và Top ou
{"Vùng đệm",
"nhom05 invisible buffer zone",
"term",
- "Tên tiếng Anh là \"Buffer Zone\". Chỉ bao gồm các hàng từ hàng 21-40 (nằm ở phía trên vùng nhìn thấy).\n\nTồn tại vùng này là vì sẽ có trường hợp hàng rác sẽ đẩy gạch trong bảng ra khỏi vùng nhìn thấy (dễ thấy nhất là Center 4-Wide).\nNhững ô gạch nào đi ra khỏi vùng nhìn thấy được sẽ đi vào vùng đệm và sẽ xuất hiện lại trong vùng nhìn thấy nếu bạn đã xóa đủ hàng.\n\nVùng đệm thường cao 20 ô (thường là do bảng đã bị cố định kích thước ở trong các dòng code), nhưng có game có vùng này cao vô hạn (ví dụ như trong chính Techmino luôn, khi bảng có thể mở rộng kích thước của nó).\n\nCác bạn có thể tìm hiểu thêm ở mục \"Vùng biến mất\".",
+ "Tên tiếng Anh: \"Buffer Zone\". Chỉ bao gồm các hàng từ hàng 21-40 (nằm ở phía trên vùng nhìn thấy).\n\nTồn tại vùng này là vì sẽ có trường hợp hàng rác sẽ đẩy các hàng bên trên trong bảng ra khỏi vùng nhìn thấy (dễ thấy nhất khi dùng Center 4-Wide).\nNhững ô gạch nào đi ra khỏi vùng nhìn thấy được sẽ đi vào vùng đệm và sẽ xuất hiện lại trong vùng nhìn thấy nếu bạn đã xóa đủ hàng.\n\nVùng đệm thường cao 20 ô (thường là do bảng đã bị cố định kích thước ở trong các dòng code), nhưng có game có vùng này cao vô hạn (ví dụ như trong chính Techmino luôn, khi bảng có thể tự mở rộng kích thước của nó).\n\nCác bạn có thể tìm hiểu thêm ở mục \"Vùng biến mất\".",
},
{"Vùng biến mất",
"nhom05 gone vanish zone",
@@ -338,7 +338,7 @@ Tuy nhiên, mỗi game sẽ có cách xử lý khác nhau. Ví dụ:
{">A|Gạch",
"nhom05a",
"",
- "Bạn có biết?\nGame này hỗ trợ và cho phép bạn chơi với 29 loại gạch khác nhau\n\n1 Mino | 1 Domino | 2 Trimino | 7 Tetromino | 18 Pentomino\n\nMino: gạch 1 ô\nDomino: gạch 2 ô\nTrimino: gạch 3 ô\nTetromino: gạch 4 ô\nPentomino: gạch 5 ô\n\nTechmino có Hexomino (gạch 5 ô) không?\nBây giờ thì chưa nhưng tương lai thì có thể có.",
+ "Bạn có biết? Techmino hỗ trợ và cho phép bạn chơi với 29 loại gạch khác nhau, bao gồm: 1 Mino, 1 Domino, 2 Trimino, 7 Tetromino và 18 Pentomino\n\nMino: gạch 1 ô\nDomino: gạch 2 ô\nTrimino: gạch 3 ô\nTetromino: gạch 4 ô\nPentomino: gạch 5 ô\n\nTechmino có Hexomino (gạch 5 ô) không?\nBây giờ thì chưa nhưng tương lai thì có thể có.",
},
{"Hình dạng",
"nhom05a hình dáng"..tetromino,
@@ -450,7 +450,7 @@ So với XRS, BiRS dễ nhớ hơn vì chỉ dùng một bảng wall-kick; nhưn
{"SRS",
"nhom05b superrotationsystem",
"term",
- "Super Rotation System | Hệ thống xoay Siêu Cấp\n\nHệ thống xoay này được sử dụng rất nhiều trong các game xếp gạch hiện đại và có rất nhiều hệ thống xoay do fan làm ra cũng dựa vào hệ thống này.\nCó tất cả 8 bảng wall-kick trong SRS, tương ứng với hai hướng xoay cho tất cả bốn tư thế của tất cả các gạch (không có trường hợp cho 180°). Nếu gạch đụng tường, đụng đáy, hay đè lên gạch khác sau khi xoay, hệ thống sẽ kiểm tra các vị trí xung quanh. Bạn có thể xem đầy đủ các bảng wall-kick của SRS trên Tetris Wiki.",
+ "Super Rotation System | Hệ thống xoay Siêu Cấp\n\nHệ thống xoay này được sử dụng rất nhiều trong các game xếp gạch hiện đại và có rất nhiều hệ thống xoay do fan làm ra cũng dựa vào hệ thống này.\nCó tất cả 8 bảng wall-kick trong SRS, tương ứng với hai hướng xoay cho tất cả bốn tư thế của tất cả các gạch (không có trường hợp cho 180°). Nếu gạch đụng tường, đụng đáy, hay đè lên gạch khác sau khi xoay, hệ thống sẽ kiểm tra các vị trí xung quanh.\n\nBạn có thể xem đầy đủ các bảng wall-kick của SRS trên Tetris Wiki.",
},
{"SRS+",
"nhom05b srsplus superrotationsystemplus",
@@ -607,12 +607,12 @@ Xem mục tiếp theo để biết thêm.
{"20G",
"nhom05e1 trọng lực; ngay lập tức; gravity instantly",
"term",
- "Tốc độ tối đa trong các game xếp gạch hiện đại.\n\nMặc dù nhìn qua thuật ngữ này thể hiện tốc độ rơi là 20 hàng / khung hình, nhưng thật ra chúng được dùng để chỉ tốc độ vô tận.\n\nHơn nữa, trong các chế độ 20G, game sẽ ưu tiên di chuyển gạch xuống đáy hơn là bất cứ thao tác di chuyển nào từ người chơi.\nLấy ví dụ: ngay cả khi ARR được đặt là 0, gạch vẫn cứ di chuyển một mạch xuống phía dưới một cách hồn nhiên giống như người chơi chưa nhấn gì.\nViệc này gây khó cho người chơi khi họ muốn gạch leo ra khỏi hố hoặc nhảy ra khỏi lỗ trong một số tình huống.",
+ "Tốc độ tối đa trong các game xếp gạch hiện đại.\n\nMặc dù nhìn qua thuật ngữ này thể hiện tốc độ rơi là 20 hàng / khung hình, nhưng thật ra chúng được dùng để chỉ tốc độ vô tận.\n\nHơn nữa, trong các chế độ 20G, game sẽ ưu tiên di chuyển gạch xuống đáy hơn là bất cứ thao tác di chuyển nào từ người chơi.\nVà ngay cả khi ARR được đặt là 0, gạch vẫn cứ di chuyển một mạch xuống phía dưới một cách hồn nhiên giống như người chơi chưa nhấn gì, trước khi di chuyển theo thao tác của người chơi.\n\nViệc này gây khó khăn cho người chơi khi họ muốn gạch leo ra khỏi hố hoặc nhảy ra khỏi lỗ trong một số tình huống.",
},
{"Lockdown Delay",
"nhom05e1 lockdelay lockdowndelay lockdowntimer ld; thời gian chờ khóa gạch",
"term",
- "Thời gian chờ khóa gạch, viết tắt là LD.\nĐây là khoảng thời gian ngay sau khi gạch chạm đất và trước khi gạch bị khóa (không thể điều khiển được nữa).\n\nTrong các game xếp gạch cổ điển, khoảng thời gian chờ này = khoảng thời gian gạch cần có để di chuyển xuống 1 ô, và không có cơ chế nào để trì hoãn việc khóa gạch.\n\nTrong các game xếp gạch hiện đại, thời gian chờ được thong thả hơn, và trong game thường có cơ chế trì hoãn việc khóa gạch, trong đó bạn có thể di chuyển hoặc xoay gạch để đặt lại thời gian chờ (tối đa 15 lần trong hầu hết các game).",
+ "Thời gian chờ khóa gạch, viết tắt là LD.\nGame sẽ chờ một khoảng thời gian, trước khi game khóa gạch (tức là gạch không thể điều khiển được nữa), bắt đầu tính từ khi gạch vừa chạm đất.\n\nTrong các game xếp gạch cổ điển, khoảng thời gian chờ này CHÍNH LÀ khoảng thời gian gạch cần có để di chuyển xuống 1 ô, và không có cách nào để hoãn thời điểm khóa gạch.\n\nTrong các game xếp gạch hiện đại, thời gian chờ được tính riêng và thoải mái hơn. Đi kèm với thời gian chờ dài hơn là cơ chế hoãn thời điểm khóa gạch, trong đó bạn có thể di chuyển hoặc xoay gạch để đặt lại bộ đếm thời gian về 0, để bạn có thể hoãn thời điểm khóa gạch thêm một lúc nữa (tối đa 15 lần trong hầu hết các game).",
},
{"Spawn&ClearDelay",
"nhom05e1 spawndelay cleardelay; thời gian chờ gạch sinh ra; thời gian chờ xóa hàng",
@@ -622,7 +622,7 @@ Xem mục tiếp theo để biết thêm.
{"ARE",
"nhom05e1 spawn appearance delay",
"term",
- "Thời gian chờ xuất hiện gạch mới\nHay còn được biết với tên: Appearance Delay và Entry Delay.\n\n\"ARE\" chỉ khoảng thời gian sau khi gạch bị khóa và trước khi gạch mới xuất hiện\n\nP/s: Từ \"ARE\" không phải là từ viết tắt hay hay là một dạng của \"be\" trong tiếng Anh; nó bắt nguồn từ <あれ> (a-re) trong tiếng Nhật, có nghĩa là \"nó\" hoặc \"cái đó\" / \"cái kia\" / \"cái ấy\".",
+ "Thời gian chờ xuất hiện gạch mới\nHay còn được biết với tên: Appearance Delay và Entry Delay.\n\n\"ARE\" chỉ khoảng thời gian sau khi gạch bị khóa và trước khi gạch mới xuất hiện\n\nP/s: Từ \"ARE\" không phải là từ viết tắt hay hay là một dạng của động từ \"be\" trong tiếng Anh; nó bắt nguồn từ <あれ> (a-re) trong tiếng Nhật, có nghĩa là \"nó\" hoặc \"cái đó\" / \"cái kia\" / \"cái ấy\".",
},
{"Line ARE",
"nhom05e1 appearance delay",
@@ -632,7 +632,7 @@ Xem mục tiếp theo để biết thêm.
{"Death ARE",
"nhom05e1 die delay",
"term",
- "Một cơ chế đặc biệt cho phép tránh game over trong một số trường hợp.\n\nDeath ARE sẽ được kích hoạt khi có một viên gạch chặn ngay tại vị trí xuất hiện của gạch mới (dẫn tới hiện tượng block out)\nKhi kích hoạt, spawn ARE sẽ được cộng với một khoảng thời gian bổ sung để cho phép người chơi dùng IRS, IHS hoặc IMS.\n\nÝ tưởng về cơ chế này được đề xuất lần đầu bởi @NOT_A_ROBOT.",
+ "Một cơ chế đặc biệt cho phép tránh game over trong một số trường hợp.\n\nDeath ARE sẽ được kích hoạt khi có một viên gạch chặn ngay tại vị trí xuất hiện của gạch mới (dẫn tới hiện tượng block out)\nKhi kích hoạt, spawn ARE sẽ được cộng với Death ARE để cho phép người chơi có cơ hội dùng IRS, IHS và IMS.\n\nÝ tưởng về cơ chế này được đề xuất lần đầu bởi @NOT_A_ROBOT.",
},
{">E2|Thg số đ.khiển",
"nhom05e2",
@@ -647,12 +647,17 @@ Xem mục tiếp theo để biết thêm.
{"DAS & ARR",
"nhom05e2 das và arr delayedautoshift autorepeatrate",
"term",
- "DAS, hay Delayed Auto-shift, chỉ khoảng thời gian sau khi gạch di chuyển sang một hướng đã chọn 1 ô cho đến truớc khi gạch di chuển một cách tự động.\n\nARR, hay Auto-Repeat Rate, chỉ khoảng cách thời gian giữ 2 lần di chuyển sang 1 ô trong lúc gạch đang tự động di chuyển.\n\nDAS và ARR được tính bằng f (khung hình) (¹/₆₀ ở 60FPS). 1ms = 16²/₃ khung hình.",
+ "DAS, hay Delayed Auto-shift, đây là khoảng thời gian ngay sau khi gạch đã di chuyển sang 1 ô và gạch đang đợi thời điểm gạch có thể bắt đầu quá trình di chuyển tự động.\n\nARR, hay Auto-Repeat Rate, chỉ khoảng cách thời gian giữa 2 lần di chuyển tự động 1 ô khi gạch đang trong quá trình di chuyển tự động.\n\nDAS và ARR được tính bằng f (khung hình) (¹/₆₀ ở 60FPS). 1ms = 16²/₃ khung hình.",
},
{"DAS cut",
"nhom05e2 dascut dcd",
"term",
- "Cơ chế đặc biệt sẽ được kích hoạt khi gạch mới xuất hiện. Khi kích hoạt, cơ chế này sẽ tăng DAS lên một chút để gạch không tự di chuyển ngay khi đang có phím được giữ.\n\nCác game khác có thể có tính năng tương tự nhưng cách hoạt động có thể khác nhau.",
+ "Là cơ chế đặc biệt sẽ được kích hoạt khi gạch mới xuất hiện. Khi kích hoạt, cơ chế này sẽ tăng DAS lên một chút để gạch không tự di chuyển ngay khi đang có phím được giữ.\n\nCác game khác có thể có tính năng tương tự nhưng cách hoạt động có thể khác nhau.",
+ },
+ {"IRS cut",
+ "irscut icd",
+ "term",
+ "Là cơ chế đặc biệt sẽ được kích hoạt khi gạch mới xuất hiện nhưng không có entry delay. Khi kích hoạt, game sẽ hoãn việc kích IRS một lúc để bạn có thời gian nhả phím xoay sau khi thả gạch xong.",
},
{"Auto-lock cut",
"nhom05e2 autolockcut",
@@ -697,7 +702,7 @@ Xem mục tiếp theo để biết thêm.
{"KPP",
"nhom05f1 số lần nhấn mỗi gạch; số phím mỗi gạch",
"term",
- "Keypresses per piece | Số lần nhấn mỗi viên gạch\nPhản ánh mức độ hiệu quả việc điều khiển gạch.\nCó thể giảm con số này bằng cách học Finesse",
+ "Keypresses per piece | Số lần nhấn mỗi viên gạch\nPhản ánh mức độ hiệu quả việc điều khiển gạch.\n\nCó thể giảm con số này bằng cách học Finesse",
},
{">F2|K.th. đ.khiển",
"nhom05f2",
@@ -708,9 +713,9 @@ Xem mục tiếp theo để biết thêm.
"nhom05f2 finesse lỗi di chuyển",
"term",
[[
-Một kỹ thuật di chuyển gạch vào vị trí mong muốn với chuỗi phím ngắn nhất có thể, giúp tiết kiệm thời gian và giảm khả năng misdrop.
+Là kỹ thuật điều khiển gạch nhanh nhất với chuỗi phím ngắn nhất có thể nhưng vẫn đảm bảo chính xác, giúp tiết kiệm thời gian và giảm khả năng misdrop.
-Đây là một kỹ năng quan trọng nên bạn hãy học Finesse sớm nhất có thể. Bạn có thể thấy khá nhiều video hướng dẫn trên Youtube cũng như các trang hướng dẫn với hình minh họa trên Google. Hãy bắt đầu từ thứ cơ bản nhất, rồi luyện tập dần để tăng độ chính xác lên. Hãy nhớ ưu tiên chính xác hơn là tốc độ nhé.
+Đây là một kỹ năng quan trọng nên bạn hãy học Finesse sớm nhất có thể. Bạn có thể thấy nhiều video hướng dẫn trên Youtube cũng như các trang hướng dẫn với hình minh họa trên Google. Hãy bắt đầu từ thứ cơ bản nhất, rồi luyện tập dần để tăng độ chính xác lên. Hãy nhớ ưu tiên chính xác hơn là tốc độ nhé.
Bạn sẽ không bị mất Finesse khi bạn nhét gạch hay thực hiện Spin vì Techmino chỉ kiểm tra những vị trí không yêu cầu soft drop
@@ -729,7 +734,7 @@ Lưu ý:
{"Hypertapping",
"nhom05f2 hypertapper nhấn liên tục",
"term",
- "Hypertapping (Nhấn liên tục)\n\nĐề cập tới một kỹ năng là khi bạn rung tay liên tục thay vì giữ phím.\n\nTrong các game xếp gạch cổ điển, thông số DAS rất cao và không thể điều chỉnh được, dẫn tới nhấn nút liên tục sẽ nhanh hơn so với giữ phím.\nBây giờ thì không cần vì các game xếp gạch hiện đại đã có DAS và ARR có thể điều chỉnh được (nếu có chăng không điều chỉnh được thì DAS cũng đã thấp hơn nhiều so với ngày trước)\n\nNhững người dùng kỹ năng này được gọi là \"hypertapper\"",
+ "Hypertapping (Nhấn liên tục)\n\nĐề cập tới một kỹ năng là khi bạn rung tay liên tục thay vì giữ phím.\n\nTrong các game xếp gạch cổ điển, thông số DAS rất cao và không thể điều chỉnh được, dẫn tới nhấn nút liên tục sẽ nhanh hơn so với giữ phím.\nBây giờ thì không cần vì các game xếp gạch hiện đại đã có DAS và ARR có thể điều chỉnh được (nếu có chăng không điều chỉnh được thì DAS cũng đã thấp hơn nhiều so với ngày trước).\n\nNhững người dùng kỹ năng này được gọi là \"hypertapper\"",
},
{"Rolling",
"nhom05f2",
@@ -811,7 +816,7 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
{"'Debt'",
"nhom05g debt owe",
"term",
- "Một thuật ngữ hay được sử dụng trong cộng đồng Tetris Trung Quốc.\n\n\"Debt\" đề cập đến tình huống mà bạn chỉ có thể tấn công KHI và CHỈ KHI setup được hoàn thành. Nên, khi đang làm một hoặc nhiều debt liên tiếp, người chơi bắt buộc phải để ý tới đối thủ để đảm bảo an toàn; còn không, bạn có thể bị bón hành sấp mặt.\n\nThuật ngữ này hay được sử dụng để diễn tả một số setup như TST tower.",
+ "Một thuật ngữ hay được sử dụng trong cộng đồng Tetris Trung Quốc.\n\n\"Debt\" đề cập đến tình huống mà bạn chỉ có thể tấn công KHI và CHỈ KHI setup được hoàn thành. Nên, khi đang làm một hoặc nhiều debt liên tiếp, người chơi bắt buộc phải để ý tới đối thủ để đảm bảo an toàn; còn không, người chơi đó có thể bị bón hành sấp mặt.\n\nThuật ngữ này hay được sử dụng để diễn tả một số setup như TST tower.",
},
{"Passthrough",
"nhom05g pingthrough",
@@ -826,17 +831,17 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
{">H|Mis-action",
"nhom05h misaction misdrop mishold",
"",
- "Misdrop: Vô tình thả rơi / đặt gạch vào nơi không mong muốn.\nMishold: Vô tình nhấn nhầm phím Hold. Việc này có thể dẫn đến việc dùng một viên gạch không mong muốn.\n\nCả misdrop và mishold có thể làm bạn mất cơ hội để làm PC"
+ "Misdrop: Vô tình thả rơi / đặt gạch vào nơi không mong muốn.\nMishold: Vô tình nhấn nhầm phím Hold. Việc này có thể dẫn đến việc dùng một viên gạch không mong muốn.\n\nCả misdrop và mishold có thể làm bạn mất cơ hội để làm PC."
},
{">I|Spin",
"nhom05i",
"",
- "(Ở trong một số game)\n\nXoay gạch để di chuyển tới một vị trí mà bình thường sẽ không tiếp cận được. Ở một số game, thao tác này sẽ gửi thêm hàng rác hoặc là tăng thêm điểm. Mỗi game sẽ có cách kiểm tra Spin khác nhau."
+ "(Ở nhiều game, đa số các game cổ điển không có cái này)\n\nXoay gạch để di chuyển tới một vị trí mà bình thường sẽ không tiếp cận được. Ở một số game, thao tác này sẽ gửi thêm hàng rác hoặc là tăng thêm điểm. Mỗi game sẽ có cách kiểm tra Spin khác nhau."
},
{"Mini",
"nhom05i",
"term",
- "Một kiểu spin (được cho là) dễ làm hơn so với spin thông thường (vì trong một số game cũ, chúng được gọi là \"Ez T-spin\").\nLượng điểm bổ sung và hàng rác đều ít hơn so với spin thông thường.\n\nMỗi game sẽ có các quy tắc khác nhau để kiểm tra và chúng có thể không trực quan.\nNhưng bạn chỉ cần nhớ mấy cái bố cục làm Mini-spin là được!",
+ "Một kiểu spin (được cho là) dễ làm hơn so với spin thông thường (vì trong một số game cũ, chúng được gọi là \"Ez T-spin\").\nLượng điểm bổ sung và hàng rác đều ít hơn so với spin thông thường.\n\nMỗi game sẽ có các quy tắc khác nhau để kiểm tra và chúng có thể không trực quan.\nNhưng bạn chỉ cần nhớ mấy cách làm Mini-spin là được!",
},
{"All-spin",
"nhom05i allspin",
@@ -846,12 +851,12 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
{"T-spin",
"nhom05i tspin",
"term",
- "Spin được thực hiện bởi Tetromino T.\n\nT-spin chủ yếu được phát hiện bởi \"quy luật 3 góc\".\nTức là, nếu 3 trong 4 góc của một hình chữ nhật (có tâm là tâm xoay của gạch T) bị đè bởi bất kỳ gạch nào, thì spin đó được tính là T-spin.\n\nNgoài quy tắc đó ra thì còn có một số quy tắc để phát hiện T-spin và phân biệt giữa T-spin và Mini T-spin.",
+ "Spin được thực hiện bởi Tetromino T.\n\nT-spin chủ yếu được phát hiện bởi \"quy luật 3 góc\": nếu 3 trong 4 góc của hình vuông ngoại tiếp gạch T bị đè bởi bất kỳ gạch nào, thì spin đó được tính là T-spin.\n\nNgoài quy tắc đó ra thì còn có một số quy tắc để phát hiện T-spin và phân biệt giữa T-spin và Mini T-spin.",
},
{"O-Spin",
"nhom05i ospin",
"term",
- "Gạch O vốn dĩ \"tròn\", không đổi hình dạng khi xoay ở bất cứ hướng nào, nên nó không thể \"đá\" được. Do đó gạch O không tài nào leo ra khỏi \"lỗ\" hoặc \"hố\" nếu bị kẹt. Từ việc này, có một người đã làm một cái video fake cách làm O-spin trong Tetris 99 và Tetris Friends\n\nHiện tại có 2 hệ thống xoay hỗ trợ O-spin:\n\tXRS cho phép gạch O có thể \"teleport\" tới một cái lỗ.\n\tTRS cho phép gạch O \"teleport\" và \"biến hình\"",
+ "Gạch O vốn dĩ \"tròn\", không đổi hình dạng khi xoay ở bất cứ hướng nào, nên nó không thể \"đá\" được. Do đó gạch O không tài nào leo ra khỏi \"lỗ\" hoặc \"hố\" nếu bị kẹt. Lợi dụng việc này, có người đã làm video fake cách làm O-spin trong Tetris 99 và Tetris Friends\n\nHiện tại có 2 hệ thống xoay hỗ trợ O-spin:\n\tXRS cho phép gạch O có thể \"teleport\" tới một cái lỗ.\n\tTRS cho phép gạch O \"teleport\" và \"biến hình\"",
},
{"Fin, Neo, Iso",
"nhom05i fin neo iso",
@@ -903,7 +908,7 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
{"Back to Back",
"nhom05j b2b btb backtoback",
"term",
- "Hay còn gọi là B2B. Xóa 2 hoặc nhiều lần xóa theo kiểu nâng cao (như Tetris hay Spin) liên tiếp (nhưng không được kiểu xóa bình thường giữa chừng).\nKhông như combo, Back To Back sẽ không bị mất khi đặt gạch.\n\nỞ Techmino, B2B được tính bằng thanh năng lượng, chứ không tính theo số lần xóa kiểu đặc biệt.\nCũng trong Techmino, nhiều B2B liên tiếp được tính là Back-to-back-to-back (B3B) (xem mục B2B2B để biết thêm).\n\nTechmino cũng tính cả PC và HPC liên tiếp là B2B và B3B",
+ "Hay còn gọi là B2B. Xóa 2 hoặc nhiều lần xóa theo kiểu nâng cao (như Tetris hay Spin) liên tiếp (nhưng không được xóa kiểu bình thường giữa chừng).\nKhông như combo, Back To Back sẽ không bị mất khi đặt gạch.\n\nỞ Techmino, B2B được tính bằng thanh năng lượng, chứ không tính theo số lần xóa kiểu đặc biệt.\nCũng trong Techmino, nhiều B2B liên tiếp được tính là Back-to-back-to-back (B3B) (xem mục B2B2B để biết thêm).\n\nTechmino cũng tính cả PC và HPC liên tiếp là B2B và B3B",
},
{"B2B2B",
"nhom05j b3b backtobacktoback",
@@ -913,7 +918,7 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
{"All Clear",
"nhom05j pc perfectclear ac allclear",
"term",
- "Còn được biết tới là Perfect Clear (PC). Đây là thuật ngữ được dùng nhiều trong cộng đồng và cũng như được dùng trong Techmino\nXóa toàn bộ gạch ra khỏi bảng, không trừ gạch nào\n\n[Sea: còn có một từ ít dùng nữa, đó là \"Bravo\"]",
+ "Còn được biết tới là Perfect Clear (PC). Đây là thuật ngữ được dùng nhiều trong cộng đồng và cũng như được dùng trong Techmino\nXóa toàn bộ gạch ra khỏi bảng, không trừ gạch nào\n\n[Sea: còn có một từ cổ cho thuật ngữ này nữa, đó là \"Bravo\"]",
},
{"HPC",
"nhom05j hc halfperfectclear",
@@ -947,7 +952,7 @@ Trông nó nhìn rất giống cục xương, nên đôi khi được gọi là
Trong Techmino, bone block được mô tả là "một skin gạch duy nhất, lạ mắt mà tất cả các gạch đều sử dụng".
Skin khác nhau sẽ có skin bone block khác nhau.
-Cũng trong Techmino nhưng ở tiếng Việt, từ "gạch ]]..CHAR.icon.bone..[[" được dùng để chỉ bone block.
+Cũng trong Techmino (khi để ngôn ngữ là tiếng Việt), từ "gạch ]]..CHAR.icon.bone..[[" được dùng để chỉ bone block.
]],
},
{"=[NHÓM 06]=",
@@ -1424,19 +1429,19 @@ NHÓM 07: MỘT VÀI CƠ CHẾ VÀ CHẾ ĐỘ CỦA MỘT SỐ GAME
{"=[NHÓM 09]=",
"nhom09",
"",
- "NHÓM 09: WIKI; CÁC TRANG WEB BÀY SETUP,\nCUNG CẤP CÂU ĐỐ & CHIA SẺ SETUP"
+ "NHÓM 09: WIKI; CÁC TRANG WEB BÀY SETUP, CUNG CẤP CÂU ĐỐ & CHIA SẺ SETUP"
},
{">A|Wiki",
"nhom09a",
"",
""
},
- {"Huiji Wiki",
- "nhom09a huiji wiki",
- "help",
- "(灰机wiki)\n\nMột wiki về Tetris của những người đam mê Tetris từ các nhóm và chi nhánh của Cộng đồng Nghiên cứu Tetris Trung Quốc. Hiện tại hầu hết các trang đều được tham khảo và dịch từ Wiki Hard Drop và Tetris Wiki. Liên kết sẽ dẫn bạn tới bản tiếng Trung giản thể.",
- "https://tetris.huijiwiki.com",
- },
+ -- {"Chinese Tetris Wiki",
+ -- "china tetris wiki",
+ -- "help",
+ -- "A Chinese Tetris wiki by Tetris enthusiasts from Chinese Tetris Research Community groups and affiliates. Most pages have been referenced and translated from Hard Drop Wiki and Tetris Wiki for now. Link in Simplified Chinese.",
+ -- "http://tetriswiki.cn",
+ -- },
{"Wiki Hard Drop",
"nhom09a harddrop hd wiki",
"help",
@@ -1446,7 +1451,7 @@ NHÓM 07: MỘT VÀI CƠ CHẾ VÀ CHẾ ĐỘ CỦA MỘT SỐ GAME
{"Tetris.wiki",
"nhom09a tetris wiki",
"help",
- "Một wiki tập trung vào các nội dung liên quan đến Tetris. Wiki được tạo ra từ năm 2015 bởi Myndzi. Trong những năm qua, hàng nghìn đóng góp đã được thực hiện để ghi lại các game xếp gạch chính thức và các game do fan làm, các series, những cơ chế của game,… cũng như tạo ra những bài hướng dẫn để cải thiện trải nghiệm chơi.",
+ "Một wiki tập trung vào các nội dung liên quan đến Tetris. Wiki được tạo ra từ năm 2015 bởi Myndzi, hiện đang được quản lý bởi Simon.lc. Trong những năm qua, hàng nghìn đóng góp đã được thực hiện để ghi lại các game xếp gạch chính thức và các game do fan làm, các series, những cơ chế của game,… cũng như tạo ra những bài hướng dẫn để cải thiện trải nghiệm chơi.",
"https://tetris.wiki",
},
{"Tetris Wiki Fandom",
@@ -1696,7 +1701,7 @@ Opener phải đạt 2 trong 4 tiêu chí sau
{"BTPC",
"nhom12a opener btcannon betacannon",
"setup",
- "Phần tiếp theo của DT Cannon kết thúc bằng All Clear.\nĐể có thêm thông tin, bạn có thể nhấn nút hình địa cầu để mở bài ở trên wiki Hard Drop",
+ "Phần tiếp theo của BT Cannon kết thúc bằng All Clear.\nĐể có thêm thông tin, bạn có thể nhấn nút hình địa cầu để mở bài ở trên wiki Hard Drop",
"https://harddrop.com/wiki?search=bt_cannon",
},
{"TKI 3 Perfect Clear",
diff --git a/parts/language/dict_zh.lua b/parts/language/dict_zh.lua
index 704003da..8a021049 100644
--- a/parts/language/dict_zh.lua
+++ b/parts/language/dict_zh.lua
@@ -10,12 +10,12 @@ return {
{"新人学习/练习路线",
"读我 必读 萌新 xinren new noob readme",
"help",
- "以下是关于提升真正打块能力的指引,如果在以下任何项目练习过程中感到有困难,可以适当回去玩玩自己喜欢的项目。别忘了你是来 “玩” 游戏的,兴趣最重要。\n以下给出几个新手时期的主线任务树,前期主要就应该练习以下内容,学定式和T-Spin什么的对实力帮助很小(我们不认为靠定式对战秒其他萌新是有效实力):\n(注意,三段应当同时进行,不是A→B→C)\nA. 堆叠能力练习方法\n\tA1. 手上的块可以放的时候先别急着放,看看下一块有没有地方,如果放不下去就看看手上的能不能换个地方\n\tA2. 尝试把地形尽量控制得平整,因为大多数情况比较平的地形来啥块都比较容易放得下去\n\tA3. 允许hold的时候可以多想想手里和hold的块和后续几块应该怎么安排顺序,长远地使地形平整\nB. 操作效率与速度练习方法\n\tB1. 不要每一块都拿影子去对形状对位置,要自己想象这个块转一下是什么方向,想好了再开始按按键\n\tB2. 学习双旋,能逆时针转一次就不要顺时针转三次,费手\n\tB3. 学习极简,刚开始不用管速度,保证正确率最重要,养成良好习惯以后再提速快得很\nC. 堆叠能力考核\n\tC1. 稳定完成40行不死(可以用hold)\n\tC2. 稳定完成40行不死(不能用hold)\n\tC3. 稳定全消四完成40行(可以用hold)\n\tC4. 稳定全消四完成40行(不能用hold)\n以上都是根据社区和个人经验总结的模糊方法与目标,所以C的考核可以根据自身情况调整严格程度(例如 “稳定” 的具体成功率)。\n注:完成C的考核后,需要在未来一直注意没有上限的A1,这是方块的根本元素之一,强大的读next能力可以让你快速上手任何变种玩法。",
+ "以下是关于提升真正打块能力的指引,如果在以下任何项目练习过程中感到有困难,可以适当回去玩玩自己喜欢的项目。别忘了你是来 “玩” 游戏的,兴趣最重要。\n以下给出几个新手时期的主线任务树,前期主要就应该练习以下内容,学定式和T-Spin什么的对实力帮助很小(我们不认为靠定式对战秒其他萌新是有效实力):\n(注意,三段应当同时进行,不是A→B→C)\nA. 堆叠能力练习方法\n\tA1. 手上的块可以放的时候先别急着放,看看下一块有没有地方,如果放不下去就看看手上的能不能换个地方\n\tA2. 尝试把地形尽量控制得平整,因为大多数情况比较平的地形来啥块都比较容易放得下去\n\tA3. 允许hold的时候可以多想想手里和hold的块和后续几块应该怎么安排顺序,长远地使地形平整\nB. 操作效率与速度练习方法\n\tB1. 不要每一块都拿影子去对形状对位置,要自己想象这个块转一下是什么方向,想好了再开始按按键\n\tB2. 学习双旋,能逆时针转一次就不要顺时针转三次,费手\n\tB3. 学习极简,刚开始不用管速度,保证正确率最重要,养成良好习惯以后再提速快得很\nC. 堆叠能力考核\n\tC1. 稳定完成40行不死(可以用hold)\n\tC2. 稳定完成40行不死(不能用hold)\n\tC3. 稳定全程消四完成40行(可以用hold)\n\tC4. 稳定全程消四完成40行(不能用hold)\n以上都是根据社区和个人经验总结的模糊方法与目标,所以C的考核可以根据自身情况调整严格程度(例如 “稳定” 的具体成功率)。\n注:完成C的考核后,需要在未来一直注意没有上限的A1,这是方块的根本元素之一,强大的读next能力可以让你快速上手任何变种玩法。",
},
{"关于T-spin学习",
"T旋 T转 tspins",
"help",
- "首先指出:要能熟练做出各种T-spin并不是只看着T-spin的那一小部分地形就可以玩好的,对玩家堆叠能力和计算next能力同样也有较高的要求。\n\n如果不只是出于娱乐、随便玩玩的目的,是真的想不断提升T-spin能力变强,请在基础能力达到一定要求前不要刻意去学习太多的T-spin,而先把重点放在堆叠等基本功上。\n\n参考学T门槛水平:40L达到60s以内(可以视个人情况调整为40~120s)、能够轻松完成全消四的40L、不使用Hold不降太多速度的前提下比较轻松完成全消四的40L(培养看next的意识和算力)。",
+ "首先指出:要能熟练做出各种T-spin并不是只看着T-spin的那一小部分地形就可以玩好的,对玩家堆叠能力和计算next能力同样也有较高的要求。\n\n如果不只是出于娱乐、随便玩玩的目的,是真的想不断提升T-spin能力变强,请在基础能力达到一定要求前不要刻意去学习太多的T-spin,而先把重点放在堆叠等基本功上。\n\n参考学T门槛水平:40L达到60s以内(可以视个人情况调整为40~120s)、能够轻松完成全程消四的40L、不使用Hold不降太多速度的前提下比较轻松完成全程消四的40L(培养看next的意识和算力)。",
},
{"游戏官网",
"official website homepage mainpage guanwang",
@@ -23,11 +23,11 @@ return {
"Techmino的官网!\n可以在上面下载游戏本体,或者修改头像以及个人信息。\n\n游戏作者的一些话:强烈不建议在任何公开场合提及甚至宣传Techmino,更不要随便对外发送我们的官网链接!请务必只在私下里向有基础或真的很有兴趣入坑认真玩的玩家推荐,不然很容易拉低社群质量破坏交流氛围,比较难处理,甚至有可能影响游戏的未来发展。为了保证游戏能够变得越来越好玩,千万慎重考虑您对游戏的推广方式!感谢您对Techmino的大力支持!!",
"http://studio26f.org",
},
- {"灰机Wiki",
- "huiji",
+ {"俄罗斯方块中文维基",
+ "zhongwenweiji wiki",
"help",
"俄罗斯方块中文维基,由一群来自俄罗斯方块研究群及下属群的方块同好建立的关于俄罗斯方块的中文百科全书。\n\n目前其大部分页面翻译和参考来自Hard Drop Wiki和Tetris Wiki",
- "https://tetris.huijiwiki.com",
+ "http://tetriswiki.cn",
},
{"HardDrop Wiki",
"hd",
@@ -618,17 +618,17 @@ FNNS and {"赞助3",
"主流方块游戏中七种块的颜色会使用同一套彩虹配色:\nZ:红 S:绿 J:蓝 L:橙 T:紫 O:黄 I:青\n\nTechmino默认也使用这一套 “标准” 配色。",
},
{"提前旋转(IRS)",
- "irs initialrotatesystem",
+ "tiqianxuanzhuan irs initialrotatesystem",
"term",
"Initial Rotation System 提前旋转系统\n方块出现前提前按下旋转后,出现时就是转好的形状,有时可以避免死亡。",
},
{"提前暂存(IHS)",
- "ihs initialholdsystem",
+ "tiqianzancun ihs initialholdsystem",
"term",
"Initial Hold System 提前Hold系统\n方块出现前提前按下hold后,直接出现hold里的方块,有时可以避免死亡。",
},
{"提前移动(IMS)",
- "ims initialmovesystem",
+ "tiqianyidong ims initialmovesystem",
"term",
"Initial Move System 提前移动系统\n方块出现前提前按住移动后,出现时会朝移动方向偏一格,有时可以避免死亡(Techmino限定)。\n注:需要块出现时das已充满",
},
@@ -853,6 +853,11 @@ FNNS and {"赞助3",
"term",
"Techmino中指玩家的操作焦点转移到新方块的瞬间,此时减小(重置)DAS计时器,让自动移动不会立刻生效,减少 “移动键松开晚了导致下一块一出来就立即开始移动” 的情况\n注:其他游戏中的DAS打断机制可能和Techmino的有区别,仅供参考。",
},
+ {"IRS打断(ICD)",
+ "irscut icd daduan",
+ "term",
+ "(由Electra设计)新方块生成时触发IRS的特殊延迟。在没有生成延迟时,这会让预输入的旋转动作延迟一段时间再生效,允许晚一点松开旋转键防止md。",
+ },
{"误硬降打断(HCD)",
"autolockcut mdcut daduan",
"term",
diff --git a/parts/language/lang_en.lua b/parts/language/lang_en.lua
index 413cd2ea..a5ebadff 100644
--- a/parts/language/lang_en.lua
+++ b/parts/language/lang_en.lua
@@ -464,14 +464,13 @@ C. Gamepad
tas="TAS (T)",
},
net_menu={
- league="Tech League",
- ffa="FFA",
+ galaxim="Galaxim",
rooms="Rooms",
resetPW="Reset password",
logout="Log out",
},
- net_league={
- match="Find Match",
+ net_galaxim={
+ match="Enter Sim.",
},
net_rooms={
password="Password",
@@ -590,6 +589,7 @@ C. Gamepad
bg_on="Normal BG",
bg_off="No BG",
bg_custom="Custom BG",
+ bg_custom_base64="Paste image as BG\n(PNG/JPG in Base64)",
defaultBG="Default BG",
resetDbg="Reset to default",
lockBG="Lock BG",
@@ -625,6 +625,7 @@ C. Gamepad
das="DAS",arr="ARR",
dascut="DAS Cut",
+ irscut="IRS Cut",
dropcut="Auto-lock Cut",
sddas="Soft Drop DAS",sdarr="Soft Drop ARR",
ihs="Initial Hold",
@@ -921,12 +922,9 @@ C. Gamepad
['master_g']= {"Master", "GRADED", "Get the highest grade you can!"},
['master_ex']= {"GrandMaster", "EXTRA", "An eternity shorter than an instant"},
['master_instinct']= {"Master", "INSTINCT", "What if the active piece becomes invisible?"},
- ['strategy_e']= {"Strategy", "EASY", "Fast 20G decision"},
+ ['strategy_e_plus']= {"Strategy", "EASY+", "Holdless strategy!"},
['strategy_h']= {"Strategy", "HARD", "Fast 20G decision"},
['strategy_u']= {"Strategy", "ULTIMATE", "Fast 20G decision"},
- ['strategy_e_plus']= {"Strategy", "EASY+", "Holdless strategy!"},
- ['strategy_h_plus']= {"Strategy", "HARD+", "Holdless strategy!"},
- ['strategy_u_plus']= {"Strategy", "ULTIMATE+", "Holdless strategy!"},
['blind_e']= {"Invisible", "SLOW", "For beginners"},
['blind_n']= {"Invisible", "FAST", "For intermediates"},
['blind_h']= {"Invisible", "INSTANT", "For the experienced"},
@@ -971,13 +969,14 @@ C. Gamepad
['backfire_h']= {"Backfire", "HARD", "Send 100 lines as fast as you can while attacking yourself!"},
['backfire_l']= {"Backfire", "LUNATIC", "Send 100 lines as fast as you can while attacking yourself!"},
['backfire_u']= {"Backfire", "ULTIMATE", "Send 100 lines as fast as you can while attacking yourself!"},
- ['sprintAtk']= {"Sprint", "100 Attack", "Send 100 lines as fast as you can!"},
+ ['sprintAtk']= {"Sprint", "100 ATTACK", "Send 100 lines as fast as you can!"},
['sprintEff']= {"Efficiency", "40L", "Send more attack in 40 lines!"},
['zen']= {'Zen', "200L", "A 200-line score attack with no time limit"},
['ultra']= {'Ultra', "EXTRA", "A 2-minute score attack"},
['infinite']= {"Infinite", "", "Just a sandbox"},
['infinite_dig']= {"Dig", "INFINITE", "Dig-diggin'-dug"},
['marathon_inf']= {"Marathon", "INFINITE", "Infinite marathon."},
+ ['spinren']= {"Spin Combo", "EFFICIENCY", "Spike in a blink"},
['custom_clear']= {"Custom", "NORMAL"},
['custom_puzzle']= {"Custom", "PUZZLE"},
@@ -997,7 +996,7 @@ C. Gamepad
"1 next 1 hold!",
"1 next 6 hold!",
"20G is actually a brand new game rule!",
- "40-line Sprint WR: 13.928s by sillyshark123",
+ "40-line Sprint WR: 13.430s by WestL",
"6 next 1 hold!",
"6 next 6 hold?!",
"A choke a day keeps record away",
diff --git a/parts/language/lang_es.lua b/parts/language/lang_es.lua
index 49c1e1b9..3b489955 100644
--- a/parts/language/lang_es.lua
+++ b/parts/language/lang_es.lua
@@ -425,14 +425,13 @@ return {
tas="TAS (T)",
},
net_menu={
- league="Liga Tech",
- ffa="FFA",
+ -- galaxim="Galaxim", -- Galaxy+Simulation
rooms="Salas",
resetPW="Restabl. Contraseña",
logout="Desconec.",
},
- net_league={
- match="Buscar Match",
+ net_galaxim={
+ -- match="Enter Sim.", -- (Actively) Enter (the) (digital) Simulation of (a galaxy)
},
net_rooms={
password="Contraseña",
@@ -585,6 +584,7 @@ return {
das="DAS",arr="ARR",
dascut="Intrrp. de DAS",
+ irscut="Intrrp. de IRS",
dropcut="Intrrp. de Autocaída",
sddas="DAS de C. Ráp.",sdarr="ARR de C. Rápida",
ihs="Resv. Inicial",
@@ -879,12 +879,9 @@ return {
['master_g']= {"Master", "Con rangos", "¡Consigue el rango más alto que puedas!"},
['master_ex']= {"GrandMaster", "Extra", "Una eternidad que dura un instante."},
['master_instinct']={"Master", "Instintivo", "¿Y si la pieza activa es invisible?"},
- ['strategy_e']= {"Strategy", "Fácil", "Decisiones rápidas en 20G."},
+ ['strategy_e_plus']={"Strategy", "Fácil+", "Lo mismo pero sin reserva!"},
['strategy_h']= {"Strategy", "Difícil", "Decisiones rápidas en 20G."},
['strategy_u']= {"Strategy", "Supremo", "Decisiones rápidas en 20G."},
- ['strategy_e_plus']={"Strategy", "Fácil+", "Lo mismo pero sin reserva!"},
- ['strategy_h_plus']={"Strategy", "Difícil+", "Lo mismo pero sin reserva!"},
- ['strategy_u_plus']={"Strategy", "Supremo+", "Lo mismo pero sin reserva!"},
-- ['blind_e']= {"Invisible", "SLOW", "For beginners"},
-- ['blind_n']= {"Invisible", "FAST", "For intermediates"},
-- ['blind_h']= {"Invisible", "INSTANT", "For the experienced"},
@@ -943,6 +940,7 @@ return {
['infinite']= {"Infinito", "", "Modo Sandbox."},
['infinite_dig']= {"Infinito: Queso", "", "Limpia, limpia, más limpia que tú."},
['marathon_inf']= {"Maratón", "Infinito", "Maratón infinita."},
+ -- ['spinren']= {"Spin Combo", "EFFICIENCY", "Spike in a blink"},
['custom_clear']= {"Personalizado", "Normal"},
['custom_puzzle']= {"Personalizado", "Puzzle"},
diff --git a/parts/language/lang_fr.lua b/parts/language/lang_fr.lua
index ab65a205..c07129b5 100644
--- a/parts/language/lang_fr.lua
+++ b/parts/language/lang_fr.lua
@@ -243,6 +243,7 @@ return {
"Ceci est un simple jeu de blocs.",
"On y joue comme sur C2/IO/JS/WWC/KOS et autres.",
"",
+ "Propulsé par LÖVE",
"Vous pouvez envoyer des rapports de bogues ou des suggestions via le groupe de test ou l'email du créateur ~",
"Assurez-vous d'obtenir le jeu uniquement des canaux officiels,",
"Ne téléchargez pas ce jeu depuis une autre source au risque d'avoir des virus,",
@@ -400,14 +401,13 @@ return {
-- tas="TAS (T)",
},
net_menu={
- -- league="Tech League",
- ffa="FFA",
+ -- galaxim="Galaxim", -- Galaxy+Simulation
rooms="Salons",
resetPW="Réinitialiser le mot de passe",
logout="Se déconnecter",
},
- net_league={
- match="Find Match",
+ net_galaxim={
+ -- match="Enter Sim.", -- (Actively) Enter (the) (digital) Simulation of (a galaxy)
},
net_rooms={
password="Mot de passe",
@@ -562,6 +562,7 @@ return {
das="DAS",arr="ARR",
dascut="DAS cut",
+ irscut="IRS cut",
-- dropcut="Auto-lock cut",
sddas="DAS de chute rapide",sdarr="ARR de chute rapide",
ihs="Réserve Initiale",
@@ -852,12 +853,9 @@ return {
['master_final']= {"Master", "FINAL", "20G : Un point final impossible à atteindre !"},
-- ['master_ph']= {"Master", "FANTASMA", "20G: ???"},
['master_ex']= {"GrandMaster", "EXTRA", "Tentez de devenir un Grandmaster."},
- ['strategy_e']= {"Stratégie", "FACILE", "Décision rapide 20G"},
+ ['strategy_e_plus']={"Stratégie", "FACILE+", "Stratégie sans retenue"},
['strategy_h']= {"Stratégie", "DIFFICILE", "Décision rapide 20G"},
['strategy_u']= {"Stratégie", "ULTIME", "Décision rapide 20G"},
- ['strategy_e_plus']={"Stratégie", "FACILE+", "Stratégie sans retenue"},
- ['strategy_h_plus']={"Stratégie", "DIFFICILE+", "Stratégie sans retenue"},
- ['strategy_u_plus']={"Stratégie", "ULTIME+", "Stratégie sans retenue"},
-- ['blind_e']= {"Invisible", "SLOW", "For beginners"},
-- ['blind_n']= {"Invisible", "FAST", "For intermediates"},
-- ['blind_h']= {"Invisible", "INSTANT", "For the experienced"},
@@ -916,7 +914,8 @@ return {
['ultra']= {'Ultra', "EXTRA", "2 minutes pour avoir le meilleur score."},
['infinite']= {"Infini", "", "Mode tranquile."},
['infinite_dig']= {"Infini : Dig", "", "Creuser, creuser, creuser."},
- ['marathon_inf']= {"Marathon", "Infini", "Marathon infini."},
+ ['marathon_inf']= {"Marathon", "INFINI", "Marathon infini."},
+ -- ['spinren']= {"Spin Combo", "EFFICIENCY", "Spike in a blink"},
['custom_clear']= {"Perso.", "NORMAL"},
['custom_puzzle']= {"Perso.", "PUZZLE"},
diff --git a/parts/language/lang_id.lua b/parts/language/lang_id.lua
index f08d1934..f4019f7f 100644
--- a/parts/language/lang_id.lua
+++ b/parts/language/lang_id.lua
@@ -426,14 +426,13 @@ return {
tas="TAS (T)",
},
net_menu={
- league="Tech League",
- ffa="FFA",
+ -- galaxim="Galaxim", -- Galaxy+Simulation
rooms="Ruang-ruang",
-- resetPW="Reset password",
logout="Log out",
},
- net_league={
- match="Cari Tandingan",
+ net_galaxim={
+ -- match="Enter Sim.", -- (Actively) Enter (the) (digital) Simulation of (a galaxy)
},
net_rooms={
password="Password",
@@ -587,6 +586,7 @@ return {
das="DAS",arr="ARR",
dascut="Gangguan DAS",
+ irscut="Gangguan IRS",
dropcut="Gangguan Auto-kunci",
sddas="DAS Jatuh",sdarr="ARR Jatuh",
ihs="Simpan Saat Tunda",
@@ -883,12 +883,9 @@ return {
['master_g']= {"Ahli", "BERTINGKAT", "Dapatkan tingkat tertinggi!"},
['master_ex']= {"Sangat Ahli", "EKSTRA", "Blok tidak kelihatan"},
['master_instinct']= {"Ahli", "INSTINK", "Bagaimana jika blok terkontrol tersembunyi?"},
- ['strategy_e']= {"Strategi", "MUDAH", "Keputusan 20G cepat"},
+ ['strategy_e_plus']= {"Strategi", "MUDAH+", "Mode strategi, tetapi tanpa menyimpan"},
['strategy_h']= {"Strategi", "SULIT", "Keputusan 20G cepat"},
['strategy_u']= {"Strategi", "TERAKHIR", "Keputusan 20G cepat"},
- ['strategy_e_plus']= {"Strategi", "MUDAH+", "Mode strategi, tetapi tanpa menyimpan"},
- ['strategy_h_plus']= {"Strategi", "SULIT+", "Mode strategi, tetapi tanpa menyimpan"},
- ['strategy_u_plus']= {"Strategi", "TERAKHIR+", "Mode strategi, tetapi tanpa menyimpan"},
['blind_e']= {"Tak Terlihat", "PELAN", "Untuk pemula"},
['blind_n']= {"Tak Terlihat", "CEPAT", "Untuk amatir"},
['blind_h']= {"Tak Terlihat", "INSTAN", "Untuk orang berpengalaman"},
@@ -940,6 +937,7 @@ return {
['infinite']= {"Tak Terbatas", "", "Bak pasir"},
['infinite_dig']= {"Tak Terbatas: Gali","", "Gali, gali, gali"},
['marathon_inf']= {"Maraton", "TAK TERBATAS", "Maraton tanpa akhir."},
+ -- ['spinren']= {"Spin Combo", "EFFICIENCY", "Spike in a blink"},
['custom_clear']= {"Tersesuai", "NORMAL"},
['custom_puzzle']= {"Tersesuai", "TEKA-TEKI"},
@@ -954,7 +952,7 @@ return {
"↑↑↓↓←→←→BA",
"$include",
"20G sebenarnya peraturan permainan baru!",
- "Rekor dunia 40L: 14.188s dari Lurny",
+ "Rekor dunia 40L: 13.430s dari WestL",
"Sistem pencapaian segera akan datang!",
"ALL SPIN!",
"Am G F G",
diff --git a/parts/language/lang_ja.lua b/parts/language/lang_ja.lua
index 91bfb9a6..cade7f93 100644
--- a/parts/language/lang_ja.lua
+++ b/parts/language/lang_ja.lua
@@ -470,14 +470,13 @@ C. ゲームパッド
tas="TAS (T)",
},
net_menu={
- league="テクリーグ",
- ffa="FFA",
+ -- galaxim="Galaxim", -- Galaxy+Simulation
rooms="ルーム",
resetPW="パスワード再設定",
logout="ログアウト",
},
- net_league={
- match="対戦相手を探す",
+ net_galaxim={
+ -- match="Enter Sim.", -- (Actively) Enter (the) (digital) Simulation of (a galaxy)
},
net_rooms={
password="パスワード",
@@ -631,6 +630,7 @@ C. ゲームパッド
das="DAS",arr="ARR",
dascut="DASカット",
+ irscut="IRSカット",
dropcut="自動設置カット",
sddas="ソフトドロップDAS",sdarr="ソフトドロップARR",
ihs="先行ホールド",
@@ -927,12 +927,9 @@ C. ゲームパッド
['master_g']= {"マスター", "GRADED", "最高段位を取れ!"},
['master_ex']= {"グランドマスター", "EXTRA", "一瞬にも満たない永遠"},
['master_instinct']= {"マスター", "INSTINCT", "もしミノが見えなくなったら?"},
- ['strategy_e']= {"ストラテジー", "EASY", "20Gでの素早い判断"},
+ ['strategy_e_plus']= {"ストラテジー", "EASY+", "20Gでの素早い判断"},
['strategy_h']= {"ストラテジー", "HARD", "20Gでの素早い判断"},
['strategy_u']= {"ストラテジー", "ULTIMATE", "20Gでの素早い判断"},
- ['strategy_e_plus']= {"ストラテジー", "EASY+", "20Gでの素早い判断"},
- ['strategy_h_plus']= {"ストラテジー", "HARD+", "20Gでの素早い判断"},
- ['strategy_u_plus']= {"ストラテジー", "ULTIMATE+", "20Gでの素早い判断"},
['blind_e']= {"インビジブル", "HALF", "初心者用"},
['blind_n']= {"インビジブル", "ALL", "中級者用"},
['blind_h']= {"インビジブル", "SUDDEN", "上級者用"},
@@ -977,13 +974,14 @@ C. ゲームパッド
['backfire_h']= {"バックファイヤー", "HARD", "撃った火力が戻ってくる!"},
['backfire_l']= {"バックファイヤー", "LUNATIC", "撃った火力が戻ってくる!"},
['backfire_u']= {"バックファイヤー", "ULTIMATE", "撃った火力が戻ってくる!"},
- ['sprintAtk']= {"スプリント", "100 Attack", "100line送れ!"},
- ['sprintEff']= {"スプリント", "Efficiency", "40lineの間に高火力を出せ!"},
+ ['sprintAtk']= {"スプリント", "100 ATTACK", "100line送れ!"},
+ ['sprintEff']= {"スプリント", "EFFICIENCY", "40lineの間に高火力を出せ!"},
['zen']= {'zen', "200", "時間制限なしで200line消去"},
['ultra']= {'ウルトラ', "EXTRA", "2分間でスコアアタック"},
['infinite']= {"無限", "", "サンドボックス"},
['infinite_dig']= {"無限: 掘り", "", "掘れ掘れ掘れ掘れ掘れ掘・・・"},
['marathon_inf']= {"マラソン", "INFINITE", "ずっと走れるね"},
+ -- ['spinren']= {"Spin Combo", "EFFICIENCY", "Spike in a blink"},
['custom_clear']= {"カスタム", "NORMAL"},
['custom_puzzle']= {"カスタム", "PUZZLE"},
@@ -1007,7 +1005,7 @@ getTip={refuseCopy=true,
"20PCって何?",
"26TSDって何?",
"2つの回転を使ってみよう、3つ使うとさらにいいです!",
- "40-line Sprint WR: 14.188s by Lurny",
+ "40-line Sprint WR: 13.430s by WestL",
"6next 1hold!",
"6next 6hold?!",
"低音を響かせろ!",
diff --git a/parts/language/lang_pt.lua b/parts/language/lang_pt.lua
index ced9d26c..85334736 100644
--- a/parts/language/lang_pt.lua
+++ b/parts/language/lang_pt.lua
@@ -414,13 +414,12 @@ return {
-- tas="TAS (T)",
},
net_menu={
- -- league="Tech League",
- ffa="FFA",
+ -- galaxim="Galaxim", -- Galaxy+Simulation
rooms="Salas",
-- resetPW="Reset password",
-- logout="Log out",
},
- net_league={
+ net_galaxim={
-- match="Find Match",
},
net_rooms={
@@ -575,6 +574,7 @@ return {
das="DAS",arr="ARR",
dascut="DAS cut",
+ irscut="IRS cut",
-- dropcut="Auto-lock cut",
sddas="Soft Drop DAS",sdarr="Soft Drop ARR",
ihs="Segurar Inicial",
@@ -865,12 +865,9 @@ return {
['master_final']= {"Mestre", "FINAL", "20G: Final inalcançável!"},
['master_ph']= {"Mestre", "FANTASMA", "20G: ???"},
['master_ex']= {"GrandMaster", "EXTRA", "Para ser um Grand Master, aceite \nesse desafio."},
- -- ['strategy_e']= {"Strategy", "EASY", "Fast 20G decision"},
+ -- ['strategy_e_plus']={"Strategy", "EASY+", "Holdless strategy"},
-- ['strategy_h']= {"Strategy", "HARD", "Fast 20G decision"},
-- ['strategy_u']= {"Strategy", "ULTIMATE", "Fast 20G decision"},
- -- ['strategy_e_plus']={"Strategy", "EASY+", "Holdless strategy"},
- -- ['strategy_h_plus']={"Strategy", "HARD+", "Holdless strategy"},
- -- ['strategy_u_plus']={"Strategy", "ULTIMATE+", "Holdless strategy"},
-- ['blind_e']= {"Invisible", "SLOW", "For beginners"},
-- ['blind_n']= {"Invisible", "FAST", "For intermediates"},
-- ['blind_h']= {"Invisible", "INSTANT", "For the experienced"},
@@ -929,7 +926,8 @@ return {
['ultra']= {'Ultra', "EXTRA", "Pegue a maior pontuação em 2 minutos."},
['infinite']= {"Infinito", "", "Modo Sandbox."},
['infinite_dig']= {"Infinito:Cave", "", "Cava, Cava, Cava."},
- ['marathon_inf']= {"Maratona", "Infinito", "Infinito maratona."},
+ ['marathon_inf']= {"Maratona", "INFINITO", "Infinito maratona."},
+ -- ['spinren']= {"Spin Combo", "EFFICIENCY", "Spike in a blink"},
['custom_clear']= {"Custom", "NORMAL"},
['custom_puzzle']= {"Custom", "PUZZLE"},
@@ -949,7 +947,7 @@ return {
"1next 1hold!",
"1next 6hold!",
"Na verdade 20G é uma regra de jogo nova.",
- "40-lines Sprint WR: 14.188s by Lurny",
+ "40-line Sprint WR: 13.430s by WestL",
"6next 1hold!",
"6next 6hold?!",
"ALL SPIN!",
diff --git a/parts/language/lang_symbol.lua b/parts/language/lang_symbol.lua
index 7a4c2b3f..dddf09bc 100644
--- a/parts/language/lang_symbol.lua
+++ b/parts/language/lang_symbol.lua
@@ -172,13 +172,12 @@ return {
tas="#&; (T)",
},
net_menu={
- league="TL",
- ffa="FFA",
+ -- galaxim="Galaxim", -- Galaxy+Simulation
rooms="< >",
resetPW="R ***",
logout="@_@x",
},
- net_league={
+ net_galaxim={
match="!",
},
net_rooms={
@@ -331,6 +330,7 @@ return {
das="x---x x x",arr="x x-x-x",
dascut="x x ↓___x x",
+ irscut="'' !''x",
dropcut="↓_ !↓↓x",
sddas="↓---↓ ↓ ↓",sdarr="↓ ↓-↓-↓",
ihs="![ ]",
diff --git a/parts/language/lang_vi.lua b/parts/language/lang_vi.lua
index 96b963c8..756af5f2 100644
--- a/parts/language/lang_vi.lua
+++ b/parts/language/lang_vi.lua
@@ -197,7 +197,7 @@ return {
keySettingInstruction="Nhấn một phím để gán phím đó\nescape (esc): Hủy\nbackspace: Xoá",
- customBGhelp=not MOBILE and "Kéo một tấm ảnh vào đây để áp dụng ảnh nền tuỳ chỉnh" or "Chưa hỗ trợ ảnh nền cho điện thoại",
+ customBGhelp="Kéo một tấm ảnh vào đây để áp dụng ảnh nền tuỳ chỉnh",
customBGloadFailed="Định dạng ảnh không được hỗ trợ",
errorMsg="Techmino bị lỗi và cần phải được khởi động lại\nBạn có thể gửi error log để giúp dev sửa game nhanh hơn.",
@@ -459,14 +459,13 @@ C. Tay cầm chơi game (Gamepad):
tas="TAS (T)",
},
net_menu={
- league="Tech League",
- ffa="FFA",
+ galaxim="Galaxim",
rooms="Danh sách phòng",
resetPW="Đặt lại mật khẩu",
logout="Đăng xuất",
},
- net_league={
- match="Tìm trận",
+ net_galaxim={
+ match="Bước vào mô phỏng",
},
net_rooms={
password="Mật khẩu",
@@ -586,6 +585,7 @@ C. Tay cầm chơi game (Gamepad):
bg_on="Ảnh nền thường",
bg_off="Không ảnh nền",
bg_custom="Ảnh nền tự chọn",
+ bg_custom_base64="Dán ảnh và cài thành ảnh nền\n(PNG/JPG ở format Base64)",
defaultBG="Nền mặc định",
resetDbg='Đặt lại',
lockBG="Khóa ảnh nền",
@@ -621,6 +621,7 @@ C. Tay cầm chơi game (Gamepad):
das="DAS",arr="ARR",
dascut="DAS cut",
+ irscut="IRS cut",
dropcut="Auto-lock cut",
sddas="DAS thả nhẹ",sdarr="ARR thả nhẹ",
ihs="Giữ tức thì",
@@ -924,12 +925,9 @@ C. Tay cầm chơi game (Gamepad):
['master_g']= {"Master", "GRADED", "Lấy điểm cao nhất có thể!"},
['master_ex']= {"GrandMaster", "EXTRA", "Cũng là lấy điểm cao nhất có thể nhưng mà gắt hơn!"},
['master_instinct']= {"Master", "INSTINCT", "Lấy điểm cao nhất có thể nhưng với gạch tàng hình!"},
- ['strategy_e']= {"Strategy", "DỄ", "Quyết định nhanh hoặc là thua"},
+ ['strategy_e_plus']= {"Strategy", "DỄ+", "Quyết định nhanh và không được Hold!"},
['strategy_h']= {"Strategy", "KHÓ", "Quyết định nhanh hoặc là thua"},
['strategy_u']= {"Strategy", "THÁCH ĐẤU", "Quyết định nhanh hoặc là thua"},
- ['strategy_e_plus']= {"Strategy", "DỄ+", "Quyết định nhanh và không được Hold!"},
- ['strategy_h_plus']= {"Strategy", "KHÓ+", "Quyết định nhanh và không được Hold!"},
- ['strategy_u_plus']= {"Strategy", "THÁCH ĐẤU+", "Quyết định nhanh và không được Hold!"},
['blind_e']= {"Invisible", "DỄ", "Dành cho người mới"},
['blind_n']= {"Invisible", "THƯỜNG", "Dành cho người đã quen"},
['blind_h']= {"Invisible", "KHÓ", "Dành cho người đã có kinh nghiệm"},
@@ -965,8 +963,8 @@ C. Tay cầm chơi game (Gamepad):
['tech_h_plus']= {"Tech B2B", "KHÓ+", "Chỉ được clear Spin hoặc PC"},
['tech_l']= {"Tech B2B", "RẤT KHÓ", "Cố gắng không phá B2B!"},
['tech_l_plus']= {"Tech B2B", "RẤT KHÓ+", "Chỉ được clear Spin hoặc PC"},
- ['tech_finesse']= {"Kỹ thuật di chuyển","", "Không được phép có lỗi di chuyển!"},
- ['tech_finesse_f']= {"Kỹ thuật di chuyển","Khg ĐƠN/ĐÔI/TAM","Không được phép có lỗi di chuyển hoặc kiểu Xoá hàng thường!"},
+ ['tech_finesse']= {"Tech FINESSE", "", "Không được phép có lỗi di chuyển!"},
+ ['tech_finesse_f']= {"Tech FINESSE", "PLUS", "Không được phép có lỗi di chuyển hoặc kiểu Xoá hàng thường!"},
['tsd_e']= {"TSD Challenge", "DỄ", "Chỉ được làm T-Spin Double!"},
['tsd_h']= {"TSD Challenge", "KHÓ", "Chỉ được làm T-Spin Double!"},
['tsd_u']= {"TSD Challenge", "THÁCH ĐẤU", "Chỉ được làm T-Spin Double!"},
@@ -974,13 +972,14 @@ C. Tay cầm chơi game (Gamepad):
['backfire_h']= {"Backfire", "KHÓ", "Sống sót những hàng rác do chính bạn gửi"},
['backfire_l']= {"Backfire", "RẤT KHÓ", "Sống sót những hàng rác do chính bạn gửi"},
['backfire_u']= {"Backfire", "THÁCH ĐẤU", "Sống sót những hàng rác do chính bạn gửi"},
- ['sprintAtk']= {"Sprint", "100 Attack", "Gửi 100 hàng!"},
- ['sprintEff']= {"Sprint", "Efficiency", "Gửi càng nhiều hàng càng tốt trong 40 hàng"},
+ ['sprintAtk']= {"Sprint", "100 ATTACK", "Gửi 100 hàng!"},
+ ['sprintEff']= {"Sprint", "EFFICIENCY", "Gửi càng nhiều hàng càng tốt trong 40 hàng"},
['zen']= {'Zen', "200", "Xoá 200 hàng nhưng không có thời gian giới hạn"},
['ultra']= {'Ultra', "EXTRA", "Lấy càng nhiều điểm càng tốt trong 2 phút"},
['infinite']= {"Infinite", "", "Chỉ là một chế độ tự do"},
['infinite_dig']= {"Infinite: Dig", "", "Đào, đào nữa, đào mãi"},
['marathon_inf']= {"Marathon", "VÔ TẬN", "Marathon không có điểm dừng."},
+ ['spinren']= {"Spin Ren", "EFFICIENCY", "Một nháy mắt, gửi chục hàng"},
['custom_clear']= {"Custom", "NORMAL"},
['custom_puzzle']= {"Custom", "PUZZLE"},
@@ -1004,7 +1003,7 @@ C. Tay cầm chơi game (Gamepad):
"6 next 1 hold!",
"6 next 6 hold?!",
"20G thực chất là một chế độ mới đấy!",
- "Kỷ lục Sprint 40 hàng: 14.188s (Lurny)",
+ "Kỷ lục Sprint 40 hàng: 13.430s (WestL)",
"Rất gần nhưng lại rất xa",
"ALL SPIN!",
"Am G F G",
@@ -1125,7 +1124,7 @@ C. Tay cầm chơi game (Gamepad):
-- Techmino's birthday
"Ngày sinh nhật của Techmino? Hiện tại (đang giả định) là 26/T6.",
-- How to O-spin: Rotate 626 times in one second (mistaken)
- "Cách O-spin? Nhấn phím xoay 626 lần trong 1 giây (ĐÙA ĐẤY ĐỪNG TIN!)",
+ "Cách làm O-spin? Nhấn phím xoay 626 lần trong 1 giây (ĐÙA ĐẤY ĐỪNG TIN!)",
-- 2021 was the year of Techmino's online debut.
"2021 là năm ra mắt chế độ trực tuyến của Techmino.",
-- The Chinese name of this game is 'Block Research Institute'.
@@ -1133,15 +1132,15 @@ C. Tay cầm chơi game (Gamepad):
-- This game is not called Teachmino
"Tên game không phải là Teachmino!",
--
- "Muốn game có thứ gì đó đặc biệt lúc mở game? Hãy chỉnh đồng hồ trên điện thoại vào một ngày đặc biệt nào đó đi!",
+ "Hãy thử chỉnh đồng hồ trên điện thoại để xem xem, có thứ gì đó đặc biệt hay không?",
-- O-spin is a lie!
- {C.Y,"O-spin",C.Z," is a ",C.R,"lie",C.Z,"!"},
+ {C.Y,"O-spin",C.Z," là ",C.R,"lời nói dối",C.Z,"của em!"},
-- techminohaowan
"Hảo Techmino",
--
-- TIPS WHEN PLAYING
-- Don't act weak! Don't act weak! Don't act weak!
- "Đừng tỏ ra yếu đuối! Đừng tỏ ra yếu đuối! ĐỪNG TỎ RA YẾU ĐUỐI!",
+ "Đừng tỏ ra yếu đuối! Và KHÔNG BAO GIỜ tỏ ra yếu đuối!",
-- Warning: No pretending to be weak.
{C.R,"CẢNH BÁO! ",C.Z,"Đừng giả vờ yếu đuối"},
-- "Meow!"
@@ -1152,7 +1151,7 @@ C. Tay cầm chơi game (Gamepad):
-- Don't play with your phone if your homework isn't finished.
"Đừng chơi điện thoại khi bài tập về nhà còn chưa hoàn thành.",
-- Enabling vibration on some mobile systems may cause severe lag."
- "Bật rung trên một số điện thoại có thể làm cho chúng… phải thở oxy!",
+ "Bật rung có thể làm một số điện thoại phải thở oxy!",
-- Eat the button? Really? I suggest you play it back to see if you pressed it and how long it took you to press it"
"Phím không ăn? Hãy thử kiểm tra lại phím đi!",
-- Probably someone will read the tip
@@ -1160,31 +1159,43 @@ C. Tay cầm chơi game (Gamepad):
-- It seems like no one has reached a high level by playing with their feet yet.
"Hình như tới giờ chưa ai chơi xếp gạch giỏi bằng chân…",
-- Moderate gaming is good for the brain. Addiction to games is harmful. Plan your time
- "Chơi game vừa phải có thể tốt cho bộ não. Nhưng nếu nghiện thì toang! Nhớ lập thời gian biểu nhé!",
+ "Chơi game vừa phải có thể tốt cho bộ não. Nhưng nếu nghiện thì toang! Nhớ sắp xếp quỹ thời gian cho hợp lý nhé!",
-- The ability to dig is extremely important in battles!!!
"Khả năng đào xuống (downstacking) của bạn là RẤT QUAN TRỌNG trong chiến đấu!!!",
-- Skilled players of the Classic Tetris game are also formidable; don't underestimate them
"Đừng có mà xem thường những người chơi xếp gạch cổ điển! Chơi cái đó cũng khó không khác gì chơi xếp gạch hiện đại đâu.",
-- Classic Tetris and Modern Tetris are two different games; being skilled in one doesn't mean you'll be skilled in the other. You have to start from scratch.
- "Xếp gạch cổ điển và xếp gạch hiện đại là hai thể loại game khác nhau đấy! Giỏi một trong hai chưa chắc bạn giỏi cả bên còn lại đâu. Bạn phải học lại từ đầu đấy",
+ "Xếp gạch cổ điển và xếp gạch hiện đại là hai thể loại game khác nhau đấy! Giỏi một trong hai chưa chắc bạn giỏi cả bên còn lại đâu. Bạn đều phải học lại từ đầu đấy",
-- To protect the players' well-being, the game has a temporary and simplified anti-addiction system! (But you probably won't trigger it, haha)
"Để tránh việc người chơi nào đó chơi quá lâu, game đã có hệ thống chống nghiện đơn giản tạm thời (Nhưng bạn có lẽ sẽ không bao giờ kích hoạt chúng đâu, haha)",
-- Basic stacking and digging skills are crucial; those who neglect these two aspects often regret it (trust me)
- {"Kỹ năng xếp lên vào đào xuống là 2 kỹ năng RẤT quan trọng; những ai coi thường hay bỏ bê hai khía cạnh này thường hay bị bón hành súp mặt lờ (tin ",C.W,"MrZ",C.Z," đi!)"},
+ {"Kỹ năng xếp lên vào đào xuống là 2 kỹ năng RẤT quan trọng; những người hay bị bón hành hầu hết là những người đếch tôn trọng 2 kỹ năng này (tin lời ",C.W,"MrZ",C.Z," đi!)"},
-- Even if you're topped out, don't give up; every line of garbage can potentially become your weapon.
"Đừng bỏ cuộc khi đống hàng rác đang làm bạn sắp bị top out, bởi bạn có thể biến chúng trở thành đòn phản công.",
-- The video shown above is not a recording; it's the robot playing in real-time.
- "Cái ở trên là bản ghi sẵn hả? Không, là AI đang chơi trong thời gian thực đấy!",
+ "Cái ở trên là video hả? Không, là AI đang chơi trong thời gian thực đấy!",
-- Extended gaming sessions will gradually deteriorate your performance! Remember to take breaks when playing for a long time~
- "Thường xuyên chơi game lâu có thể khiến bạn có thể bị đuối sức (cả thể chất và tinh thần, tệ nhất có thể bị stall). Hãy nhớ nghỉ giải lao sau khi chơi lâu nhé!",
+ "Thường xuyên chơi game lâu có thể khiến bạn có thể bị đuối sức (cả thể chất và tinh thần, tệ nhất có thể bị stall). Hãy nhớ nghỉ giải lao sau khi chơi lâu nhé! Meow~",
-- Be careful of tenosynovitis!
{C.R,"CẢNH BÁO! ",C.Z,"Bệnh viêm bao gân cổ tay!"},
-- The button with a question mark in the bottom-right corner is the game manual (assuming you haven't enabled the Simple mode).
- "Cái nút "..CHAR.icon.help.." ở góc phải dưới cùng trong menu (không bật chế độ Đơn giản) đấy hả? Nó là manual (hướng dẫn sử dụng) của game đấy!",
+ "Cái nút "..CHAR.icon.help.." ở màn hình chính (giả sử bạn chưa mở Chế độ đơn giản) là hướng dẫn sử dụng của Techmino đấy!",
-- If you're new to blocks, just play more games; there isn't much specific targeted practice beyond 40 lines in two minutes
"Bạn mới tập chơi xếp gạch à? Nếu vậy cứ chơi nhiều lên. Không có nhiều mục tiêu luyện tập cụ thể ngoài xóa 40 hàng trong 2 phút đâu!",
--
"Hãy ra ngoài và chạm cỏ đi!",
+ -- [SELF-MADE]
+ {"Có thuật ngữ nào bạn không hiểu à? Hãy tra ",C.R,"Z",C.Z,"ictionary!"}, -- Have a term you don't understand? Check Zictionary
+ -- Maybe saying this you may not believe, but there are many tips here never appear in English!
+ {"Nói cái này có thể bạn không tin, ",C.lSea,"nhưng có nhiều mẹo trong số này bạn sẽ không bao giờ thấy ở trong Techmino tiếng Anh đâu!"},
+
+--
+ -- OTHER
+ "\"Zictionary\" có 2 tên gọi khác, đó là: \"TetroDictionary\" và \"Little Z Dictionary\"",
+ "\"Zictionary\" có thể có vài chỗ nghe bất tự nhiên. Cứ thoải mái gửi bản chỉnh sửa lên GitHub đi!",
+ "Làm ơn đừng đánh đồng Korobeiniki với bản nhạc A. Hai nhạc này có sự khác biệt rất rõ trong giai điệu nhé!",
+ "Làm cách nào để mời người khác cùng chơi xếp gạch với mình? Xếp gạch giờ không còn đơn giản như trước đây nữa...",
+
--
-- MrZ
{C.W,"uid:225238922"},
@@ -1192,7 +1203,7 @@ C. Tay cầm chơi game (Gamepad):
--
-- Z SAID
-- I can't write cool music (crying)
- {C.W,"Z: ",C.Z,"Tôi không tài nào viết nổi một bản nhạc nào trông ngầu cả (sadge)."},
+ {C.W,"Z: ",C.Z,"Tôi không tài nào viết nổi một bản nhạc nào ra hồn cả (sadge)."},
-- I haven't studied music composition. I just composed it myself. If you really think it's good, that's great!
{C.W,"Z: ",C.Z,"Tôi chưa từng học sáng tác nhạc, và tôi chỉ tự sáng tác chúng. Nếu bạn thấy những bản nhạc này hay, thật tuyệt!"},
-- What else can I write for tips?
@@ -1222,7 +1233,7 @@ C. Tay cầm chơi game (Gamepad):
"Techmino.exe hiện không phản hồi",
"Techmino đã đột ngột dừng lại",
-- If you have a real interest in programming, I recommend Lua. Easy installation, simple syntax, and fast execution speed. Stay away from boring school programming (haha)
- {"Nếu bạn thực sự có hứng thú trong lập trình, tôi đề xuất sử dụng Lua. Dễ cài đặt, cú pháp đơn giản, tốc độ thực thi nhanh. Hãy tránh xa những tiết học lập trình chán ngắt ở trên trường luôn đi! (haha) - ",C.W,"MrZ",C.Z," said."},
+ {C.W,"MrZ:",C.Z,"Nếu bạn thực sự có hứng thú trong lập trình, tôi đề xuất sử dụng Lua. Dễ cài, cú pháp đơn giản, tốc độ thực thi nhanh. Hãy tránh xa những tiết học lập trình chán ngắt ở trên trường luôn đi! (haha)"},
--
-- CHANGELOG
{C.lW, "V0.0.091726",": ",C.Z, "Thêm hệ thống xoay TRS"},
@@ -1269,18 +1280,20 @@ C. Tay cầm chơi game (Gamepad):
--
-- SEA'S JOKE
{C.W,"MrZ",C.Z," còn có một biệt danh dễ thương hơn, đó là ",C.W,"Z-Chan"},
+ {C.W,"Z-Chan",C.Z," cute quá. Tui không cưỡng lại được... HELP!"},
{C.lSea,"Sea: ",C.Z,"Tui không có đủ mặn để viết joke. Nên một số câu đùa đang chạy ở đây được viết bởi ",C.yellow,"Shard Nguyễn",C.Z,". \"Em cảm ơn anh!\""},
{C.lSea,"Sea: ",C.Z,"Tui đang tự hỏi liệu còn bao nhiêu lỗi tui bỏ sót lúc dịch game không? Tính ra tui đã cập nhật đi cập nhật lại cũng 4-5 lần rồi."},
{"Cộng đồng Tetris ",C.R,"Việt ",C.lY,"Nam ",C.Z,": https://discord.gg/jX7BX9g"}, -- Tetris Vietnam (TVN)
{"\"Tetris Việt Nam\"? Không, đó là \"Hội phụ hồ Việt Nam\" (https://discord.gg/hoiphuhovietnam)"},
- "\"Zictionary\" có 2 tên gọi khác, đó là: \"TetroDictionary\" và \"Little Z Dictionary\"",
"Mình xin phép ủng hộ cho player này. Ủng hộ càng nhiều tỉ lệ thắng càng cao!",
{"Aiiiii mua cần phô mai ủng hộ ",C.yellow,"Chủ tiệm phô mai",C.Z," không?"}, -- A joke in TVN
-- Who will you choose? A girl that can break up to you and make you sad
-- Or choose Katyusha that can warm your heart and 40ha land of enemy.
- "Bạn sẽ chọn ai? Một em gái có thể chia tay và làm bạn buồn? Hay là chọn em Katyusha có thể làm ấm lòng bạn và 40ha đất kẻ thù?", -- Based on a comment in https://www.youtube.com/watch?v=nczdLwTyWmY
+ "Bạn sẽ chọn ai? Một em gái nào đó có thể chia tay và làm bạn buồn? Hay là chọn em gái Katyusha có thể làm ấm lòng bạn và 40ha đất kẻ thù?", -- Based on a comment in https://www.youtube.com/watch?v=nczdLwTyWmY
+ -- What if the ".io" domain disappear? What will happen with TETR.IO?
+ "Nếu tên miền cấp quốc gia '.io' biến mất, chuyện gì sẽ xảy ra với TETR.IO?",
},
pumpkin="Tôi là một quả bí ngô",
}
diff --git a/parts/language/lang_zh.lua b/parts/language/lang_zh.lua
index 7eccf2fe..7cad4a74 100644
--- a/parts/language/lang_zh.lua
+++ b/parts/language/lang_zh.lua
@@ -43,7 +43,7 @@ return {
infHeightOn="无限高度 开",
infHeightOff="无限高度 关",
infHeightHint="用功能键1切换",
- -- highestGrade="(highest: $1)",
+ highestGrade="最高段位: $1",
speedLV="速度等级",
piece="块数",line="行数",atk="攻击",eff="效率",
@@ -454,14 +454,13 @@ return {
tas="TAS (T)",
},
net_menu={
- league="Tech League",
- ffa="FFA",
+ galaxim="Galaxim",
rooms="房间列表",
resetPW="重置密码",
logout="退出登录",
},
- net_league={
- match="匹配对手",
+ net_galaxim={
+ match="进入模拟",
},
net_rooms={
password="密码",
@@ -614,6 +613,7 @@ return {
das="DAS:",arr="ARR:",
dascut="DAS打断:",
+ irscut="IRS打断",
dropcut="误硬降打断:",
sddas="软降DAS:",sdarr="软降ARR:",
ihs="提前Hold",
@@ -910,12 +910,9 @@ return {
['master_g']= {"大师", "段位考试", "20G段位考试"},
['master_ex']= {"宗师", "EX", "成为方块大师"},
['master_instinct']={"大师", "本能", "当前块在出现后一小会后会隐形"},
- ['strategy_e']= {"策略堆叠", "简单", "20G堆叠中速决策练习"},
+ ['strategy_e_plus']={"策略堆叠", "简单+", "20G堆叠中速决策练习\n无Hold"},
['strategy_h']= {"策略堆叠", "困难", "20G堆叠快速决策练习"},
['strategy_u']= {"策略堆叠", "极限", "20G堆叠极速决策练习"},
- ['strategy_e_plus']={"策略堆叠", "简单+", "20G堆叠中速决策练习\n无Hold"},
- ['strategy_h_plus']={"策略堆叠", "困难+", "20G堆叠快速决策练习\n无Hold"},
- ['strategy_u_plus']={"策略堆叠", "极限+", "20G堆叠极速决策练习\n无Hold"},
['blind_e']= {"隐形", "半隐", "不强大脑"},
['blind_n']= {"隐形", "全隐", "挺强大脑"},
['blind_h']= {"隐形", "瞬隐", "很强大脑"},
@@ -967,6 +964,7 @@ return {
['infinite']= {"无尽", "", "沙盒"},
['infinite_dig']= {"无尽:挖掘", "", "挖呀挖呀挖"},
['marathon_inf']= {"马拉松", "无尽", "无尽马拉松"},
+ ['spinren']= {"Spin连击", "效率", "掌管效率的神"},
['custom_clear']= {"自定义", "普通"},
['custom_puzzle']= {"自定义", "拼图"},
@@ -984,7 +982,7 @@ return {
"1next 6hold!",
"3.1415926535897932384(\\d{3})",
"3next 1hold?",
- "40行世界纪录:14.188s by Lurny",
+ "40行世界纪录: 13.430s by WestL",
"6236326236327175",
"626in1",
"6next 1hold!",
@@ -1060,7 +1058,7 @@ return {
"游戏原声已上架网易云音乐",
"有建议的话可以反馈给作者~",
"这不是休闲游戏……别怪关卡要求太高,多练吧",
- "中文方块百科全书:tetris.huijiwiki.com",
+ "中文方块百科全书:tetriswiki.cn",
"众所周知mac不能拿来玩游戏",
"作业没做完别玩手机",
"作者40行sub26了",
@@ -1207,7 +1205,7 @@ return {
"豆知识[016]本游戏的B2B是气槽机制,和传统的开关机制不一样哦",
"豆知识[017]本游戏内置了几个休(yìng)闲(hé)小游戏哦~",
"豆知识[018]本游戏在设计的时候受到了大量其他块游甚至一些音游的启发",
- "豆知识[019]必须要软降才能到达的位置都会判定为极简操作",
+ "豆知识[019]必须要软降才能到达的位置不会被判定为非极简操作",
"豆知识[020]别看攻击效率不高,其实消四还是很强的",
"豆知识[021]别问游戏名字怎么取的,问就是随便想的",
"豆知识[022]不同人打40行最合适的方式不一样,s1w/63/散消/s2w……",
diff --git a/parts/language/lang_zh_code.lua b/parts/language/lang_zh_code.lua
index 4d96ded2..998f410a 100644
--- a/parts/language/lang_zh_code.lua
+++ b/parts/language/lang_zh_code.lua
@@ -375,14 +375,13 @@ return {
tas="TAS(); (T)",
},
net_menu={
- league="M.TechLeague();",
- ffa="M.FFA",
+ galaxim="M.Galaxim();",
rooms="M.Rooms();",
resetPW="M.ResetPW",
logout="M.Logout();",
},
- net_league={
- match="TL.Match();",
+ net_galaxim={
+ match="GX.Enter();",
},
net_rooms={
password="Password=",
@@ -535,6 +534,7 @@ return {
das="Set.DAS=",arr="Set.SRR=",
dascut="Set.DASCut=",
+ irscut="Set.IRSCut=",
dropcut="Set.DropCut=",
sddas="Set.SDDAS=",sdarr="Set.SDARR=",
ihs="Set.IHS",
@@ -831,12 +831,9 @@ return {
['master_g']= {"Master(Graded);", "", "20G段位考试"},
['master_ex']= {"Master(EX);", "", "成为方块大师"},
['master_instinct']= {"Master(Instinct);", "", "当前块在出现后一小会后会隐形"},
- ['strategy_e']= {"Strategy(Easy);", "", "20G堆叠中速决策练习"},
+ ['strategy_e_plus']= {"Strategy(EasyP);", "", "20G堆叠中速决策练习\n无Hold"},
['strategy_h']= {"Strategy(Hard);", "", "20G堆叠快速决策练习"},
['strategy_u']= {"Strategy(Ultimate);", "", "20G堆叠极速决策练习"},
- ['strategy_e_plus']= {"Strategy(EasyP);", "", "20G堆叠中速决策练习\n无Hold"},
- ['strategy_h_plus']= {"Strategy(HardP);", "", "20G堆叠快速决策练习\n无Hold"},
- ['strategy_u_plus']= {"Strategy(UltimateP);", "", "20G堆叠极速决策练习\n无Hold"},
['blind_e']= {"Blind(Slow);", "", "不强大脑"},
['blind_n']= {"Blind(Fast);", "", "挺强大脑"},
['blind_h']= {"Blind(Instant);", "", "很强大脑"},
@@ -884,10 +881,11 @@ return {
['sprintAtk']= {"Sprint(100ATK);", "", "打出100攻击"},
['sprintEff']= {"Sprint(EFF);", "", "40行内打出更高的攻击"},
['zen']= {"Zen(200L);", "", "不限时200行"},
- ['ultra']= {"Ultra(EXTRA);", "", "在两分钟内尽可能拿到最多的分数"},
+ ['ultra']= {"Ultra(Extra);", "", "在两分钟内尽可能拿到最多的分数"},
['infinite']= {"Infinite();", "", "沙盒"},
['infinite_dig']= {"InfDig();", "", "挖呀挖呀挖"},
['marathon_inf']= {"Marathon(Inf);", "", "无尽马拉松"},
+ ['spinren']= {"Spinren(EFF)", "", "掌管效率的神"},
['custom_clear']= {"Custom(Clear);", ""},
['custom_puzzle']= {"Custom(Puzzle);", ""},
diff --git a/parts/language/lang_zh_trad.lua b/parts/language/lang_zh_trad.lua
index 5ded89fd..e56a6175 100644
--- a/parts/language/lang_zh_trad.lua
+++ b/parts/language/lang_zh_trad.lua
@@ -43,7 +43,7 @@ return {
infHeightOn="無限高度 開",
infHeightOff="無限高度 關",
infHeightHint="用功能鍵1切換",
- -- highestGrade="(highest: $1)",
+ highestGrade="最高段位: $1",
speedLV="速度等級",
piece="塊數",line="行數",atk="攻擊",eff="效率",
@@ -426,14 +426,13 @@ return {
tas="TAS (T)",
},
net_menu={
- league="Tech League",
- ffa="FFA",
+ galaxim="Galaxim",
rooms="房間列表",
resetPW="重設密碼",
logout="登出",
},
- net_league={
- match="匹配對手",
+ net_galaxim={
+ match="进入模拟",
},
net_rooms={
password="密碼",
@@ -586,6 +585,7 @@ return {
das="DAS",arr="ARR",
dascut="DAS打斷",
+ irscut="IRS打斷",
dropcut="誤硬降打斷",
sddas="軟降DAS",sdarr="軟降ARR",
ihs="提前Hold",
@@ -882,12 +882,9 @@ return {
['master_g']= {"大師", "段位考試", "20G段位考試"},
['master_ex']= {"宗師", "EX", "成為方塊大師"},
['master_instinct']={"大師", "本能", "隱藏當前塊"},
- ['strategy_e']= {"策略堆疊", "簡單", "20G堆疊中速決策練習"},
+ ['strategy_e_plus']={"策略堆疊", "簡單+", "20G堆疊中速決策練習\n無Hold"},
['strategy_h']= {"策略堆疊", "困難", "20G堆疊快速決策練習"},
['strategy_u']= {"策略堆疊", "極限", "20G堆疊極速決策練習"},
- ['strategy_e_plus']={"策略堆疊", "簡單+", "20G堆疊中速決策練習\n無Hold"},
- ['strategy_h_plus']={"策略堆疊", "困難+", "20G堆疊快速決策練習\n無Hold"},
- ['strategy_u_plus']={"策略堆疊", "極限+", "20G堆疊極速決策練習\n無Hold"},
['blind_e']= {"隱形", "半隱", "不強大腦"},
['blind_n']= {"隱形", "全隱", "挺強大腦"},
['blind_h']= {"隱形", "瞬隱", "很強大腦"},
@@ -940,6 +937,7 @@ return {
['infinite']= {"無盡", "", "沙盒"},
['infinite_dig']= {"無盡:挖掘", "", "挖呀挖呀挖"},
['marathon_inf']= {"馬拉松", "無盡", "無盡馬拉松"},
+ ['spinren']= {"Spin連擊", "效率", "掌管效率的神"},
['custom_clear']= {"自定義", "普通"},
['custom_puzzle']= {"自定義", "拼圖"},
diff --git a/parts/modes.lua b/parts/modes.lua
index 67801152..e2a9848d 100644
--- a/parts/modes.lua
+++ b/parts/modes.lua
@@ -30,7 +30,7 @@ return {
{name='dig_eff_400l', x=-1200,y=0, size=40,shape=1,icon="dig_eff"},
{name='marathon_n', x=0, y=-600, size=60,shape=1,icon="marathon", unlock={'marathon_h','solo_e','round_e','big_n','blind_e','classic_e','survivor_e','c4wtrain_n','pctrain_n','sprintAtk','zen','construct_sg'}},
- {name='marathon_h', x=0, y=-800, size=50,shape=1,icon="marathon", unlock={'master_n','strategy_e'}},
+ {name='marathon_h', x=0, y=-800, size=50,shape=1,icon="marathon", unlock={'master_n','strategy_e_plus'}},
{name='solo_e', x=-600, y=-1000,size=40,shape=1,icon="solo", unlock={'solo_n'}},
{name='solo_n', x=-800, y=-1000,size=40,shape=1,icon="solo", unlock={'solo_h'}},
@@ -62,12 +62,9 @@ return {
{name='master_g', x=0, y=-1600,size=40,shape=3,icon="master"},
{name='master_ex', x=170, y=-1450,size=40,shape=2,icon="master_ex"},
- {name='strategy_e', x=-150, y=-1020,size=40,shape=3,icon="master", unlock={'strategy_e_plus'}},
- {name='strategy_h', x=-150, y=-1150,size=35,shape=3,icon="master", unlock={'strategy_h_plus'}},
- {name='strategy_u', x=-150, y=-1280,size=30,shape=2,icon="master", unlock={'strategy_u_plus'}},
- {name='strategy_e_plus', x=-300, y=-1120,size=40,shape=3,icon="master"},
- {name='strategy_h_plus', x=-300, y=-1250,size=35,shape=3,icon="master"},
- {name='strategy_u_plus', x=-300, y=-1380,size=30,shape=2,icon="master"},
+ {name='strategy_e_plus', x=-150, y=-1020,size=40,shape=3,icon="master"},
+ {name='strategy_h', x=-150, y=-1150,size=35,shape=3,icon="master"},
+ {name='strategy_u', x=-150, y=-1280,size=30,shape=2,icon="master"},
{name='blind_e', x=150, y=-700, size=40,shape=1,icon="hidden", unlock={'blind_n','master_instinct'}},
{name='blind_n', x=150, y=-800, size=40,shape=1,icon="hidden2", unlock={'blind_h'}},
@@ -88,29 +85,30 @@ return {
{name='survivor_l', x=1050, y=-600, size=40,shape=3,icon="survivor", unlock={'survivor_u'}},
{name='survivor_u', x=1250, y=-600, size=40,shape=2,icon="survivor"},
- {name='attacker_h', x=450, y=-800, size=40,shape=1,icon="attack", unlock={'attacker_u'}},
- {name='attacker_u', x=450, y=-1000,size=40,shape=1,icon="attack"},
+ {name='attacker_h', x=450, y=-800, size=40,shape=3,icon="attack", unlock={'attacker_u'}},
+ {name='attacker_u', x=450, y=-1000,size=40,shape=2,icon="attack"},
- {name='defender_n', x=650, y=-800, size=40,shape=1,icon="defend", unlock={'defender_l'}},
- {name='defender_l', x=650, y=-1000,size=40,shape=1,icon="defend"},
+ {name='defender_n', x=650, y=-800, size=40,shape=3,icon="defend", unlock={'defender_l'}},
+ {name='defender_l', x=650, y=-1000,size=40,shape=2,icon="defend"},
- {name='dig_h', x=850, y=-800, size=40,shape=1,icon="dig", unlock={'dig_u'}},
- {name='dig_u', x=850, y=-1000,size=40,shape=1,icon="dig"},
+ {name='dig_h', x=850, y=-800, size=40,shape=3,icon="dig", unlock={'dig_u'}},
+ {name='dig_u', x=850, y=-1000,size=40,shape=2,icon="dig"},
- {name='c4wtrain_n', x=700, y=-450, size=40,shape=1,icon="pc", unlock={'c4wtrain_l'}},
- {name='c4wtrain_l', x=900, y=-450, size=40,shape=1,icon="pc"},
+ {name='c4wtrain_n', x=800, y=-450, size=40,shape=1,icon="pc", unlock={'c4wtrain_l'}},
+ {name='c4wtrain_l', x=950, y=-450, size=40,shape=3,icon="pc"},
- {name='pctrain_n', x=700, y=-300, size=40,shape=1,icon="pc", unlock={'pctrain_l','pc_n'}},
- {name='pctrain_l', x=900, y=-300, size=40,shape=1,icon="pc"},
-
- {name='pc_n', x=800, y=-140, size=40,shape=1,icon="pc", unlock={'pc_h'}},
- {name='pc_h', x=950, y=-140, size=40,shape=3,icon="pc", unlock={'pc_l','pc_inf'}},
- {name='pc_l', x=1100, y=-140, size=40,shape=3,icon="pc"},
- {name='pc_inf', x=1100, y=-280, size=40,shape=2,icon="pc"},
-
- {name='sprintAtk', x=500, y=-280, size=40,shape=1,icon="sprint2", unlock={'sprintEff','tech_n','tech_finesse','tsd_e','backfire_n'}},
+ {name='sprintAtk', x=500, y=-300, size=40,shape=1,icon="sprint2", unlock={'sprintEff','tech_n','tech_finesse','tsd_e','backfire_n','spinren'}},
{name='sprintEff', x=360, y=-150, size=40,shape=1,icon="sprint2"},
+ {name='spinren', x=720, y=-260, size=40,shape=3,icon="tsd"},
+
+ {name='pctrain_n', x=950, y=-300, size=40,shape=1,icon="pc", unlock={'pctrain_l','pc_n'}},
+ {name='pctrain_l', x=1100, y=-300, size=40,shape=3,icon="pc"},
+ {name='pc_n', x=950, y=-150, size=40,shape=3,icon="pc", unlock={'pc_h'}},
+ {name='pc_h', x=1100, y=-150, size=40,shape=2,icon="pc", unlock={'pc_l','pc_inf'}},
+ {name='pc_l', x=1250, y=-150, size=40,shape=2,icon="pc"},
+ {name='pc_inf', x=1250, y=-300, size=40,shape=2,icon="pc"},
+
{name='tech_n', x=400, y=20, size=40,shape=1,icon="tech", unlock={'tech_n_plus','tech_h'}},
{name='tech_n_plus', x=200, y=-10, size=40,shape=3,icon="tech_plus"},
{name='tech_h', x=400, y=170, size=40,shape=1,icon="tech", unlock={'tech_h_plus','tech_l'}},
@@ -122,8 +120,8 @@ return {
{name='tech_finesse_f', x=1050, y=20, size=40,shape=1,icon="tech_plus"},
{name='tsd_e', x=700, y=100, size=40,shape=1,icon="tsd", unlock={'tsd_h'}},
- {name='tsd_h', x=860, y=160, size=40,shape=1,icon="tsd", unlock={'tsd_u'}},
- {name='tsd_u', x=1050, y=170, size=40,shape=1,icon="tsd"},
+ {name='tsd_h', x=860, y=160, size=40,shape=3,icon="tsd", unlock={'tsd_u'}},
+ {name='tsd_u', x=1050, y=170, size=40,shape=2,icon="tsd"},
{name='backfire_n', x=640, y=270, size=40,shape=1,icon="backfire", unlock={'backfire_h'}},
{name='backfire_h', x=790, y=300, size=40,shape=1,icon="backfire", unlock={'backfire_l'}},
diff --git a/parts/modes/c4wtrain_n.lua b/parts/modes/c4wtrain_n.lua
index 564542ae..e9889eb8 100644
--- a/parts/modes/c4wtrain_n.lua
+++ b/parts/modes/c4wtrain_n.lua
@@ -6,23 +6,22 @@ return {
eventSet='c4wBase',
bg='rgb',bgm='oxygen',
},
- score=function(P) return {math.min(P.modeData.maxCombo,100),P.stat.time} end,
- scoreDisp=function(D) return STRING.time(D[2]).." "..D[1].." Combo" end,
- comp=function(a,b) return a[2]b[1] end,
+ score=function(P) return {math.min(P.stat.row,100),P.stat.time} end,
+ scoreDisp=function(D) return D[1].." Lines "..STRING.time(D[2]) end,
+ comp=function(a,b) return a[1]>b[1] or a[1]==b[1] and a[2]=100 then
local T=P.stat.time
return
- T<=32 and 5 or
- T<=50 and 4 or
- T<=80 and 3 or
+ T<=32.6 and 5 or
+ T<=49.5 and 4 or
+ T<=94.2 and 3 or
2
else
return
- L>=60 and 2 or
- L>=30 and 1 or
- L>=10 and 0
+ L>=42 and 1 or
+ L>=26 and 0
end
end,
}
diff --git a/parts/modes/custom_clear.lua b/parts/modes/custom_clear.lua
index 06ac187a..74b9814b 100644
--- a/parts/modes/custom_clear.lua
+++ b/parts/modes/custom_clear.lua
@@ -1,3 +1,5 @@
+require'parts.scenes.customGame'.initialize()
+
return {
env={},
load=function()
@@ -12,10 +14,11 @@ return {
PLY.newPlayer(1)
local AItype=GAME.modeEnv.opponent:sub(1,2)
local AIlevel=tonumber(GAME.modeEnv.opponent:sub(-1))
+ local useHold=GAME.modeEnv.holdCount>0 and GAME.modeEnv.holdMode=='hold'
if AItype=='9S' then
- PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=GAME.modeEnv.holdCount})
+ PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=useHold})
elseif AItype=='CC' then
- PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=GAME.modeEnv.holdCount,node=20000+5000*AIlevel})
+ PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=useHold,node=20000+5000*AIlevel})
end
for _,P in next,PLY_ALIVE do
diff --git a/parts/modes/custom_puzzle.lua b/parts/modes/custom_puzzle.lua
index efb43f32..ddda4752 100644
--- a/parts/modes/custom_puzzle.lua
+++ b/parts/modes/custom_puzzle.lua
@@ -1,6 +1,8 @@
local gc_setColor,gc_draw=love.graphics.setColor,love.graphics.draw
local ply_applyField=PLY.draw.applyField
+require'parts.scenes.customGame'.initialize()
+
return {
env={
fkey1=function(P) P.modeData.showMark=1-P.modeData.showMark end,
@@ -54,10 +56,11 @@ return {
local AItype=GAME.modeEnv.opponent:sub(1,2)
local AIlevel=tonumber(GAME.modeEnv.opponent:sub(-1))
PLY.newPlayer(1)
+ local useHold=GAME.modeEnv.holdCount>0 and GAME.modeEnv.holdMode=='hold'
if AItype=='9S' then
- PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=GAME.modeEnv.holdCount})
+ PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=useHold})
elseif AItype=='CC' then
- PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=GAME.modeEnv.holdCount,node=20000+5000*AIlevel})
+ PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=useHold,node=20000+5000*AIlevel})
end
end,
savePrivate=function()
diff --git a/parts/modes/dig_quad_10l.lua b/parts/modes/dig_quad_10l.lua
index 601b3321..7c74f5f7 100644
--- a/parts/modes/dig_quad_10l.lua
+++ b/parts/modes/dig_quad_10l.lua
@@ -35,13 +35,13 @@ return {
comp=function(a,b) return a[1]>b[1] or a[1]==b[1] and a[2]=7 and 4 or
dig>=5 and 3 or
dig>=3 and 2 or
dig>=2 and 1 or
0
+ )-math.floor((P.stat.clears[4]-P.stat.dig_quad)^.62),0,5)
end,
}
diff --git a/parts/modes/spinren.lua b/parts/modes/spinren.lua
new file mode 100644
index 00000000..1b4c53a6
--- /dev/null
+++ b/parts/modes/spinren.lua
@@ -0,0 +1,101 @@
+local skip
+---@param RND love.RandomGenerator
+local function randomizer(RND)
+ local last=RND:random(2)==1 and 1 or 4
+ local function get_next()
+ local list={1,2,3,1,3,2}
+ local ret=list[last]
+ last=last+1
+ if last>6 then last=1 end
+ return ret
+ end
+ local bag={}
+ local function fill_bag()
+ local weights=0
+ while weights<24 do
+ local x=get_next()
+ table.insert(bag,x)
+ weights=weights+(x==1 and 2 or 3)
+ end
+ local pos=RND:random(#bag)+1
+ table.insert(bag,pos,4)
+ if skip==1 then skip=0 end
+ end
+ return function()
+ if #bag==0 then fill_bag() end
+ return table.remove(bag,1)
+ end
+end
+local lines={
+ {1,1,1,1,0,0,1,1,1,1},
+ {1,1,1,0,0,0,1,1,1,1},
+ {1,1,1,1,0,0,0,1,1,1},
+ {1,1,1,0,0,0,0,1,1,1}
+}
+local function get_lines(n,P)
+ local ret={}
+ for _=1,n do
+ local L=TABLE.shift(lines[P.randomizer_spinren()])
+ for i=1,#L do
+ if L[i]==1 then
+ L[i]=P.modeData.colorSet[P.holeRND:random(4)]
+ end
+ end
+ table.insert(ret,L)
+ end
+ return ret
+end
+
+return {
+ load=function()
+ PLY.newPlayer(1)
+ local P=PLY_ALIVE[1]
+ P.modeData.colorSet={}
+ for i=1,4 do
+ P.modeData.colorSet[i]=P.holeRND:random(25)
+ end
+ P.randomizer_spinren=randomizer(P.holeRND)
+ -- table.insert(P.field,1,LINE.new(0))
+ -- P.field[1][1]=18
+ -- P.field[1][2]=18
+ -- P.field[1][9]=18
+ -- P.field[1][10]=18
+ -- table.insert(P.visTime,1,LINE.new(20))
+ P:pushLineList(get_lines(18,P))
+ P.fieldBeneath=0
+ end,
+ env={
+ lock=1e99,
+ drop=1e99,
+ minsdarr=3,
+ infHold=true,
+ highCam=false,
+ bgm='lounge',
+ eventSet='sprintEff_40',
+ hook_drop=function(P)
+ if P.lastPiece.row==0 then
+ if P.stat.row<10 then
+ P:lose()
+ else
+ P:win('finish')
+ end
+ end
+ local up=MATH.clamp(22-P.stat.row+P.lastPiece.row,0,P.lastPiece.row)
+ P:pushLineList(get_lines(up,P))
+ end
+ },
+ score=function(P) return {P.stat.atk/P.stat.row,P.stat.time} end,
+ scoreDisp=function(D) return ("%.2f"):format(D[1]).." Efficiency "..STRING.time(D[2]) end,
+ comp=function(a,b) return a[1]>b[1] or a[1]==b[1] and a[2]=10 and 5 or
+ E>=9 and 4 or
+ E>=8 and 3 or
+ E>=6 and 2 or
+ E>=3 and 1 or
+ 0
+ end
+}
diff --git a/parts/net.lua b/parts/net.lua
index 8b67f308..5ab3a99b 100644
--- a/parts/net.lua
+++ b/parts/net.lua
@@ -29,8 +29,8 @@ local NET={
onlineCount="_",
- textBox=WIDGET.newTextBox{name='texts',x=340,y=80,w=600,h=560},
- inputBox=WIDGET.newInputBox{name='input',x=340,y=660,w=600,h=50,limit=256},
+ textBox=WIDGET.newTextBox{name='texts',x=20,y=110,w=980,h=500},
+ inputBox=WIDGET.newInputBox{name='input',x=20,y=630,w=980,h=50,limit=256},
}
function NET.freshRoomAllReady()
@@ -187,17 +187,48 @@ function NET.getAvatar(uid)
end
end)
end
-function NET.getNotice(lang,count)
+
+local noticeLang={
+ en='en_us',
+ fr='en_us', -- fr_fr
+ es='en_us', -- es_es
+ id='en_us', -- id_id
+ pt='en_us', -- pt_pt
+ symbol='en_us', -- gl_os
+ ja='en_us', -- ja_jp
+ vi='en_us', -- vi_vn
+ zh='zh_cn',
+ zh_trad='zh_tw',
+ zh_code='zh_cn',
+}
+function NET.launchNotice()
+ TASK.new(function()
+ local res=getMsg({
+ pool='getNotice',
+ path='/techmino/api/v1/notice?language='..noticeLang[SETTING.locale]..'&lastCount=1',
+ },6.26)
+
+ if res and res.code==200 then
+ local opt=res.data.contents[1]
+ if opt then
+ MES.new('info',opt.content,12.6)
+ else
+ MES.new('info',text.Techrater.NoticeManager.noticeNotFound)
+ end
+ end
+ end)
+end
+function NET.getNotice(count)
WAIT{timeout=6.26}
TASK.new(function()
local res=getMsg({
pool='getNotice',
- path='/techmino/api/v1/notice?language='..(lang or 'zh_cn')..'&lastCount='..(count or 5),
+ path='/techmino/api/v1/notice?language='..noticeLang[SETTING.locale]..'&lastCount='..(count or 5),
},6.26)
- if res and res.code==200 and type(res.data)=='string' then
- local dataStr=""
- SCN.go('notice',nil,dataStr)
+ if res and res.code==200 then
+ WAIT.interrupt()
+ SCN.go('notice',nil,noticeLang[SETTING.locale],res.data.contents)
end
end)
end
@@ -393,10 +424,19 @@ function NET.wsCallBack.room_chat(body)
if SCN.cur~='net_game' then return end
TASK.unlock('receiveMessage')
TASK.lock('receiveMessage',1)
- NET.textBox:push{
- COLOR.Z,_getFullName(body.data.playerId).." ",
- COLOR.N,body.data.message,
- }
+
+ local name=_getFullName(body.data.playerId).." "
+ -- P/s: we need to wrap both name and message, not just only message
+ local _,msgWrapped=FONT.get(NET.inputBox.font):getWrap(name..body.data.message,950)
+ -- We don't want to see the name repeat twice :skull:
+ msgWrapped[1]=string.gsub(msgWrapped[1],name,"",1)
+ -- Push the name in white and first line of message in blue first
+ NET.textBox:push{COLOR.Z,name,COLOR.N,msgWrapped[1]}
+ for i, line in ipairs(msgWrapped) do
+ if i ~= 1 then
+ NET.textBox:push{COLOR.N,msgWrapped[i]}
+ end
+ end
end
function NET.wsCallBack.room_create(body)
MES.new('check',text.createRoomSuccessed)
diff --git a/parts/patron.lua b/parts/patron.lua
index 3f923e13..c449c246 100644
--- a/parts/patron.lua
+++ b/parts/patron.lua
@@ -29,11 +29,13 @@ return {
{font=65,name="怀沙"},
{font=65,name="星街书婉"},
{font=65,name="老板来两份薯条"},
+ {font=65,name="yumucy"},
{font=65,name="[**昆]"},
{font=65,name="[**浩]"},
{font=65,name="sakurw"},
{font=65,name="[**霖]"},
{font=65,name="KK"},
+ {font=65,name="武仰绍"},
{font=25,name="八零哥"},
{font=25,name="蕴空之灵"},
@@ -151,4 +153,9 @@ return {
{font=25,name="电蜥蜴"},
{font=25,name="浮芙fufu"},
{font=25,name="NOname_awa"},
+ {font=65,name="liaotianhao"},
+ {font=65,name="Aquamarine"},
+ {font=65,name="jacky"},
+ {font=65,name="方块丶小刘"},
+ {font=65,name="DX3906"},
}
diff --git a/parts/player/draw.lua b/parts/player/draw.lua
index c6c167c1..fee32bfa 100644
--- a/parts/player/draw.lua
+++ b/parts/player/draw.lua
@@ -177,12 +177,12 @@ local function _drawField(P,showInvis)
if P.falling==0 then-- Blocks only
if ENV.upEdge then
gc_setShader(shader_lighter)
- gc_translate(0,-4)
+ gc_translate(0,-6)
--
for j=start,min(start+21,#F) do _drawRow(texture,j,V[j],F[j]) end
--
gc_setShader(shader_fieldSatur)
- gc_translate(0,4)
+ gc_translate(0,6)
else
gc_setShader(shader_fieldSatur)
end
@@ -197,7 +197,7 @@ local function _drawField(P,showInvis)
if ENV.upEdge then
gc_push('transform')
gc_setShader(shader_lighter)
- gc_translate(0,-4)
+ gc_translate(0,-6)
--
for j=start,min(start+21,#F) do
while j==P.clearingRow[h] do
diff --git a/parts/player/gameEnv0.lua b/parts/player/gameEnv0.lua
index 85fef2dc..5ecace2c 100644
--- a/parts/player/gameEnv0.lua
+++ b/parts/player/gameEnv0.lua
@@ -1,8 +1,9 @@
return {
das=10,arr=2,
- dascut=0,dropcut=0,
+ dascut=0,irscut=6,dropcut=0,
sddas=2,sdarr=2,
ihs=true,irs=true,ims=true,
+ logicalIHS=true,logicalIRS=true,logicalIMS=true,
ghostType='gray',
block=true,ghost=.3,center=1,
@@ -40,7 +41,7 @@ return {
RS='TRS',
sequence='bag',
seqData={1,2,3,4,5,6,7},
- skinSet='crystal_scf',
+ skinSet='Crystal (Scf)',
face=false,skin=false,
mission=false,
@@ -62,10 +63,16 @@ return {
mindas=0,minarr=0,minsdarr=0,
noInitSZO=false,
- mesDisp={},
- hook_drop={},
- hook_die={},
- task={},
+ -- Some Events are registered in player/init.lua, see "tableNeedMerge"
+ extraEvent={
+ {'attack',4},
+ },
+ extraEventHandler={
+ attack=function(P,P2,...)
+ P:beAttacked(P2,...)
+ end,
+ },
+
eventSet="X",
bg='none',bgm='race',
diff --git a/parts/player/init.lua b/parts/player/init.lua
index 4f3d2082..55c58313 100644
--- a/parts/player/init.lua
+++ b/parts/player/init.lua
@@ -273,17 +273,8 @@ local function _loadRemoteEnv(P,confStr)-- Load gameEnv
end
end
end
-local function _mergeFuncTable(f,L)
- if type(f)=='function' then
- ins(L,f)
- elseif type(f)=='table' then
- for i=1,#f do
- ins(L,f[i])
- end
- end
- return L
-end
-local hooks = {
+local tableNeedMerge={
+ 'task',
'mesDisp',
'hook_left',
'hook_left_manual',
@@ -296,36 +287,63 @@ local hooks = {
'hook_spawn',
'hook_hold',
'hook_die',
- 'task'
+ 'extraEvent',
}
+for _,k in next,tableNeedMerge do gameEnv0[k]={} end
+local function _mergeFuncTable(f,L)
+ if type(f)=='function' then
+ ins(L,f)
+ elseif type(f)=='table' then
+ for i=1,#f do
+ ins(L,f[i])
+ end
+ end
+ return L
+end
local function _applyGameEnv(P)-- Finish gameEnv processing
local ENV=P.gameEnv
- -- Apply events
- for i=1,#hooks do
- ENV[hooks[i]]=_mergeFuncTable(ENV[hooks[i]],{})
+ -- Create event tables
+ for i=1,#tableNeedMerge do
+ ENV[tableNeedMerge[i]]=_mergeFuncTable(ENV[tableNeedMerge[i]],{})
end
-- Apply eventSet
- if ENV.eventSet and ENV.eventSet~="X" then
- if type(ENV.eventSet)=='string' then
- local eventSet=require('parts.eventsets.'..ENV.eventSet)
- if eventSet then
- for k,v in next,eventSet do
- if TABLE.find(hooks,k) then
- _mergeFuncTable(v,ENV[k])
- elseif type(v)=='table' then
- ENV[k]=TABLE.copy(v)
+ while true do
+ if not (ENV.eventSet and ENV.eventSet~="X") then
+ break
+ end
+ if type(ENV.eventSet)~='string' then
+ MES.new('warn',"Wrong event set type: "..type(ENV.eventSet))
+ break
+ end
+ local eventSet=require('parts.eventsets.'..ENV.eventSet)
+ if not eventSet then
+ MES.new('warn',"No event set called: "..ENV.eventSet)
+ break
+ end
+ for k,v in next,eventSet do
+ if k=='extraEventHandler' then
+ for ev,handler in next,v do
+ if ENV.extraEventHandler[ev] then
+ local prevHandler=ENV.extraEventHandler[ev]
+ ENV.extraEventHandler[ev]=function(...)
+ prevHandler(...)
+ handler(...)
+ end
else
- ENV[k]=v
+ ENV.extraEventHandler[ev]=handler
end
end
+ elseif TABLE.find(tableNeedMerge,k) then
+ _mergeFuncTable(v,ENV[k])
+ elseif type(v)=='table' then
+ ENV[k]=TABLE.copy(v)
else
- MES.new('warn',"No event set called: "..ENV.eventSet)
+ ENV[k]=v
end
- else
- MES.new('warn',"Wrong event set type: "..type(ENV.eventSet))
end
+ break
end
if ENV.allowMod and GAME.modApplyAt~='preInit' then
diff --git a/parts/player/player.lua b/parts/player/player.lua
index b4e6099c..f3dc4340 100644
--- a/parts/player/player.lua
+++ b/parts/player/player.lua
@@ -270,27 +270,61 @@ function Player:act_rotRight()
if not self.control then return end
if self.cur then
self.ctrlCount=self.ctrlCount+1
+ if self.bufferedIRS then
+ -- Ensure IRS is spent before the rotation is processed so it doesn't throw things off.
+ -- This is so that if you for instance, are holding left IRS and then rotate right, it doesn't process
+ -- the left and right rotates in the reverse order.
+ self.keyPressing[3]=false
+ self:resolveIRS()
+ self.keyPressing[3]=true
+ end
self:spin(1)
self:_triggerEvent('hook_rotate',1)
- self.keyPressing[3]=false
+
+ -- Disable held inputs if IRS is off
+ if not self.gameEnv.irs then
+ self.keyPressing[3]=false
+ end
end
end
function Player:act_rotLeft()
if not self.control then return end
if self.cur then
self.ctrlCount=self.ctrlCount+1
+ if self.bufferedIRS then
+ -- Ensure IRS is spent before the rotation is processed so it doesn't throw things off.
+ -- This is so that if you for instance, are holding left IRS and then rotate right, it doesn't process
+ -- the left and right rotates in the reverse order.
+ self.keyPressing[4]=false
+ self:resolveIRS()
+ self.keyPressing[4]=true
+ end
self:spin(3)
self:_triggerEvent('hook_rotate',3)
- self.keyPressing[4]=false
+ -- Disable held inputs if IRS is off
+ if not self.gameEnv.irs then
+ self.keyPressing[4]=false
+ end
end
end
function Player:act_rot180()
if not self.control then return end
if self.cur then
self.ctrlCount=self.ctrlCount+2
+ if self.bufferedIRS then
+ -- Ensure IRS is spent before the rotation is processed so it doesn't throw things off.
+ -- This is so that if you for instance, are holding left IRS and then rotate right, it doesn't process
+ -- the left and right rotates in the reverse order.
+ self.keyPressing[5]=false
+ self:resolveIRS()
+ self.keyPressing[5]=true
+ end
self:spin(2)
self:_triggerEvent('hook_rotate',2)
- self.keyPressing[5]=false
+ -- Disable held inputs if IRS is off
+ if not self.gameEnv.irs then
+ self.keyPressing[5]=false
+ end
end
end
function Player:act_hardDrop()
@@ -300,6 +334,10 @@ function Player:act_hardDrop()
if self.lastPiece.autoLock and self.frameRun-self.lastPiece.frameself.ghoY then
self:createDropFX()
self.curY=self.ghoY
@@ -344,7 +382,10 @@ function Player:act_hold()
if not self.control then return end
if self.cur then
if self:hold() then
- self.keyPressing[8]=false
+ -- Disable held inputs if IHS is off
+ if not self.gameEnv.ihs then
+ self.keyPressing[8]=false
+ end
self:_triggerEvent('hook_hold')
end
end
@@ -701,6 +742,40 @@ function Player:_triggerEvent(eventName)
return true
end
end
+function Player:extraEvent(eventName,...)
+ if not (self.gameEnv.extraEvent and self.gameEnv.extraEventHandler) then return end
+ local list=self.gameEnv.extraEvent
+ local eventID
+ for i=1,#list do
+ if list[i][1]==eventName then
+ eventID=i
+ break
+ end
+ end
+ if not eventID then
+ MES.new('warn',"Extra event '"..eventName.."' doesn't exist in this mode")
+ return
+ end
+
+ local SELF
+ -- Trigger for all non-remote players
+ for _,p in next,PLAYERS do
+ if p.type~='remote' then
+ if p.type=='human' then
+ SELF=p
+ end
+ self.gameEnv.extraEventHandler[eventName](p,self,...)
+ end
+ end
+
+ ins(GAME.rep,SELF.frameRun)
+ ins(GAME.rep,64+eventID)
+ ins(GAME.rep,self.sid)
+ local data={...}
+ for i=1,#data do
+ ins(GAME.rep,data[i])
+ end
+end
function Player:getHolePos()-- Get a good garbage-line hole position
if self.garbageBeneath==0 then
@@ -833,34 +908,13 @@ function Player:ifoverlap(bk,x,y)
end
end
end
-function Player:attack(R,send,time,line,fromStream)
- if GAME.net then
- if self.type=='human' then-- Local player attack others
- ins(GAME.rep,self.frameRun)
- ins(GAME.rep,
- R.sid+
- send*0x100+
- time*0x10000+
- line*0x100000000+
- 0x2000000000000
- )
- self:createBeam(R,send)
- end
- if fromStream and R.type=='human' then-- Local player receiving lines
- ins(GAME.rep,R.frameRun)
- ins(GAME.rep,
- self.sid+
- send*0x100+
- time*0x10000+
- line*0x100000000+
- 0x1000000000000
- )
- R:receive(self,send,time,line)
- end
- else
- R:receive(self,send,time,line)
- self:createBeam(R,send)
- end
+function Player:attack(R,send,time,line)
+ self:extraEvent('attack',R.sid,send,time,line)
+end
+function Player:beAttacked(P2,sid,send,time,line)
+ if self==P2 or self.sid~=sid then return end
+ self:receive(P2,send,time,line)
+ P2:createBeam(self,send)
end
function Player:receive(A,send,time,line)
self.lastRecv=A
@@ -969,7 +1023,7 @@ function Player:freshBlockGhost()
if self.curY>self.ghoY then
self:createDropFX()
if ENV.shakeFX then
- self.swingOffset.vy=.5
+ self.swingOffset.vy=MATH.clamp((self.curY-self.ghoY-2.6)/10,0,0.626)
end
self.curY=self.ghoY
end
@@ -1151,34 +1205,67 @@ function Player:resetBlock()-- Reset Block's position and execute I*S
self.curY=y
self.minY=y+sc[1]
+ local ENV=self.gameEnv
+
+ -- In the game settings, there are user-set control flags for irs,irs,ims
+ -- These control in what way the user can buffer their rotate/hold/move inputs.
+ -- (If enabled, they may hold these inputs from the previous piece instead of just Entry Delay)
+
+ -- And mode-set flags for logicalIRS,logicalIHS,logicalIMS
+ -- These control whether IRS/IHS/IMS are effective in modifying what you can do.
+ -- (For instance, changing your piece's spawn position in 20g, or saving you from a death).
+ -- If logical IRS is disabled, the player may still IRS, but it will just buffer their input,
+ -- not actually allowing them to survive in a way they could not without.
+
local pressing=self.keyPressing
- -- IMS
- if self.gameEnv.ims and (pressing[1] and self.movDir==-1 or pressing[2] and self.movDir==1) and self.moving>=self.gameEnv.das then
- local x=self.curX+self.movDir
- if not self:ifoverlap(C.bk,x,y) then
- self.curX=x
+ -- IMS is enabled only when logicalIMS is enabled, because otherwise, it's just faster DAS.
+ if ENV.logicalIMS and (pressing[1] and self.movDir==-1 or pressing[2] and self.movDir==1) and self.moving>=self.gameEnv.das then
+ -- To avoid a top-out
+ if self:ifoverlap(C.bk,self.curX,self.curY) then
+ -- Always perform the shift, since you're topped out anyway
+ self.curX=self.curX+self.movDir
+ elseif ENV.wait>0 and ENV.ims then
+ -- Otherwise, only check IMS if it's enabled and you're in a mode with entry delay (20g)
+ local x=self.curX+self.movDir
+ if not self:ifoverlap(C.bk,x,y) then
+ self.curX=x
+ end
end
end
- -- IRS
- if self.gameEnv.irs then
+ if not ENV.logicalIRS then
+ -- If logical IRS is disabled, all IRS inputs will be buffered to prevent survival.
+ self.bufferedIRS=true
+ self.bufferedDelay=0
+ if ENV.wait==0 then
+ self.bufferedDelay=ENV.irscut
+ end
+ elseif ENV.wait==0 and ENV.irscut>0 and not self:ifoverlap(C.bk,self.curX,self.curY) then
+ -- If IRS cut delay is enabled and we aren't currently dying, buffer the input instead.
+ self.bufferedIRS=true
+ self.bufferedDelay=ENV.irscut
+ else
+ -- If we're currently dying or in an entry-delay mode (20g), perform the rotation right away.
if pressing[5] then
- self:spin(2,true)
+ self:act_rot180()
elseif pressing[3] then
if pressing[4] then
- self:spin(2,true)
+ self:act_rot180()
else
- self:spin(1,true)
+ self:act_rotRight()
end
elseif pressing[4] then
- self:spin(3,true)
+ self:act_rotLeft()
end
+ end
+ -- Disable held inputs if IRS is off
+ if not ENV.irs then
pressing[3],pressing[4],pressing[5]=false,false,false
end
-- DAS cut
- if self.gameEnv.dascut>0 then
- self.moving=self.moving-(self.moving>0 and 1 or -1)*self.gameEnv.dascut
+ if ENV.dascut>0 then
+ self.moving=self.moving-(self.moving>0 and 1 or -1)*ENV.dascut
end
-- Spawn SFX
@@ -1498,9 +1585,29 @@ function Player:_popNext(ifhold)-- Pop nextQueue to hand
local pressing=self.keyPressing
-- IHS
- if not ifhold and pressing[8] and ENV.ihs and self.holdTime>0 then
- self:hold(true)
- pressing[8]=false
+ if not ifhold and pressing[8] and self.holdTime>0 then
+ if not ENV.logicalIHS then
+ -- If logical IHS is disabled, all IHS inputs will be buffered to prevent survival.
+ self.bufferedIRS=true
+ self.bufferedIHS=true
+ self.bufferedDelay=0
+ if ENV.wait==0 then
+ self.bufferedDelay=ENV.irscut
+ end
+ elseif ENV.wait==0 and ENV.irscut>0 and not self:willDieWith(self.cur) then
+ -- If IRS cut delay is enabled and we're not currently dying, buffer the input instead.
+ self.bufferedIRS=true
+ self.bufferedIHS=true
+ self.bufferedDelay=ENV.irscut
+ self:resetBlock()
+ else
+ -- If we're currently dying or in an entry-delay mode (20g), perform the hold immediately.
+ self:hold(true)
+ end
+ -- Disable held inputs if IHS is off
+ if not ENV.ihs then
+ pressing[8]=false
+ end
else
self:resetBlock()
end
@@ -1814,7 +1921,7 @@ do
end
end
- local yomi = ""
+ local yomi=''
piece.spin,piece.mini=dospin,false
piece.pc,piece.hpc=false,false
@@ -1825,7 +1932,7 @@ do
cscore=(spinSCR[C.name] or spinSCR[8])[cc]
if self.b2b>800 then
self:showText(text.b3b..text.block[C.name]..text.spin..text.clear[cc],0,-30,35,'stretch')
- yomi = yomi..text.b3b..text.block[C.name]..text.spin..text.clear[cc]
+ yomi=yomi..text.b3b..text.block[C.name]..text.spin..text.clear[cc]
atk=b2bATK[cc]+cc*.5
exblock=exblock+1
cscore=cscore*2
@@ -1835,7 +1942,7 @@ do
end
elseif self.b2b>=50 then
self:showText(text.b2b..text.block[C.name]..text.spin..text.clear[cc],0,-30,35,'spin')
- yomi = yomi..text.b2b..text.block[C.name]..text.spin..text.clear[cc]
+ yomi=yomi..text.b2b..text.block[C.name]..text.spin..text.clear[cc]
atk=b2bATK[cc]
cscore=cscore*1.2
Stat.b2b=Stat.b2b+1
@@ -1844,13 +1951,13 @@ do
end
else
self:showText(text.block[C.name]..text.spin..text.clear[cc],0,-30,45,'spin')
- yomi = yomi..text.block[C.name]..text.spin..text.clear[cc]
+ yomi=yomi..text.block[C.name]..text.spin..text.clear[cc]
atk=2*cc
end
sendTime=20+atk*20
if mini then
self:showText(text.mini,0,-80,35,'appear')
- yomi = text.mini..' '..yomi
+ yomi=text.mini..' '..yomi
atk=atk*.25
sendTime=sendTime+60
cscore=cscore*.5
@@ -1871,7 +1978,7 @@ do
cscore=clearSCR[cc]
if self.b2b>800 then
self:showText(text.b3b..text.clear[cc],0,-30,50,'fly')
- yomi = text.b3b..text.clear[cc]..yomi
+ yomi=text.b3b..text.clear[cc]..yomi
atk=4*cc-10
sendTime=100
exblock=exblock+1
@@ -1882,7 +1989,7 @@ do
end
elseif self.b2b>=50 then
self:showText(text.b2b..text.clear[cc],0,-30,50,'drive')
- yomi = text.b2b..text.clear[cc]..yomi
+ yomi=text.b2b..text.clear[cc]..yomi
sendTime=80
atk=3*cc-7
cscore=cscore*1.3
@@ -1892,7 +1999,7 @@ do
end
else
self:showText(text.clear[cc],0,-30,70,'stretch')
- yomi = text.clear[cc]..yomi
+ yomi=text.clear[cc]..yomi
sendTime=60
atk=2*cc-4
end
@@ -1900,7 +2007,7 @@ do
piece.special=true
else
self:showText(text.clear[cc],0,-30,35,'appear',(8-cc)*.3)
- yomi = text.clear[cc]..yomi
+ yomi=text.clear[cc]..yomi
atk=cc-.5
sendTime=20+floor(atk*20)
cscore=cscore+clearSCR[cc]
@@ -1919,7 +2026,7 @@ do
atk=atk+1
end
self:showText(text.cmb[min(cmb,21)],0,25,15+min(cmb,15)*5,cmb<10 and 'appear' or 'flicker')
- yomi = yomi..' '..text.cmb[min(cmb,21)]
+ yomi=yomi..' '..text.cmb[min(cmb,21)]
cscore=cscore+min(50*cmb,500)*(2*cc-1)
end
@@ -2447,6 +2554,28 @@ local function _updateFX(P,dt)
end
end
end
+
+function Player:resolveIRS()
+ if self.bufferedIHS then
+ self:hold(true)
+ self.bufferedIHS=false
+ end
+
+ self.bufferedIRS=false
+ local pressing=self.keyPressing
+ if pressing[5] then
+ self:act_rot180()
+ elseif pressing[3] then
+ if pressing[4] then
+ self:act_rot180()
+ else
+ self:act_rotRight()
+ end
+ elseif pressing[4] then
+ self:act_rotLeft()
+ end
+end
+
local function update_alive(P,dt)
local ENV=P.gameEnv
@@ -2505,6 +2634,18 @@ local function update_alive(P,dt)
end
end
+ -- Buffer IRS after IRS cut delay has elapsed.
+ -- The purpose of this is to allow the player to release their rotate key during the IRS cut delay,
+ -- which will allow them to avoid accidentally using IRS.
+ if P.bufferedDelay then
+ P.bufferedDelay=P.bufferedDelay-1
+ if P.bufferedDelay<=0 then
+ if P.bufferedIRS then
+ P:resolveIRS()
+ end
+ end
+ end
+
-- Moving pressed
if P.movDir~=0 then
local das,arr=ENV.das,ENV.arr
@@ -2701,44 +2842,32 @@ local function update_alive(P,dt)
end
local function update_streaming(P)
local eventTime=P.stream[P.streamProgress]
- while eventTime and P.frameRun==eventTime do
+ while eventTime and P.frameRun==eventTime or eventTime==0 do
local event=P.stream[P.streamProgress+1]
if event==0 then-- Just wait
elseif event<=32 then-- Press key
P:pressKey(event)
elseif event<=64 then-- Release key
P:releaseKey(event-32)
- elseif event>0x2000000000000 then-- Sending lines
- local sid=event%0x100
- local amount=floor(event/0x100)%0x100
- local time=floor(event/0x10000)%0x10000
- local line=floor(event/0x100000000)%0x10000
- for _,p in next,PLY_ALIVE do
- if p.sid==sid then
- P.netAtk=P.netAtk+amount
- if P.netAtk~=P.stat.send then-- He cheated or just desynchronized to death
- MES.new('warn',"#"..P.uid.." desynchronized")
- NET.player_finish({reason='desync'})
- P:lose(true)
- return
- end
- P:attack(p,amount,time,line,true)
- P:createBeam(p,amount)
+ elseif event<=128 then-- Extra Event
+ local eventName=P.gameEnv.extraEvent[event-64][1]
+ local eventParamCount=P.gameEnv.extraEvent[event-64][2]
+ local sourceSid=P.stream[P.streamProgress+2]
+ local paramList={}
+ for i=1,eventParamCount do
+ ins(paramList,P.stream[P.streamProgress+2+i])
+ end
+ P.streamProgress=P.streamProgress+eventParamCount+1
+
+ local SRC
+ for _,p in next,PLAYERS do
+ if p.sid==sourceSid then
+ SRC=p
break
end
end
- elseif event>0x1000000000000 then-- Receiving lines
- local sid=event%0x100
- for _,p in next,PLY_ALIVE do
- if p.sid==sid then
- P:receive(
- p,
- floor(event/0x100)%0x100,-- amount
- floor(event/0x10000)%0x10000,-- time
- floor(event/0x100000000)%0x10000-- line
- )
- break
- end
+ if SRC then
+ P.gameEnv.extraEventHandler[eventName](P,SRC,unpack(paramList))
end
end
P.streamProgress=P.streamProgress+2
@@ -2804,7 +2933,7 @@ function Player:update(dt)
end
while self.trigFrame>=1 do
if self.streamProgress then
- local frameDelta-- Time between now and end of stream
+ local dataDelta -- How much data wating to be process
if self.type=='remote' then
if self.loseTimer then
self.loseTimer=self.loseTimer-1
@@ -2813,25 +2942,26 @@ function Player:update(dt)
self:lose(true)
end
end
- frameDelta=(self.stream[#self.stream-1] or 0)-self.frameRun
- if frameDelta==0 then frameDelta=nil end
+ dataDelta=#self.stream-self.streamProgress
else
- frameDelta=0
+ dataDelta=1
end
- if frameDelta then
+ if dataDelta>0 then
for _=1,
- self.loseTimer and min(frameDelta,
+ -- Speed up to finish
+ self.loseTimer and min(dataDelta,
self.loseTimer>16 and 2 or
self.loseTimer>6.2 and 12 or
self.loseTimer>2.6 and 260 or
2600
) or
- frameDelta<26 and 1 or
- frameDelta<50 and 2 or
- frameDelta<80 and 3 or
- frameDelta<120 and 5 or
- frameDelta<160 and 7 or
- frameDelta<200 and 10 or
+ -- Chasing faster when slower
+ dataDelta<26 and 1 or
+ dataDelta<42 and 2 or
+ dataDelta<62 and 3 or
+ dataDelta<70.23 and 5 or
+ dataDelta<94.2 and 7 or
+ dataDelta<126 and 10 or
20
do
update_streaming(self)
@@ -2880,7 +3010,7 @@ function Player:revive()
SFX.play('emit')
end
function Player:torikanEnd(requiredTime)
- if self.stat.time < requiredTime then
+ if self.stat.timehisLen
-- Give mino to player & update history
if history[1]~=0 then
diff --git a/parts/scenes/about.lua b/parts/scenes/about.lua
index 37e35ef9..d29add5f 100644
--- a/parts/scenes/about.lua
+++ b/parts/scenes/about.lua
@@ -6,6 +6,9 @@ local scene={}
function scene.enter()
BG.set()
+ for i=1,#text.aboutTexts do
+ text.aboutTexts[i]=text.aboutTexts[i]:gsub("LÖVE%(?.*%)?",STRING.repD("LÖVE($1.$2)",love.getVersion()))
+ end
end
function scene.mouseDown(x,y)
diff --git a/parts/scenes/app_15p.lua b/parts/scenes/app_15p.lua
index 2152211d..fc43c24c 100644
--- a/parts/scenes/app_15p.lua
+++ b/parts/scenes/app_15p.lua
@@ -29,6 +29,7 @@ function scene.enter()
slide=true
pathVis=true
revKB=false
+ DiscordRPC.update("Playing 15-Puzzle")
end
local function moveU(x,y)
diff --git a/parts/scenes/app_2048.lua b/parts/scenes/app_2048.lua
index c610e7b1..b097cb9f 100644
--- a/parts/scenes/app_2048.lua
+++ b/parts/scenes/app_2048.lua
@@ -234,6 +234,7 @@ function scene.enter()
tapControl=false
startTime=0
reset()
+ DiscordRPC.update("Playing 2048")
end
function scene.mouseDown(x,y,k)
diff --git a/parts/scenes/app_AtoZ.lua b/parts/scenes/app_AtoZ.lua
index bc6274fe..7e493269 100644
--- a/parts/scenes/app_AtoZ.lua
+++ b/parts/scenes/app_AtoZ.lua
@@ -40,6 +40,7 @@ function scene.enter()
startTime=0
time=0
state=0
+ DiscordRPC.update("Spamming keyboard")
end
function scene.keyDown(key,isRep)
diff --git a/parts/scenes/app_UTTT.lua b/parts/scenes/app_UTTT.lua
index 8c18067a..493dfc1b 100644
--- a/parts/scenes/app_UTTT.lua
+++ b/parts/scenes/app_UTTT.lua
@@ -100,6 +100,7 @@ function scene.enter()
restart()
BGM.play('truth')
BG.set('rainbow')
+ DiscordRPC.update("Playing Ultimate Tic-Tac-Toe")
end
function scene.mouseMove(x,y)
diff --git a/parts/scenes/app_arithmetic.lua b/parts/scenes/app_arithmetic.lua
index e6677ac0..93a5b6f6 100644
--- a/parts/scenes/app_arithmetic.lua
+++ b/parts/scenes/app_arithmetic.lua
@@ -360,6 +360,7 @@ function scene.enter()
drawing=false
numScale=1
BGM.play('truth')
+ DiscordRPC.update("Playing Arithmetic")
end
function scene.keyDown(key,isRep)
diff --git a/parts/scenes/app_calc.lua b/parts/scenes/app_calc.lua
index 1c62b271..eecb76c6 100644
--- a/parts/scenes/app_calc.lua
+++ b/parts/scenes/app_calc.lua
@@ -28,6 +28,7 @@ function scene.enter()
BG.set('none')
BGM.stop()
reg,val,sym=false,"0",false
+ DiscordRPC.update("Calculating something")
end
function scene.leave()
BGM.play()
@@ -85,13 +86,13 @@ function scene.keyDown(key)
sym="+"
elseif key=='*' then
_autoReturn()
- sym="*"
+ sym="×"
elseif key=='-' then
_autoReturn()
- sym="-"
+ sym="−"
elseif key=='/' then
_autoReturn()
- sym="/"
+ sym="÷"
elseif key:byte()>=48 and key:byte()<=57 then
if sym=="=" then
val=key
@@ -115,9 +116,9 @@ function scene.keyDown(key)
reg=reg:gsub("e$","")
val=
sym=="+" and tostring((tonumber(reg) or 0)+tonumber(val)) or
- sym=="-" and tostring((tonumber(reg) or 0)-tonumber(val)) or
- sym=="*" and tostring((tonumber(reg) or 0)*tonumber(val)) or
- sym=="/" and tostring((tonumber(reg) or 0)/tonumber(val)) or
+ sym=="−" and tostring((tonumber(reg) or 0)-tonumber(val)) or
+ sym=="×" and tostring((tonumber(reg) or 0)*tonumber(val)) or
+ sym=="÷" and tostring((tonumber(reg) or 0)/tonumber(val)) or
"-1"
end
sym="="
@@ -158,11 +159,11 @@ scene.widgetList={
WIDGET.newKey{name='_9',x=345,y=500,w=90,sound=false,fText="9",font=50,code=pressKey'9'},
WIDGET.newKey{name='_0',x=145,y=600,w=90,sound=false,fText="0",font=50,code=pressKey'0'},
WIDGET.newKey{name='.',x=245,y=600,w=90,sound=false,fText=".",color='lM',font=50,code=pressKey'.'},
- WIDGET.newKey{name='e',x=345,y=600,w=90,sound=false,fText="e",color='lM',font=50,code=pressKey'e'},
+ WIDGET.newKey{name='e',x=345,y=600,w=90,sound=false,fText="EE",color='lM',font=50,code=pressKey'e'},
WIDGET.newKey{name='+',x=445,y=300,w=90,sound=false,fText="+",color='lB',font=50,code=pressKey'+'},
- WIDGET.newKey{name='-',x=445,y=400,w=90,sound=false,fText="-",color='lB',font=50,code=pressKey'-'},
- WIDGET.newKey{name='*',x=445,y=500,w=90,sound=false,fText="*",color='lB',font=50,code=pressKey'*'},
- WIDGET.newKey{name='/',x=445,y=600,w=90,sound=false,fText="/",color='lB',font=50,code=pressKey'/'},
+ WIDGET.newKey{name='-',x=445,y=400,w=90,sound=false,fText="−",color='lB',font=50,code=pressKey'-'},
+ WIDGET.newKey{name='*',x=445,y=500,w=90,sound=false,fText="×",color='lB',font=50,code=pressKey'*'},
+ WIDGET.newKey{name='/',x=445,y=600,w=90,sound=false,fText="÷",color='lB',font=50,code=pressKey'/'},
WIDGET.newKey{name='<',x=545,y=300,w=90,sound=false,fText=CHAR.key.backspace,color='lR',font=50,code=pressKey'backspace'},
WIDGET.newKey{name='=',x=545,y=400,w=90,sound=false,fText="=",color='lY',font=50,code=pressKey'return'},
WIDGET.newKey{name='back',x=1135,y=640,w=170,h=80,sound='back',font=60,fText=CHAR.icon.back,code=backScene},
diff --git a/parts/scenes/app_cannon.lua b/parts/scenes/app_cannon.lua
index 3f3cd9e0..33eed85d 100644
--- a/parts/scenes/app_cannon.lua
+++ b/parts/scenes/app_cannon.lua
@@ -15,6 +15,7 @@ function scene.enter()
ex,ey=626,260
BG.set('matrix')
BGM.play('hang out')
+ DiscordRPC.update("Shooting cannon balls")
end
function scene.keyDown(key,isRep)
diff --git a/parts/scenes/app_console.lua b/parts/scenes/app_console.lua
index 50baed41..dd9b24bd 100644
--- a/parts/scenes/app_console.lua
+++ b/parts/scenes/app_console.lua
@@ -949,16 +949,16 @@ end
local combKey={
x=function()
- love.system.setClipboardText(inputBox:getText())
+ CLIPBOARD.set(inputBox:getText())
inputBox:clear()
SFX.play('reach')
end,
c=function()
- love.system.setClipboardText(inputBox:getText())
+ CLIPBOARD.set(inputBox:getText())
SFX.play('reach')
end,
v=function()
- inputBox:addText(love.system.getClipboardText())
+ inputBox:addText(CLIPBOARD.get())
SFX.play('reach')
end,
}
@@ -1034,6 +1034,7 @@ userG.the_key=first_key
function scene.enter()
WIDGET.focus(inputBox)
BG.set('none')
+ DiscordRPC.update("Hacking the system")
end
function scene.wheelMoved(_,y)
diff --git a/parts/scenes/app_cubefield.lua b/parts/scenes/app_cubefield.lua
index a6a6a711..cd0f549d 100644
--- a/parts/scenes/app_cubefield.lua
+++ b/parts/scenes/app_cubefield.lua
@@ -59,6 +59,7 @@ function scene.enter()
gc.setLineJoin('bevel')
BGM.play('push')
BG.set('none')
+ DiscordRPC.update("Playing Cubefield")
end
function scene.touchDown(x)
@@ -203,7 +204,7 @@ function scene.update(dt)
end
ct=ct-1
if ct==0 then
- local t=love.system.getClipboardText()
+ local t=CLIPBOARD.get()
if type(t)=='string' then
t=t:lower():match("^s=(%d+)$")
t=t and tonumber(t) and tonumber(t)>0 and tonumber(t)<=8000 and floor(tonumber(t))
diff --git a/parts/scenes/app_dropper.lua b/parts/scenes/app_dropper.lua
index c7c1246a..aa27dd19 100644
--- a/parts/scenes/app_dropper.lua
+++ b/parts/scenes/app_dropper.lua
@@ -38,6 +38,7 @@ function scene.enter()
state='menu'
BGM.play('hang out')
BG.set('space')
+ DiscordRPC.update("Playing Dropper")
end
function scene.keyDown(key,isRep)
diff --git a/parts/scenes/app_dtw.lua b/parts/scenes/app_dtw.lua
index b4b64c60..d969188b 100644
--- a/parts/scenes/app_dtw.lua
+++ b/parts/scenes/app_dtw.lua
@@ -181,7 +181,7 @@ function reset()
time=0
score=0
- local t=love.system.getClipboardText()
+ local t=CLIPBOARD.get()
if type(t)=='string' then
t=t:lower():match("^s=(.+)")
t=t and tonumber(t) and tonumber(t)*2
@@ -201,6 +201,7 @@ function scene.enter()
reset()
BG.set('fixColor',.26,.26,.26)
BGM.play(bgm)
+ DiscordRPC.update("Avoiding touching white tiles")
end
local function touch(n)
diff --git a/parts/scenes/app_link.lua b/parts/scenes/app_link.lua
index 3615daec..c3dab386 100644
--- a/parts/scenes/app_link.lua
+++ b/parts/scenes/app_link.lua
@@ -249,6 +249,7 @@ function scene.enter()
invis=false
newGame()
BGM.play('truth')
+ DiscordRPC.update("Playing Link")
end
function scene.keyDown(key,isRep)
diff --git a/parts/scenes/app_mahjong.lua b/parts/scenes/app_mahjong.lua
index 8d55b468..d064e829 100644
--- a/parts/scenes/app_mahjong.lua
+++ b/parts/scenes/app_mahjong.lua
@@ -109,6 +109,7 @@ function scene.enter()
BG.set('fixColor',.26,.62,.26)
_newGame()
selected=false
+ DiscordRPC.update("Playing Mahjong")
end
function scene.mouseMove(x,y)
diff --git a/parts/scenes/app_memorize.lua b/parts/scenes/app_memorize.lua
index e1844c81..9af7128d 100644
--- a/parts/scenes/app_memorize.lua
+++ b/parts/scenes/app_memorize.lua
@@ -36,6 +36,7 @@ function scene.enter()
input=''
showNum='memoriZe'
BGM.play('reason')
+ DiscordRPC.update("Playing memoriZe")
end
function scene.keyDown(key,isRep)
diff --git a/parts/scenes/app_piano.lua b/parts/scenes/app_piano.lua
index 1c78662e..4942e8a4 100644
--- a/parts/scenes/app_piano.lua
+++ b/parts/scenes/app_piano.lua
@@ -95,6 +95,7 @@ function scene.enter()
generateVKey()
_notHoldCS()
_showVirtualKey(MOBILE)
+ DiscordRPC.update("Playing music")
end
function scene.leave()
diff --git a/parts/scenes/app_polyforge.lua b/parts/scenes/app_polyforge.lua
index 29e4baf6..86f4d7dd 100644
--- a/parts/scenes/app_polyforge.lua
+++ b/parts/scenes/app_polyforge.lua
@@ -40,6 +40,7 @@ function scene.enter()
end
BG.set('none')
BGM.play('dream')
+ DiscordRPC.update("Playing polyforge")
end
function scene.keyDown(key,isRep)
diff --git a/parts/scenes/app_pong.lua b/parts/scenes/app_pong.lua
index 2ee64746..06c05257 100644
--- a/parts/scenes/app_pong.lua
+++ b/parts/scenes/app_pong.lua
@@ -35,6 +35,7 @@ function scene.enter()
vy=0,
y0=false,
}
+ DiscordRPC.update("Playing Pong")
end
local function start()
diff --git a/parts/scenes/app_reflect.lua b/parts/scenes/app_reflect.lua
index 4ed1ad74..34a814c9 100644
--- a/parts/scenes/app_reflect.lua
+++ b/parts/scenes/app_reflect.lua
@@ -18,6 +18,7 @@ end
function scene.enter()
reset()
BG.set('none')
+ DiscordRPC.update("Playing Reflect")
end
function scene.keyDown(key,isRep)
diff --git a/parts/scenes/app_schulteG.lua b/parts/scenes/app_schulteG.lua
index 7b673503..a20b3c5d 100644
--- a/parts/scenes/app_schulteG.lua
+++ b/parts/scenes/app_schulteG.lua
@@ -25,6 +25,7 @@ function scene.enter()
mistake=0
state=0
progress=0
+ DiscordRPC.update("Playing Schulte Grid")
end
local function newBoard()
diff --git a/parts/scenes/app_spin.lua b/parts/scenes/app_spin.lua
index a0a90fb8..d2937e4b 100644
--- a/parts/scenes/app_spin.lua
+++ b/parts/scenes/app_spin.lua
@@ -15,6 +15,10 @@ end)
local scene={}
+function scene.enter()
+ DiscordRPC.update("Playing a non-sense thing")
+end
+
function scene.keyDown(key,isRep)
if isRep then return end
if key=='space' or key=='return' then
diff --git a/parts/scenes/app_stopwatch.lua b/parts/scenes/app_stopwatch.lua
index 54611a93..e3e67bcb 100644
--- a/parts/scenes/app_stopwatch.lua
+++ b/parts/scenes/app_stopwatch.lua
@@ -27,6 +27,7 @@ function scene.enter()
state=0
time1=STRING.time(0)
time2=STRING.time(0)
+ DiscordRPC.update("Timing something")
end
function scene.mouseDown()
diff --git a/parts/scenes/app_tap.lua b/parts/scenes/app_tap.lua
index 7e5ec26a..5de5badf 100644
--- a/parts/scenes/app_tap.lua
+++ b/parts/scenes/app_tap.lua
@@ -14,6 +14,7 @@ function scene.enter()
keyTime={} for i=1,40 do keyTime[i]=-1e99 end
BG.set('fixColor',.26,.26,.26)
BGM.play('push')
+ DiscordRPC.update("Spamming keyboard")
end
function scene.keyDown(key,isRep)
diff --git a/parts/scenes/app_ten.lua b/parts/scenes/app_ten.lua
index 7388d671..ed20e954 100644
--- a/parts/scenes/app_ten.lua
+++ b/parts/scenes/app_ten.lua
@@ -64,6 +64,7 @@ function scene.enter()
invis=false
nexts=true
reset()
+ DiscordRPC.update("Playing Get the Ten")
end
local function merge()
diff --git a/parts/scenes/app_triple.lua b/parts/scenes/app_triple.lua
index 0dc7a977..b1888d4c 100644
--- a/parts/scenes/app_triple.lua
+++ b/parts/scenes/app_triple.lua
@@ -267,6 +267,7 @@ local scene={}
function scene.enter()
player:reset()
BGM.play('truth')
+ DiscordRPC.update("Playing Triple Town")
end
function scene.mouseClick(x,y)
diff --git a/parts/scenes/customGame.lua b/parts/scenes/customGame.lua
index 4d6826a7..c2d000c4 100644
--- a/parts/scenes/customGame.lua
+++ b/parts/scenes/customGame.lua
@@ -23,7 +23,10 @@ local function apply_locals()
TABLE.clear(CUSTOMENV)
TABLE.cover(CUSTOMGAME_LOCAL.customenv,CUSTOMENV)
end
-do -- Initialize fields, sequence, missions, gameEnv for cutsom game
+
+local scene={}
+
+function scene.initialize() -- Initialize fields, sequence, missions, gameEnv for cutsom game
local fieldData=loadFile('conf/customBoards','-string -canSkip')
local fieldReinit=false
if not fieldData then
@@ -64,6 +67,7 @@ do -- Initialize fields, sequence, missions, gameEnv for cutsom game
TABLE.complete(customData,CUSTOMGAME_LOCAL.customenv)
end
TABLE.complete(require"parts.customEnv0",CUSTOMGAME_LOCAL.customenv)
+ apply_locals()
end
local sList={
@@ -87,8 +91,6 @@ local sList={
}
local modUsed
-local scene={}
-
function scene.enter()
destroyPlayers()
BG.set(CUSTOMGAME_LOCAL.customenv.bg)
@@ -186,10 +188,10 @@ function scene.keyDown(key,isRep)
if #CUSTOMGAME_LOCAL.bag>0 then str=str..DATA.copySequence(CUSTOMGAME_LOCAL.bag) end
str=str.."!"
if #CUSTOMGAME_LOCAL.mission>0 then str=str..DATA.copyMission(CUSTOMGAME_LOCAL.mission) end
- sys.setClipboardText(str.."!"..DATA.copyBoards(CUSTOMGAME_LOCAL.field).."!")
+ CLIPBOARD.set(str.."!"..DATA.copyBoards(CUSTOMGAME_LOCAL.field).."!")
MES.new('check',text.exportSuccess)
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
- local str=sys.getClipboardText()
+ local str=CLIPBOARD.get()
local args=str:sub((str:find(":") or 0)+1):split("!")
local hasTooHighField=false
repeat
diff --git a/parts/scenes/custom_field.lua b/parts/scenes/custom_field.lua
index 76fc86e4..ab6851ce 100644
--- a/parts/scenes/custom_field.lua
+++ b/parts/scenes/custom_field.lua
@@ -226,10 +226,10 @@ function scene.keyDown(key)
SFX.play('clear_4',.8)
SFX.play('fall',.8)
elseif key=='c' and kb.isDown('lctrl','rctrl') or key=='cC' then
- sys.setClipboardText("Techmino Field:"..DATA.copyBoard(FIELD[page]))
+ CLIPBOARD.set("Techmino Field:"..DATA.copyBoard(FIELD[page]))
MES.new('check',text.exportSuccess)
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
- local str=sys.getClipboardText()
+ local str=CLIPBOARD.get()
local p=str:find(":")-- ptr*
if p then
if not str:sub(1,p-1):find("Field") then
diff --git a/parts/scenes/custom_mission.lua b/parts/scenes/custom_mission.lua
index f5e2dc84..e730a959 100644
--- a/parts/scenes/custom_mission.lua
+++ b/parts/scenes/custom_mission.lua
@@ -68,11 +68,11 @@ function scene.keyDown(key)
end
elseif key=='c' and kb.isDown('lctrl','rctrl') or key=='cC' then
if #MISSION>0 then
- sys.setClipboardText("Techmino Target:"..DATA.copyMission(MISSION))
+ CLIPBOARD.set("Techmino Target:"..DATA.copyMission(MISSION))
MES.new('check',text.exportSuccess)
end
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
- local str=sys.getClipboardText()
+ local str=CLIPBOARD.get()
local p=str:find(":")-- ptr*
if p then
if not str:sub(1,p-1):find("Target") then
diff --git a/parts/scenes/custom_sequence.lua b/parts/scenes/custom_sequence.lua
index 47a76381..787ade53 100644
--- a/parts/scenes/custom_sequence.lua
+++ b/parts/scenes/custom_sequence.lua
@@ -1,4 +1,3 @@
-local sys=love.system
local kb=love.keyboard
local sin=math.sin
@@ -76,11 +75,11 @@ function scene.keyDown(key)
scene.widgetList.sequence:scroll(kb.isDown('lshift','rshift') and -1 or 1)
elseif key=='c' and kb.isDown('lctrl','rctrl') or key=='cC' then
if #BAG>0 then
- sys.setClipboardText("Techmino SEQ:"..DATA.copySequence(BAG))
+ CLIPBOARD.set("Techmino SEQ:"..DATA.copySequence(BAG))
MES.new('check',text.exportSuccess)
end
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
- local str=sys.getClipboardText()
+ local str=CLIPBOARD.get()
local p=str:find(":")-- ptr*
if p then
if not str:sub(1,p-1):find("SEQ") then
diff --git a/parts/scenes/dict.lua b/parts/scenes/dict.lua
index 95fb0fa2..4d8ebabc 100644
--- a/parts/scenes/dict.lua
+++ b/parts/scenes/dict.lua
@@ -124,7 +124,7 @@ end
local function _copy()
local t=_getList()[listBox.selected]
t=t.title_Org..":\n"..t.content_Org..(t.url and "\n[ "..t.url.." ]\n" or "\n")..text.dictNote
- love.system.setClipboardText(t)
+ CLIPBOARD.set(t)
scene.widgetList.copy.hide=true
MES.new('info',text.copyDone)
end
@@ -163,6 +163,7 @@ function scene.enter()
if not MOBILE then WIDGET.focus(inputBox) end
BG.set('rainbow')
+ DiscordRPC.update("Learning Zictionary")
end
function scene.wheelMoved(_,y)
diff --git a/parts/scenes/error.lua b/parts/scenes/error.lua
index 47514ef9..63a5e9cd 100644
--- a/parts/scenes/error.lua
+++ b/parts/scenes/error.lua
@@ -13,6 +13,7 @@ function scene.enter()
if SETTING then
SFX.fplay('error',SETTING.voc*.8 or 0)
end
+ DiscordRPC.update("Struke by an error")
end
function scene.draw()
diff --git a/parts/scenes/game.lua b/parts/scenes/game.lua
index b8c31cdf..b601765b 100644
--- a/parts/scenes/game.lua
+++ b/parts/scenes/game.lua
@@ -222,6 +222,8 @@ function scene.enter()
_updateStepButton()
_updateRepButtons()
_updateMenuButtons()
+
+ DiscordRPC.update("Playing "..GAME.curMode.name)
end
scene.mouseDown=NULL
diff --git a/parts/scenes/lang.lua b/parts/scenes/lang.lua
index 287e0f26..9cf3509e 100644
--- a/parts/scenes/lang.lua
+++ b/parts/scenes/lang.lua
@@ -21,6 +21,9 @@ local curLang=1
local scene={}
+function scene.enter()
+ DiscordRPC.update("Setting language")
+end
function scene.leave()
saveSettings()
end
diff --git a/parts/scenes/launchpad.lua b/parts/scenes/launchpad.lua
index 195cc944..6aa9c15e 100644
--- a/parts/scenes/launchpad.lua
+++ b/parts/scenes/launchpad.lua
@@ -168,6 +168,10 @@ local function press(x,y)
end
end
+function scene.enter()
+ DiscordRPC.update("Playing Launchpad")
+end
+
function scene.touchDown(x,y)
x,y=floor((x-pad.x)/80),floor((y-pad.y)/80)
if x>=0 and x<=8 and y>=0 and y<=7 then
diff --git a/parts/scenes/load.lua b/parts/scenes/load.lua
index c82a67be..5bb9d895 100644
--- a/parts/scenes/load.lua
+++ b/parts/scenes/load.lua
@@ -193,6 +193,7 @@ function scene.enter()
maxProgress=10
t1,t2=0,0-- Timer
animeType={} for i=1,#SVG_TITLE_FILL do animeType[i]=math.random(#titleTransform) end-- Random animation type
+ NET.launchNotice()
end
function scene.leave()
SCN.go('quit','none')
diff --git a/parts/scenes/login.lua b/parts/scenes/login.lua
index d4f0b4e6..0a2b005f 100644
--- a/parts/scenes/login.lua
+++ b/parts/scenes/login.lua
@@ -14,7 +14,7 @@ local function _submit()
end
end
local function _paste()
- local t=love.system.getClipboardText()
+ local t=CLIPBOARD.get()
if t then
t=STRING.trim(t)
if #t==128 and t:match("[0-9A-Z]+") then
diff --git a/parts/scenes/main.lua b/parts/scenes/main.lua
index bec291ac..985ca38a 100644
--- a/parts/scenes/main.lua
+++ b/parts/scenes/main.lua
@@ -44,6 +44,8 @@ function scene.enter()
GAME.setting={}
PLY.newDemoPlayer(1)
PLAYERS[1]:setPosition(520,140,.8)
+
+ DiscordRPC.update("In Main Menu")
end
function scene.resize()
@@ -104,8 +106,7 @@ function scene.keyDown(key,isRep)
end
elseif key=='3' then
if _testButton(10) then
- MES.new('warn',text.notFinished)
- -- NET.getNotice()
+ NET.getNotice()
end
elseif key=='4' then
if _testButton(11) then
@@ -212,7 +213,7 @@ end
scene.widgetList={
WIDGET.newButton{name='offline',x=-1200,y=210,w=800,h=100,color='lR',font=45,align='R',edge=30,code=pressKey'1'},
WIDGET.newButton{name='qplay', x=-1200,y=330,w=800,h=100,color='lM',font=40,align='R',edge=30,code=pressKey'q'},
- WIDGET.newButton{name='online', x=-1200,y=450,w=800,h=100,color='D',font=45,align='R',edge=30,code=pressKey'a'},
+ WIDGET.newButton{name='online', x=-1200,y=450,w=800,h=100,color='lV',font=45,align='R',edge=30,code=pressKey'a'},
WIDGET.newButton{name='custom', x=-1200,y=570,w=800,h=100,color='lS',font=45,align='R',edge=30,code=pressKey'z'},
WIDGET.newButton{name='setting',x=2480,y=210,w=800,h=100, color='lO',font=40,align='L',edge=30,code=pressKey'-'},
@@ -221,7 +222,7 @@ scene.widgetList={
WIDGET.newButton{name='replays',x=2480,y=570,w=800,h=100, color='lC',font=40,align='L',edge=30,code=pressKey','},
WIDGET.newButton{name='music', x=90,y=80,w=100, color='lY',code=pressKey'2',font=70,fText=CHAR.icon.music},
- WIDGET.newButton{name='notice', x=210,y=80,w=100, color='D',code=pressKey'3',font=70,fText=CHAR.key.winMenu},
+ WIDGET.newButton{name='notice', x=210,y=80,w=100, color='lG',code=pressKey'3',font=70,fText=CHAR.key.winMenu},
WIDGET.newButton{name='lang', x=330,y=80,w=100, color='lN',code=pressKey'4',font=70,fText=CHAR.icon.language},
WIDGET.newButton{name='about', x=-110,y=670,w=600,h=70, color='lB',align='R',edge=20,code=pressKey'x',font=50,fText=CHAR.icon.info},
WIDGET.newButton{name='manual', x=1390,y=670,w=600,h=70, color='lR',align='L',edge=20,code=pressKey'm',font=50,fText=CHAR.icon.help},
diff --git a/parts/scenes/main_simple.lua b/parts/scenes/main_simple.lua
index 74aca2ea..7308fab3 100644
--- a/parts/scenes/main_simple.lua
+++ b/parts/scenes/main_simple.lua
@@ -5,6 +5,7 @@ local tip=GC.newText(getFont(30),"")
function scene.enter()
tip:set(text.getTip())
BG.set()
+ DiscordRPC.update("In Simple Menu")
end
function scene.draw()
diff --git a/parts/scenes/mode.lua b/parts/scenes/mode.lua
index df4c536a..6f20afef 100644
--- a/parts/scenes/mode.lua
+++ b/parts/scenes/mode.lua
@@ -44,6 +44,7 @@ function scene.enter()
end
end
modUsed=usingMod()
+ DiscordRPC.update("Picking mode")
end
local function _getK()
diff --git a/parts/scenes/music.lua b/parts/scenes/music.lua
index 355bdb3b..3c1345ed 100644
--- a/parts/scenes/music.lua
+++ b/parts/scenes/music.lua
@@ -26,6 +26,7 @@ if #bgmList==0 then bgmList={"[NO BGM]"} end
function scene.enter()
playing=BGM.getPlaying()[1]
selected=TABLE.find(bgmList,playing) or 1
+ DiscordRPC.update("Elevating the soul through music")
end
function scene.wheelMoved(_,y)
diff --git a/parts/scenes/net_league.lua b/parts/scenes/net_galaxim.lua
similarity index 84%
rename from parts/scenes/net_league.lua
rename to parts/scenes/net_galaxim.lua
index d9c6837a..3900b1ab 100644
--- a/parts/scenes/net_league.lua
+++ b/parts/scenes/net_galaxim.lua
@@ -3,14 +3,15 @@ local gc=love.graphics
local scene={}
function scene.enter()
- BG.set('league')
+ BG.set('galaxy')
BGM.play('exploration')
+ DiscordRPC.update("Dreaming Techmino Galaxy coming out")
end
function scene.draw()
gc.setColor(COLOR.Z)
setFont(100)
- GC.mStr("Tech League",640,120)
+ GC.mStr("Galaxim",640,120)
drawSelfProfile()
drawOnlinePlayerCount()
end
diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua
index c3b731f7..cc535345 100644
--- a/parts/scenes/net_game.lua
+++ b/parts/scenes/net_game.lua
@@ -27,7 +27,6 @@ local function _setCancel()
end
end
local function _setReady()
- NET.player_setPlayMode('Gamer')
NET.player_setReady(true)
end
local function _setSpectate()
@@ -47,6 +46,7 @@ local function _quit()
end
local function _switchChat()
if inputBox.hide then
+
textBox.hide=false
inputBox.hide=false
WIDGET.focus(inputBox)
@@ -72,6 +72,7 @@ function scene.enter()
BG.set(GAME.prevBG)
GAME.prevBG=false
end
+ DiscordRPC.update("Playing Multiplayer")
end
function scene.leave()
TASK.unlock('netPlaying')
@@ -311,16 +312,22 @@ end
function scene.draw()
if playing then
- -- Players
- for p=1,#PLAYERS do
- PLAYERS[p]:draw()
+ -- Warning
+ drawWarning()
+
+ -- Players
+ for p=1,#PLAYERS do
+ PLAYERS[p]:draw()
end
-- Virtual keys
VK.draw()
- -- Warning
- drawWarning()
+ -- Add dark overlay if chat is open
+ if not textBox.hide then
+ gc_setColor(0, 0, 0, 0.62-0.26)
+ love.graphics.rectangle('fill',0,0,1280,720)
+ end
if NET.spectate then
setFont(30)
@@ -328,8 +335,40 @@ function scene.draw()
gc_print(text.spectating,940,0)
end
else
- -- Users
- NETPLY.draw()
+ if textBox.hide then
+ -- Users
+ NETPLY.draw()
+
+ -- Room's capacity + private?
+ gc_setColor(1,1,1)
+ setFont(40)
+ gc_print(#NETPLY.list.."/"..NET.roomState.capacity,70,655)
+ if NET.roomState.private then
+ gc_draw(IMG.lock,30,668)
+ end
+ else
+ -- Room's capacity + private?
+ setFont(40)
+ gc_setColor(1,1,1)
+ gc_printf(#NETPLY.list.."/"..NET.roomState.capacity,1120,540,100,'right')
+ if NET.roomState.private then
+ gc_draw(IMG.lock,1070,553)
+ end
+ setFont(30)
+ -- Ready/Spectate indicator
+ if NETPLY.map[USER.uid].playMode=='Spectator' then
+ gc_printf(text.WidgetText.net_game.spectate,1020,600,240,'center')
+ elseif NETPLY.map[USER.uid].readyMode=='Ready' then
+ gc_printf(text.WidgetText.net_game.ready,1020,600,240,'center')
+ else
+ gc_printf('-----',1020,600,240,'center')
+ end
+ end
+
+ -- Room's name
+ gc_setColor(1,1,1)
+ setFont(25)
+ gc_printf(NET.roomState.info.name,0,685,1270,'right')
-- Ready & Set mark
setFont(50)
@@ -338,16 +377,6 @@ function scene.draw()
mStr(text.ready,640,15)
end
- -- Room info.
- gc_setColor(1,1,1)
- setFont(25)
- gc_printf(NET.roomState.info.name,0,685,1270,'right')
- setFont(40)
- gc_print(#NETPLY.list.."/"..NET.roomState.capacity,70,655)
- if NET.roomState.private then
- gc_draw(IMG.lock,30,668)
- end
-
-- Profile
drawSelfProfile()
@@ -360,11 +389,12 @@ function scene.draw()
if a then
setFont(40)
gc_setColor(.3,.7,1,a^2)
- gc_print("M",430,10)
+ gc_print(CHAR.icon.pencil,430,10)
end
end
-local function _hideF_ready() return playing or (NETPLY.map[USER.uid].playMode=='Spectator' or NETPLY.map[USER.uid].readyMode=='Ready') end
-local function _hideF_standby() return playing or not (NETPLY.map[USER.uid].playMode=='Spectator' or NETPLY.map[USER.uid].readyMode=='Ready') end
+local function _hideF_ready() return not (textBox.hide) or playing or (NETPLY.map[USER.uid].playMode=='Spectator' or NETPLY.map[USER.uid].readyMode=='Ready') end
+local function _hideF_standby() return not (textBox.hide) or playing or not (NETPLY.map[USER.uid].playMode=='Spectator' or NETPLY.map[USER.uid].readyMode=='Ready') end
+local function _hideF_hideChat() return textBox.hide end
scene.widgetList={
textBox,
inputBox,
@@ -381,6 +411,31 @@ scene.widgetList={
WIDGET.newButton{x=230,y=65,w=30,color='lM',fText="",code=function() NET.player_joinGroup(5) end,hideF=_hideF_ready},
WIDGET.newButton{x=270,y=65,w=30,color='lC',fText="",code=function() NET.player_joinGroup(6) end,hideF=_hideF_ready},
+ WIDGET.newKey{x=1045,y=135,w=50,font=40,fText=CHAR.zChan.normal ,code=function() inputBox:addText(CHAR.zChan.normal ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1110,y=135,w=50,font=40,fText=CHAR.zChan.full ,code=function() inputBox:addText(CHAR.zChan.full ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1175,y=135,w=50,font=40,fText=CHAR.zChan.happy ,code=function() inputBox:addText(CHAR.zChan.happy ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1240,y=135,w=50,font=40,fText=CHAR.zChan.confused ,code=function() inputBox:addText(CHAR.zChan.confused ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1045,y=200,w=50,font=40,fText=CHAR.zChan.grinning ,code=function() inputBox:addText(CHAR.zChan.grinning ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1110,y=200,w=50,font=40,fText=CHAR.zChan.frowning ,code=function() inputBox:addText(CHAR.zChan.frowning ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1175,y=200,w=50,font=40,fText=CHAR.zChan.tears ,code=function() inputBox:addText(CHAR.zChan.tears ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1240,y=200,w=50,font=40,fText=CHAR.zChan.anxious ,code=function() inputBox:addText(CHAR.zChan.anxious ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1045,y=265,w=50,font=40,fText=CHAR.zChan.rage ,code=function() inputBox:addText(CHAR.zChan.rage ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1110,y=265,w=50,font=40,fText=CHAR.zChan.fear ,code=function() inputBox:addText(CHAR.zChan.fear ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1175,y=265,w=50,font=40,fText=CHAR.zChan.question ,code=function() inputBox:addText(CHAR.zChan.question ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1240,y=265,w=50,font=40,fText=CHAR.zChan.angry ,code=function() inputBox:addText(CHAR.zChan.angry ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1045,y=330,w=50,font=40,fText=CHAR.zChan.shocked ,code=function() inputBox:addText(CHAR.zChan.shocked ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1110,y=330,w=50,font=40,fText=CHAR.zChan.ellipses ,code=function() inputBox:addText(CHAR.zChan.ellipses ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1175,y=330,w=50,font=40,fText=CHAR.zChan.sweatDrop ,code=function() inputBox:addText(CHAR.zChan.sweatDrop ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1240,y=330,w=50,font=40,fText=CHAR.zChan.cry ,code=function() inputBox:addText(CHAR.zChan.cry ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1045,y=395,w=50,font=40,fText=CHAR.zChan.cracked ,code=function() inputBox:addText(CHAR.zChan.cracked ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1110,y=395,w=50,font=40,fText=CHAR.zChan.qualified ,code=function() inputBox:addText(CHAR.zChan.qualified ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1175,y=395,w=50,font=40,fText=CHAR.zChan.unqualified,code=function() inputBox:addText(CHAR.zChan.unqualified) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1240,y=395,w=50,font=40,fText=CHAR.zChan.understand ,code=function() inputBox:addText(CHAR.zChan.understand ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1045,y=460,w=50,font=40,fText=CHAR.zChan.thinking ,code=function() inputBox:addText(CHAR.zChan.thinking ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1110,y=460,w=50,font=40,fText=CHAR.zChan.spark ,code=function() inputBox:addText(CHAR.zChan.spark ) end,hideF=_hideF_hideChat},
+-- WIDGET.newKey{x=1175,y=460,w=50,font=40,fText=CHAR.zChan. ,code=function() inputBox:addText( ) end,hideF=_hideF_hideChat},
+ WIDGET.newKey{x=1240,y=460,w=50,font=40,fText=CHAR.zChan.none ,code=function() inputBox:addText(CHAR.zChan.none ) end,hideF=_hideF_hideChat},
+
WIDGET.newKey{name='chat', x=390,y=45,w=60,fText="···", code=_switchChat},
WIDGET.newKey{name='quit', x=890,y=45,w=60,font=30,fText=CHAR.icon.cross_thick,code=_quit},
}
diff --git a/parts/scenes/net_menu.lua b/parts/scenes/net_menu.lua
index ce29d6c3..29c8406e 100644
--- a/parts/scenes/net_menu.lua
+++ b/parts/scenes/net_menu.lua
@@ -2,6 +2,7 @@ local scene={}
function scene.enter()
BG.set()
+ DiscordRPC.update("Ready to Click \"Rooms\"")
end
function scene.leave()
NET.ws_close()
@@ -14,11 +15,10 @@ function scene.draw()
end
scene.widgetList={
- WIDGET.newKey{name='setting', x=1200,y=160,w=90, h=90,code=goScene'setting_game',font=60,fText=CHAR.icon.settings},
- WIDGET.newButton{name='league',x=640, y=180,w=350,h=120,font=40,color='D',code=goScene'net_league'},
- WIDGET.newButton{name='ffa', x=640, y=360,w=350,h=120,font=40,color='D',code=function() MES.new('warn',text.notFinished)--[[NET.enterRoom({name='ffa'})]] end},
- WIDGET.newButton{name='rooms', x=640, y=540,w=350,h=120,font=40,code=goScene'net_rooms'},
- WIDGET.newButton{name='logout',x=880, y=40,w=180, h=60,color='dR',
+ WIDGET.newKey{name='setting', x=1200,y=160,w=90, h=90,code=goScene'setting_game',font=60,fText=CHAR.icon.settings},
+ WIDGET.newButton{name='galaxim',x=640, y=260,w=350,h=120,font=40,color='D',code=goScene'net_galaxim'},
+ WIDGET.newButton{name='rooms', x=640, y=460,w=350,h=120,font=40,code=goScene'net_rooms'},
+ WIDGET.newButton{name='logout', x=880, y=40,w=180, h=60,color='dR',
code=function()
if tryBack() then
print('logout')
diff --git a/parts/scenes/net_newRoom.lua b/parts/scenes/net_newRoom.lua
index 406a4168..4e462240 100644
--- a/parts/scenes/net_newRoom.lua
+++ b/parts/scenes/net_newRoom.lua
@@ -53,6 +53,7 @@ end
function scene.enter()
sure=0
destroyPlayers()
+ DiscordRPC.update("Creating new room...")
end
function scene.leave()
BGM.play()
@@ -85,8 +86,8 @@ scene.widgetList={
WIDGET.newSelector{name='lock', x=730,y=410,w=260,color='O',list=sList.lock,disp=ROOMval('lock'),code=ROOMsto('lock')},
WIDGET.newSelector{name='wait', x=730,y=520,w=260,color='G',list=sList.wait,disp=ROOMval('wait'),code=ROOMsto('wait')},
WIDGET.newSelector{name='fall', x=730,y=600,w=260,color='G',list=sList.fall,disp=ROOMval('fall'),code=ROOMsto('fall')},
- WIDGET.newSelector{name='hurry', x=730,y=680,w=260,color='G',list=sList.hurry,disp=ROOMval('hurry'),code=ROOMval('hurry')},
- WIDGET.newSelector{name='hang', x=730,y=760,w=260,color='G',list=sList.hang,disp=ROOMval('hang'),code=ROOMval('hang')},
+ WIDGET.newSelector{name='hurry', x=730,y=680,w=260,color='G',list=sList.hurry,disp=ROOMval('hurry'),code=ROOMsto('hurry')},
+ WIDGET.newSelector{name='hang', x=730,y=760,w=260,color='G',list=sList.hang,disp=ROOMval('hang'),code=ROOMsto('hang')},
-- Capacity & Create & Back
WIDGET.newSelector{name='capacity', x=1070,y=330,w=310,color='lY',list={2,3,4,5,7,10,17,31,49,99},disp=ROOMval('capacity'),code=ROOMsto('capacity')},
@@ -103,10 +104,10 @@ scene.widgetList={
WIDGET.newSwitch{name='bone', x=1170,y=970, lim=250,disp=ROOMval('bone'), code=ROOMrev('bone')},
-- Ruleset
- WIDGET.newSelector{name='eventSet', x=1050,y=760,w=340,color='H',list=sList.eventSet,disp=ROOMval('eventSet'),code=ROOMval('eventSet')},
+ WIDGET.newSelector{name='eventSet', x=1050,y=760,w=340,color='H',list=sList.eventSet,disp=ROOMval('eventSet'),code=ROOMsto('eventSet')},
-- Next & Hold
- WIDGET.newSelector{name='holdMode', x=310, y=890, w=300,color='lY',list=sList.holdMode,disp=ROOMval('holdMode'),code=ROOMval('holdMode'),hideF=function() return ROOMENV.holdCount==0 end},
+ WIDGET.newSelector{name='holdMode', x=310, y=890, w=300,color='lY',list=sList.holdMode,disp=ROOMval('holdMode'),code=ROOMsto('holdMode'),hideF=function() return ROOMENV.holdCount==0 end},
WIDGET.newSlider{name='nextCount', x=140, y=960, lim=130,w=200,axis={0,6,1},disp=ROOMval('nextCount'),code=ROOMsto('nextCount')},
WIDGET.newSlider{name='holdCount', x=140, y=1030,lim=130,w=200,axis={0,6,1},disp=ROOMval('holdCount'),code=ROOMsto('holdCount')},
WIDGET.newSwitch{name='infHold', x=560, y=960, lim=200, disp=ROOMval('infHold'),code=ROOMrev('infHold'),hideF=function() return ROOMENV.holdCount==0 end},
diff --git a/parts/scenes/net_rooms.lua b/parts/scenes/net_rooms.lua
index 25e0a153..f96fb01e 100644
--- a/parts/scenes/net_rooms.lua
+++ b/parts/scenes/net_rooms.lua
@@ -74,6 +74,7 @@ local scene={}
function scene.enter()
BG.set()
_fetchRoom()
+ DiscordRPC.update("Checking room list")
end
function scene.keyDown(key)
diff --git a/parts/scenes/notice.lua b/parts/scenes/notice.lua
index d7387308..3b869c55 100644
--- a/parts/scenes/notice.lua
+++ b/parts/scenes/notice.lua
@@ -2,11 +2,20 @@ local scene={}
function scene.enter()
BG.set('cubes')
- if type(SCN.args[1])=='string' then
- scene.widgetList.texts:setTexts(SCN.args[1])
+ local data=SCN.args[2]
+ if data then
+ local texts={"<"..SCN.args[1]..">"}
+ for i=1,#data do
+ table.insert(texts,("[$1] $2"):repD(data[i].id or "?",data[i].timestamp or "20??/??/??"))
+ table.insert(texts,data[i].content)
+ table.insert(texts,"")
+ table.insert(texts,"——————————————————————————")
+ end
+ scene.widgetList.texts:setTexts(texts)
else
scene.widgetList.texts:setTexts({"No data"})
end
+ DiscordRPC.update("Checking Latest News")
end
function scene.wheelMoved(_,y)
@@ -27,7 +36,7 @@ function scene.keyDown(key)
end
scene.widgetList={
- WIDGET.newTextBox{name='texts',x=30,y=45,w=1000,h=640,font=20,fix=true},
+ WIDGET.newTextBox{name='texts',x=30,y=45,w=1000,h=640,font=25,fix=true,lineH=45},
WIDGET.newButton{name='back',x=1140,y=640,w=170,h=80,sound='back',font=60,fText=CHAR.icon.back,code=backScene},
}
diff --git a/parts/scenes/replays.lua b/parts/scenes/replays.lua
index 0c77b66e..e119a0ce 100644
--- a/parts/scenes/replays.lua
+++ b/parts/scenes/replays.lua
@@ -78,6 +78,7 @@ function scene.enter()
BG.set()
listBox:setList(REPLAY)
_updateButtonVisibility()
+ DiscordRPC.update("Finding replay")
end
function scene.leave()
if #mods>0 then
@@ -97,7 +98,7 @@ function scene.keyDown(key)
if rep.available and rep.fileName then
local repStr=loadFile(rep.fileName,'-string')
if repStr then
- love.system.setClipboardText(love.data.encode('string','base64',repStr))
+ CLIPBOARD.set(love.data.encode('string','base64',repStr))
MES.new('info',text.exportSuccess)
else
MES.new('error',text.replayBroken)
@@ -107,7 +108,7 @@ function scene.keyDown(key)
end
end
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
- local repStr=love.system.getClipboardText()
+ local repStr=CLIPBOARD.get()
local res,fileData=pcall(love.data.decode,'string','base64',repStr)
if res then
local fileName=os.date("replay/%Y_%m_%d_%H%M%S_import.rep")
diff --git a/parts/scenes/reset_password.lua b/parts/scenes/reset_password.lua
index 7923b56a..e6228472 100644
--- a/parts/scenes/reset_password.lua
+++ b/parts/scenes/reset_password.lua
@@ -15,7 +15,7 @@ local function _setPW()
end
end
local function _paste()
- local t=love.system.getClipboardText()
+ local t=CLIPBOARD.get()
if t then
t=STRING.trim(t)
if #t==8 and t:match("[0-9]+") then
diff --git a/parts/scenes/savedata.lua b/parts/scenes/savedata.lua
index 2ae08365..aaa32069 100644
--- a/parts/scenes/savedata.lua
+++ b/parts/scenes/savedata.lua
@@ -7,12 +7,12 @@ function scene.enter()
end
local function _dumpCB(T)
- love.system.setClipboardText(STRING.packText(TABLE.dump(T)))
+ CLIPBOARD.set(STRING.packText(TABLE.dump(T)))
MES.new('check',text.exportSuccess)
end
local function _parseCB()
local _
- local s=love.system.getClipboardText()
+ local s=CLIPBOARD.get()
-- Decode
s=STRING.unpackText(s)
diff --git a/parts/scenes/setting_control.lua b/parts/scenes/setting_control.lua
index f8444dd5..52a18d67 100644
--- a/parts/scenes/setting_control.lua
+++ b/parts/scenes/setting_control.lua
@@ -9,6 +9,7 @@ function scene.enter()
das,arr=SETTING.das,SETTING.arr
pos,dir,wait=0,1,30
BG.set('bg1')
+ DiscordRPC.update("Tweaking control settings")
end
local trigFrame=0
@@ -89,21 +90,24 @@ scene.widgetList={
WIDGET.newText{name='title', x=100, y=50,lim=626,font=70,align='L'},
WIDGET.newText{name='preview', x=520, y=610,font=40,align='R'},
- WIDGET.newSlider{name='das', x=250, y=190,lim=230,w=600,axis={0,20,1},disp=SETval('das'), show=_sliderShow,code=SETsto('das')},
- WIDGET.newSlider{name='arr', x=250, y=260,lim=230,w=525,axis={0,15,1},disp=SETval('arr'), show=_sliderShow,code=SETsto('arr')},
- WIDGET.newSlider{name='sddas', x=250, y=330,lim=230,w=350,axis={0,10,1},disp=SETval('sddas'), show=_sliderShow,code=SETsto('sddas')},
- WIDGET.newSlider{name='sdarr', x=250, y=400,lim=230,w=140,axis={0,4,1}, disp=SETval('sdarr'), show=_sliderShow,code=SETsto('sdarr')},
- WIDGET.newSlider{name='dascut', x=250, y=470,lim=230,w=600,axis={0,20,1},disp=SETval('dascut'), show=_sliderShow,code=SETsto('dascut')},
+ WIDGET.newSlider{name='das', x=250, y=180,lim=230,w=600,axis={0,20,1},disp=SETval('das'), show=_sliderShow,code=SETsto('das')},
+ WIDGET.newSlider{name='arr', x=250, y=240,lim=230,w=525,axis={0,15,1},disp=SETval('arr'), show=_sliderShow,code=SETsto('arr')},
+ WIDGET.newSlider{name='sddas', x=250, y=300,lim=230,w=350,axis={0,10,1},disp=SETval('sddas'), show=_sliderShow,code=SETsto('sddas')},
+ WIDGET.newSlider{name='sdarr', x=250, y=360,lim=230,w=140,axis={0,4,1}, disp=SETval('sdarr'), show=_sliderShow,code=SETsto('sdarr')},
+ WIDGET.newSlider{name='dascut', x=250, y=420,lim=230,w=600,axis={0,20,1},disp=SETval('dascut'), show=_sliderShow,code=SETsto('dascut')},
+ WIDGET.newSlider{name='irscut', x=250, y=480,lim=230,w=600,axis={0,20,1},disp=SETval('irscut'), show=_sliderShow,code=SETsto('irscut')},
WIDGET.newSlider{name='dropcut',x=250, y=540,lim=230,w=300,axis={0,10,1},disp=SETval('dropcut'),show=_sliderShow,code=SETsto('dropcut')},
- WIDGET.newSwitch{name='ihs', x=1100, y=260,lim=300, disp=SETval('ihs'), code=SETrev('ihs')},
- WIDGET.newSwitch{name='irs', x=1100, y=330,lim=300, disp=SETval('irs'), code=SETrev('irs')},
- WIDGET.newSwitch{name='ims', x=1100, y=400,lim=300, disp=SETval('ims'), code=SETrev('ims')},
+
+ WIDGET.newSwitch{name='ihs', x=1100, y=240,lim=300, disp=SETval('ihs'), code=SETrev('ihs')},
+ WIDGET.newSwitch{name='irs', x=1100, y=300,lim=300, disp=SETval('irs'), code=SETrev('irs')},
+ WIDGET.newSwitch{name='ims', x=1100, y=360,lim=300, disp=SETval('ims'), code=SETrev('ims')},
+
WIDGET.newButton{name='reset', x=160, y=640,w=200,h=100,color='lR',font=40,
code=function()
local _=SETTING
_.das,_.arr,_.dascut=10,2,0
_.sddas,_.sdarr=0,2
- _.ihs,_.irs,_.ims=false,false,false
+ _.ihs,_.irs,_.ims,_.irscut=false,false,false,6
end},
WIDGET.newButton{name='back', x=1140, y=640,w=170,h=80,sound='back',font=60,fText=CHAR.icon.back,code=backScene},
}
diff --git a/parts/scenes/setting_game.lua b/parts/scenes/setting_game.lua
index 0a658782..e2024445 100644
--- a/parts/scenes/setting_game.lua
+++ b/parts/scenes/setting_game.lua
@@ -4,6 +4,7 @@ local scene={}
function scene.enter()
BG.set()
+ DiscordRPC.update("Tweaking Settings")
end
function scene.leave()
saveSettings()
diff --git a/parts/scenes/setting_key.lua b/parts/scenes/setting_key.lua
index 22e532b1..5618af6e 100644
--- a/parts/scenes/setting_key.lua
+++ b/parts/scenes/setting_key.lua
@@ -102,6 +102,7 @@ function scene.enter()
selected=false
_freshKeyList()
BG.set('none')
+ DiscordRPC.update("Binding keys")
end
function scene.leave()
saveFile(KEY_MAP,'conf/key')
diff --git a/parts/scenes/setting_sound.lua b/parts/scenes/setting_sound.lua
index 16d96199..a51ea253 100644
--- a/parts/scenes/setting_sound.lua
+++ b/parts/scenes/setting_sound.lua
@@ -15,6 +15,7 @@ function scene.enter()
scene.widgetList.sfxPack:reset()
scene.widgetList.vocPack:reset()
BG.set()
+ DiscordRPC.update("Tweaking Settings")
end
function scene.leave()
saveSettings()
diff --git a/parts/scenes/setting_video.lua b/parts/scenes/setting_video.lua
index e916a0fc..6c8ec220 100644
--- a/parts/scenes/setting_video.lua
+++ b/parts/scenes/setting_video.lua
@@ -2,6 +2,9 @@ local gc=love.graphics
local scene={}
+function scene.enter()
+ DiscordRPC.update("Tweaking Settings")
+end
function scene.leave()
saveSettings()
end
@@ -30,7 +33,7 @@ function scene.draw()
gc.push('transform')
gc.setColor(1,1,1)
local T=skinLib[1]
- gc.translate(-200,1410-WIDGET.scrollPos) -- -200
+ gc.translate(0,1610-WIDGET.scrollPos)
gc.setShader(SHADER.blockSatur)
gc.draw(T,435,0)gc.draw(T,465,0)gc.draw(T,465,30)gc.draw(T,495,30)
gc.setShader(SHADER.fieldSatur)
@@ -47,7 +50,7 @@ local function _msaaShow(S)
return S==0 and 0 or 2^S
end
-scene.widgetScrollHeight=900
+scene.widgetScrollHeight=1200
scene.widgetList={
WIDGET.newText{name='title', x=640,y=15,lim=630,font=80},
@@ -88,11 +91,18 @@ scene.widgetList={
WIDGET.newSwitch{name='clean', x=950,y=1100,lim=360,disp=SETval('cleanCanvas'), code=function() SETTING.cleanCanvas=not SETTING.cleanCanvas; applySettings() end},
WIDGET.newSwitch{name='fullscreen', x=950,y=1150,lim=360,disp=SETval('fullscreen'), code=function() SETTING.fullscreen=not SETTING.fullscreen; applySettings() end,hideF=function() return MOBILE end},
WIDGET.newSwitch{name='portrait', x=950,y=1150,lim=360,disp=SETval('portrait'), code=function() SETTING.portrait=not SETTING.portrait; saveSettings(); MES.new('warn',text.settingWarn2,6.26) end,hideF=function() return not MOBILE end},
- WIDGET.newSlider{name='msaa', x=950,y=1220,lim=360,w=200,axis={0,4,1},show=_msaaShow,disp=function() return SETTING.msaa==0 and 0 or math.log(SETTING.msaa,2) end,code=function(v) SETTING.msaa=v==0 and 0 or 2^v; saveSettings(); if TASK.lock('warnMessage',6.26) then MES.new('warn',text.settingWarn2,6.26) end end},
+ WIDGET.newSlider{name='msaa', x=950,y=1220,lim=360,w=200,axis={0,4,1},disp=SETval('msaa'),show=_msaaShow,
+ code=function(v)
+ SETTING.msaa=v
+ if TASK.lock('warnMessage',6.26) then
+ MES.new('warn',text.settingWarn2,6.26)
+ end
+ end
+ },
- WIDGET.newKey{name='bg_on', x=680,y=1290,w=200,h=60,code=function() SETTING.bg='on' ; applySettings() end},
- WIDGET.newKey{name='bg_off', x=900,y=1290,w=200,h=60,code=function() SETTING.bg='off'; applySettings() end},
- WIDGET.newKey{name='bg_custom', x=1120,y=1290,w=200,h=60,
+ WIDGET.newKey{name='bg_on', x=680,y=1290,w=200,h=60,font=25,code=function() SETTING.bg='on' ; applySettings() end},
+ WIDGET.newKey{name='bg_off', x=900,y=1290,w=200,h=60,font=25,code=function() SETTING.bg='off'; applySettings() end},
+ WIDGET.newKey{name='bg_custom', x=1120,y=1290,w=200,h=60,font=25,
code=function()
if love.filesystem.getInfo('conf/customBG') then
SETTING.bg='custom'
@@ -114,7 +124,7 @@ scene.widgetList={
end,
hideF=function() return SETTING.bg=='on' end
},
- WIDGET.newSelector{name='defaultBG', x=680,y=1365,w=200,color='G',
+ WIDGET.newSelector{name='defaultBG', x=680,y=1465,w=200,color='G',
list={'space','bg1','bg2','rainbow','rainbow2','aura','rgb','glow','matrix','cubes','tunnel','galaxy','quarks','blockfall','blockrain','blockhole','blockspace'},
disp=SETval('defaultBG'),
code=function(v)
@@ -123,7 +133,7 @@ scene.widgetList={
end,
hideF=function() return SETTING.bg~='on' end
},
- WIDGET.newKey{name='resetDbg',x=870,y=1365,w=140,h=60,font=15,
+ WIDGET.newKey{name='resetDbg',x=680,y=1540,w=200,h=60,font=20,
code=function()
SETTING.defaultBG='space'
scene.widgetList.defaultBG:reset()
@@ -131,7 +141,20 @@ scene.widgetList={
end,
hideF=function() return SETTING.bg~='on' or SETTING.defaultBG=='space' end
},
- WIDGET.newSwitch{name='lockBG',x=1170,y=1365,lim=200,
+ WIDGET.newKey{name='bg_custom_base64',x=1010,y=1502.5,w=420,h=135,align='M',
+ code=function()
+ local okay,data=pcall(love.data.decode,"data","base64",CLIPBOARD.get())
+ if okay and pcall(gc.newImage,data) then
+ love.filesystem.write('conf/customBG',data)
+ SETTING.bg='custom'
+ applySettings()
+ else
+ MES.new('error',text.customBGloadFailed)
+ end
+ end,
+ -- hideF=function() return SETTING.bg=='off' end
+ },
+ WIDGET.newSwitch{name='lockBG',x=450,y=1465,lim=200,
disp=SETval('lockBG'),
code=function()
SETTING.lockBG=not SETTING.lockBG
@@ -140,7 +163,7 @@ scene.widgetList={
hideF=function() return SETTING.bg~='on' end
},
- WIDGET.newSwitch{name='noTheme',x=1170,y=1435,
+ WIDGET.newSwitch{name='noTheme',x=450,y=1540,
disp=SETval('noTheme'),
code=function()
SETTING.noTheme=not SETTING.noTheme
@@ -156,12 +179,12 @@ scene.widgetList={
end
},
- WIDGET.newSelector{name='blockSatur', x=600,y=1440,w=300,color='lN',
+ WIDGET.newSelector{name='blockSatur', x=800,y=1640,w=300,color='lN',
list={'normal','soft','gray','light','color'},
disp=SETval('blockSatur'),
code=function(v) SETTING.blockSatur=v; applySettings() end
},
- WIDGET.newSelector{name='fieldSatur', x=600,y=1540,w=300,color='lN',
+ WIDGET.newSelector{name='fieldSatur', x=800,y=1740,w=300,color='lN',
list={'normal','soft','gray','light','color'},
disp=SETval('fieldSatur'),
code=function(v) SETTING.fieldSatur=v; applySettings() end
diff --git a/parts/scenes/staff.lua b/parts/scenes/staff.lua
index 9b7a51e5..b34a68f9 100644
--- a/parts/scenes/staff.lua
+++ b/parts/scenes/staff.lua
@@ -17,6 +17,7 @@ function scene.enter()
BG.set()
names={}
counter=26
+ DiscordRPC.update("Knowing Staffs")
end
function scene.mouseDown(x,y)
diff --git a/parts/scenes/stat.lua b/parts/scenes/stat.lua
index afab7dde..59ba04ab 100644
--- a/parts/scenes/stat.lua
+++ b/parts/scenes/stat.lua
@@ -37,6 +37,7 @@ function scene.enter()
for i=1,11 do
item[i]=text.stat[i].."\t"..item[i]
end
+ DiscordRPC.update("Admiring Oneself")
end
function scene.mouseDown(x,y)
diff --git a/parts/scenes/support.lua b/parts/scenes/support.lua
index 654060b2..a46f5061 100644
--- a/parts/scenes/support.lua
+++ b/parts/scenes/support.lua
@@ -1,5 +1,9 @@
local scene={}
+function scene.enter()
+ DiscordRPC.update("Sponsoring a Great Cause")
+end
+
function scene.draw()
-- QR Code frame
GC.setLineWidth(2)
diff --git a/parts/scenes/viewlog.lua b/parts/scenes/viewlog.lua
index 2c41e610..31b6de1c 100644
--- a/parts/scenes/viewlog.lua
+++ b/parts/scenes/viewlog.lua
@@ -164,7 +164,7 @@ scene.widgetList={
textBox,
WIDGET.newButton {name='home',x=1140,y= 90,w=170,h=80,sound='click',font=60,fText=CHAR.key.macHome,code=pressKey('home')},
WIDGET.newButton {name='endd',x=1140,y=190,w=170,h=80,sound='click',font=60,fText=CHAR.key.macEnd ,code=pressKey('end')},
- WIDGET.newButton {name='copy',x=1140,y=290,w=170,h=80,sound='click',font=60,fText=CHAR.icon.copy ,code=function()love.system.setClipboardText(table.concat(textBox.texts,'\n'))end,color='lC'},
+ WIDGET.newButton {name='copy',x=1140,y=290,w=170,h=80,sound='click',font=60,fText=CHAR.icon.copy ,code=function()CLIPBOARD.set(table.concat(textBox.texts,'\n'))end,color='lC'},
logList,
diff --git a/parts/theme.lua b/parts/theme.lua
index 6cd65ca2..d129de6b 100644
--- a/parts/theme.lua
+++ b/parts/theme.lua
@@ -12,13 +12,13 @@ function THEME.calculate(Y,M,D)
Y,M,D=os.date('%Y'),os.date('%m'),os.date('%d')
end
-- Festival calculate within one statement
- return
+ if not SETTING.noTheme then return
-- Christmas
M=='12' and math.abs(D-25)<4 and
'xmas' or
-- Halloween
- (M=='10' and D>='28' or M=='11' and D<='04') and
+ (M=='10' and D>='28' or M=='11' and D>='01' and D<='04') and
'halloween' or
-- Birthday
@@ -42,59 +42,63 @@ function THEME.calculate(Y,M,D)
M=='04' and D=='01' and
'fool' or
+ -- April fool's day
+ M=='07' and (D=='14' or D=='15') and
+ 'edm' or
+
-- Z day
D=='26' and (
(M=='03' or M=='04' or M=='05' or M=='06') and 'zday1' or
(M=='07' or M=='08' or M=='09' or M=='10') and 'zday2' or
(M=='11' or M=='12' or M=='01' or M=='02') and 'zday3'
- ) or
-
- -- Normal
- (
- (M=='02' or M=='03' or M=='04') and 'season1' or
- (M=='05' or M=='06' or M=='07') and 'season2' or
- (M=='08' or M=='09' or M=='10') and 'season3' or
- (M=='11' or M=='12' or M=='01') and 'season4'
)
+ end
+
+ -- If there is theme and theme is enabled, then we will never reach here
+ return -- Normal
+ (
+ (M=='02' or M=='03' or M=='04') and 'season1' or
+ (M=='05' or M=='06' or M=='07') and 'season2' or
+ (M=='08' or M=='09' or M=='10') and 'season3' or
+ (M=='11' or M=='12' or M=='01') and 'season4'
+ )
end
+---@param theme string
+---@param keepBGM boolean|false|nil
function THEME.set(theme,keepBGM)
- if type(theme)=='string' and theme:sub(1,6)=='season' then
+ if type(theme)~='string' then
+ return
+ elseif theme:sub(1,6)=='season' then
BG.setDefault(SETTING.defaultBG)
- BGM.setDefault(({season1='null',season2='nil',season3='vaccum',season4='space'})[theme])
- elseif not SETTING.noTheme then
- if theme=='xmas' then
- BG.setDefault('snow')
- BGM.setDefault('xmas')
- MES.new('info',"==Merry Christmas==")
- elseif theme=='birth' then
- BG.setDefault('firework')
- BGM.setDefault('magicblock')
- elseif theme=='sprfes' then
- BG.setDefault('firework')
- BGM.setDefault('spring festival')
- MES.new('info',"★☆新年快乐☆★")
- elseif theme=='halloween' then
- BG.setDefault('glow')
- BGM.setDefault('antispace')
- MES.new('info',">>Happy halloween<<")
- elseif theme=='zday1' then
- BG.setDefault('lanterns')
- BGM.setDefault('overzero')
- elseif theme=='zday2' then
- BG.setDefault('lanterns')
- BGM.setDefault('jazz nihilism')
- elseif theme=='zday3' then
- BG.setDefault('lanterns')
- BGM.setDefault('empty')
- elseif theme=='fool' then
- BG.setDefault('blockrain')
- BGM.setDefault('how feeling')
- else
- return
- end
+ BGM.setDefault(({season1='null',season2='nil',season3='vacuum',season4='space'})[theme])
+ elseif theme=='xmas' then
+ BG.setDefault('snow')
+ BGM.setDefault('xmas')
+ MES.new('info',"==Merry Christmas==")
+ elseif theme=='birth' then
+ BG.setDefault('firework')
+ BGM.setDefault('magicblock')
+ elseif theme=='sprfes' then
+ BG.setDefault('firework')
+ BGM.setDefault('spring festival')
+ MES.new('info',"★☆新年快乐☆★")
+ elseif theme=='halloween' then
+ BG.setDefault('glow')
+ BGM.setDefault('antispace')
+ MES.new('info',">>Happy halloween<<")
+ elseif theme:sub(1,4)=='zday' then
+ BG.setDefault('lanterns')
+ BGM.setDefault(({zday1='overzero',zday2='jazz nihilism',zday3='empty'})[theme])
+ elseif theme=='fool' then
+ BG.setDefault('blockrain')
+ BGM.setDefault('how feeling')
+ elseif theme=='edm' then
+ BG.setDefault('lightning2')
+ BGM.setDefault('malate')
+ MES.new('music'," 红 色 电 音\n 极 地 大 冲 击\n 只要你敢触电——\n 7月14日、15日 天地人间完全放电\n不用麻醉,一样情不自禁HI起来,飞起来")
else
- return THEME.set(THEME.calculate('0',os.date('%m'),'0'))
+ return
end
THEME.cur=theme
diff --git a/readme.md b/readme.md
index 2642de2d..ec2068c8 100644
--- a/readme.md
+++ b/readme.md
@@ -24,6 +24,20 @@ A collection of various modern block game rules, more ways to play, and some new
-----
-[官网(建设中) Official website (WIP)](http://101.43.110.22:10026)
+[官网(重构中) Official Website (RWIP)](https://www.studio26f.org/home)
-[维基(建设中) Github wiki](https://github.com/26F-Studio/Techmino/wiki)
+[社区引导站(建设中)(非官方) Techmino Hub (WIP)(unofficial)](https://techmino-hub.vercel.app/)
+
+[Github维基(暂停建设) Github Wiki (WNIP)](https://github.com/26F-Studio/Techmino/wiki)
+
+## Paypal Donation (Paypal赞助)
+
+开了一个支付方式试一下,记得自己留一下付款记录,未来可能会返一些东西(不保证)
+
+Made a payment method to try it out, remember to keep a payment record, there may be some benifits in the future (not guaranteed)
+
+[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CNJ9G8242SP8E)
+
+## 500 Stars Poster
+
+
diff --git a/updateLog.txt b/updateLog.txt
index 2886f8d0..55f5c848 100644
--- a/updateLog.txt
+++ b/updateLog.txt
@@ -1,16 +1,50 @@
未来计划:
正在点亮科技树...
+0.17.22: 暂停? Break?
+ 新增:
+ 新的IRS系统和一个IRS参数设置(By Electra)
+ 新的事件系统,允许自由定义事件和参数数量,让更多的模式创意成为可能 (By Electra & MrZ)
+ DiscordRPC支持
+ 主菜单添加公告页面
+ 尝试重启联网
+ 改动:
+ 删除三个凑数的策略堆叠模式
+ 3D方块效果微调
+ 调整所有方块皮肤的名称
+ 一些内部系统重构,尝试支持Web端
+ 修复:
+ 晃动特效开大了20g下颠到吐
+ hisPool序列算法错误(会影响部分模式录像)
+ 开了“关闭节日主题”时可能导致启动就卡死
+
+
+0.17.19: 暂停 Break
+ 新增:
+ 新模式:Spin连击 (by Gompyn) #1129
+ 改动:
+ 调整一些模式的外框形状
+ 修复:
+ 大师-段位考试模式崩溃
+ 第三季度主菜单音乐名称打错导致没有bgm和进音乐室报错
+ c4w普通的计分完全改为竞速 #1126
+
0.17.17: 暂停 Break
新增:
新语音包: neuro (by Petalzu) #1109
改动:
c4w普通的模式说明改为和100l相同 #1082
更强大的ARS_Z #1094
+ 更新一些英文文本 (by KonSola5)
+ 字体微调 (by C₂₉H₂₅N₃O₅) #1116
+ 优化neuro立绘动画和纠正俊达萌的身高
+ 消四挖掘模式中非挖掘消四会降低评分
修复:
大师-段位考试模式崩溃
大师-段位考试计分算法细节修复 #1092 #1113
拼花模式段位计分有1行偏差 #1099
+ 两个消四模式的段位计算错误 #1120
+ 锁定背景时初始化有问题 #1122
0.17.16: 暂停 Break
新增:
diff --git a/version.lua b/version.lua
index c6bec5d7..5dca7c19 100644
--- a/version.lua
+++ b/version.lua
@@ -1,7 +1,7 @@
return {
- ["apkCode"]=1717,
- ["code"]=1717,
- ["string"]="V0.17.17",
- ["room"]="ver A-12",
+ ["apkCode"]=1722,
+ ["code"]=1722,
+ ["string"]="V0.17.22",
+ ["room"]="ver A-14",
["name"]="暂停 Break",
}